summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-09-23 16:06:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-09-24 11:41:55 +0000
commitbac1035f131c0b95b75fb39ffd1a39652843de9f (patch)
tree44839fddbea648d54e4be47bcfbe4a5979bacd29
parent271a6c3487a14599023a9106329505597638d793 (diff)
BASELINE: Update Chromium to 77.0.3865.98
Change-Id: Ice85979eb8b64af9a3c649d719bec6ea14ac3bf7 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
-rw-r--r--chromium/AUTHORS2
-rw-r--r--chromium/DEPS6
-rw-r--r--chromium/build/toolchain/win/setup_toolchain.py6
-rw-r--r--chromium/build/util/LASTCHANGE2
-rw-r--r--chromium/build/util/LASTCHANGE.committime2
-rw-r--r--chromium/chrome/VERSION2
-rw-r--r--chromium/chrome/android/features/tab_ui/tab_management_java_sources.gni1
-rw-r--r--chromium/chrome/app/resources/chromium_strings_sl.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_es.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_kn.xtb2
-rw-r--r--chromium/chrome/app/resources/generated_resources_sl.xtb4
-rw-r--r--chromium/chrome/app/resources/generated_resources_tr.xtb2
-rw-r--r--chromium/chrome/app/resources/google_chrome_strings_sl.xtb2
-rw-r--r--chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc21
-rw-r--r--chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h5
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json6
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json6
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_win.json6
-rw-r--r--chromium/chrome/common/webui_url_constants.cc5
-rw-r--r--chromium/chrome/common/webui_url_constants.h5
-rw-r--r--chromium/chrome/credential_provider/gaiacp/gaia_resources.grd3
-rw-r--r--chromium/chrome/test/BUILD.gn1
-rw-r--r--chromium/components/arc/ime/DEPS1
-rw-r--r--chromium/components/arc/ime/arc_ime_service.cc8
-rw-r--r--chromium/components/arc/ime/arc_ime_service.h2
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/actions/get_payment_information_action.cc8
-rw-r--r--chromium/components/dom_distiller/DEPS1
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc44
-rw-r--r--chromium/components/dom_distiller/core/url_utils.cc41
-rw-r--r--chromium/components/dom_distiller/core/url_utils.h4
-rw-r--r--chromium/components/dom_distiller/core/url_utils_unittest.cc58
-rw-r--r--chromium/components/dom_distiller/core/viewer.cc12
-rw-r--r--chromium/components/dom_distiller/core/viewer.h3
-rw-r--r--chromium/components/dom_distiller/core/viewer_unittest.cc47
-rw-r--r--chromium/components/download/internal/common/download_create_info.cc3
-rw-r--r--chromium/components/download/internal/common/resource_downloader.cc5
-rw-r--r--chromium/components/download/internal/common/resource_downloader.h3
-rw-r--r--chromium/components/download/public/common/download_create_info.h3
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.cc18
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.h3
-rw-r--r--chromium/components/exo/client_controlled_shell_surface_unittest.cc17
-rw-r--r--chromium/components/previews/core/previews_experiments.cc9
-rw-r--r--chromium/components/previews/core/previews_experiments.h4
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.cc2
-rw-r--r--chromium/components/printing/resources/print_header_footer_template_page.html28
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.cc7
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.h14
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc8
-rw-r--r--chromium/components/strings/components_strings_id.xtb2
-rw-r--r--chromium/components/strings/components_strings_no.xtb2
-rw-r--r--chromium/components/strings/components_strings_tr.xtb2
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.cc4
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.h4
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator_unittest.cc18
-rw-r--r--chromium/components/viz/common/features.cc2
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.h6
-rw-r--r--chromium/content/browser/BUILD.gn2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.h2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.mm38
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.cc6
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc15
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h7
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.cc27
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.h4
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_unittest.cc90
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc4
-rw-r--r--chromium/content/browser/builtin_service_manifests.cc7
-rw-r--r--chromium/content/browser/download/download_browsertest.cc78
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc1
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl.cc8
-rw-r--r--chromium/content/browser/frame_host/navigation_request.cc16
-rw-r--r--chromium/content/browser/frame_host/navigation_request.h4
-rw-r--r--chromium/content/browser/network_service_instance_impl.cc29
-rw-r--r--chromium/content/browser/network_service_instance_impl.h2
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.cc1
-rw-r--r--chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.cc10
-rw-r--r--chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.h4
-rw-r--r--chromium/content/browser/renderer_host/media/service_launched_video_capture_device.h4
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.h4
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc1
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider.cc150
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider.h52
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc118
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.cc27
-rw-r--r--chromium/content/browser/service_manager/service_manager_context.cc23
-rw-r--r--chromium/content/browser/service_process_host_impl.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.cc9
-rw-r--r--chromium/content/browser/utility_process_host.cc8
-rw-r--r--chromium/content/browser/utility_process_host.h6
-rw-r--r--chromium/content/browser/video_capture_service.cc150
-rw-r--r--chromium/content/browser/webrtc/webrtc_video_capture_browsertest.cc8
-rw-r--r--chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc32
-rw-r--r--chromium/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc18
-rw-r--r--chromium/content/browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc19
-rw-r--r--chromium/content/public/browser/BUILD.gn2
-rw-r--r--chromium/content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h2
-rw-r--r--chromium/content/public/browser/service_process_host.cc15
-rw-r--r--chromium/content/public/browser/service_process_host.h6
-rw-r--r--chromium/content/public/browser/video_capture_service.h31
-rw-r--r--chromium/content/renderer/loader/resource_dispatcher.cc3
-rw-r--r--chromium/content/utility/services.cc11
-rw-r--r--chromium/content/utility/utility_service_factory.cc5
-rw-r--r--chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h16
-rw-r--r--chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc22
-rw-r--r--chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc5
-rw-r--r--chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc7
-rw-r--r--chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h14
-rw-r--r--chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc10
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list.json13
-rw-r--r--chromium/gpu/config/gpu_lists_version.h2
-rw-r--r--chromium/infra/config/cr-buildbucket.cfg113
-rw-r--r--chromium/ios/chrome/browser/ui/dialogs/BUILD.gn2
-rw-r--r--chromium/ios/chrome/test/earl_grey/BUILD.gn2
-rw-r--r--chromium/media/blink/webmediaplayer_impl.cc6
-rw-r--r--chromium/media/gpu/vaapi/vp8_encoder.cc6
-rw-r--r--chromium/media/mojo/services/mojo_cdm_service.cc5
-rw-r--r--chromium/media/mojo/services/mojo_cdm_service.h2
-rw-r--r--chromium/services/content/public/cpp/navigable_contents_view.cc61
-rw-r--r--chromium/services/network/mdns_responder.cc12
-rw-r--r--chromium/services/network/mdns_responder_unittest.cc5
-rw-r--r--chromium/services/network/public/cpp/features.cc7
-rw-r--r--chromium/services/network/public/cpp/features.h2
-rw-r--r--chromium/services/video_capture/BUILD.gn37
-rw-r--r--chromium/services/video_capture/device_factory.h3
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc14
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.h4
-rw-r--r--chromium/services/video_capture/device_factory_provider_impl.cc (renamed from chromium/services/video_capture/video_capture_service_impl.cc)103
-rw-r--r--chromium/services/video_capture/device_factory_provider_impl.h (renamed from chromium/services/video_capture/video_capture_service_impl.h)44
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.cc10
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.h4
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc2
-rw-r--r--chromium/services/video_capture/public/cpp/BUILD.gn21
-rw-r--r--chromium/services/video_capture/public/cpp/manifest.cc43
-rw-r--r--chromium/services/video_capture/public/cpp/manifest.h17
-rw-r--r--chromium/services/video_capture/public/cpp/mock_device_factory_provider.cc (renamed from chromium/services/video_capture/public/cpp/mock_video_capture_service.cc)12
-rw-r--r--chromium/services/video_capture/public/cpp/mock_device_factory_provider.h (renamed from chromium/services/video_capture/public/cpp/mock_video_capture_service.h)23
-rw-r--r--chromium/services/video_capture/public/mojom/BUILD.gn7
-rw-r--r--chromium/services/video_capture/public/mojom/constants.mojom1
-rw-r--r--chromium/services/video_capture/public/mojom/device_factory_provider.mojom (renamed from chromium/services/video_capture/public/mojom/video_capture_service.mojom)18
-rw-r--r--chromium/services/video_capture/service_impl.cc192
-rw-r--r--chromium/services/video_capture/service_impl.h107
-rw-r--r--chromium/services/video_capture/service_main.cc14
-rw-r--r--chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc4
-rw-r--r--chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h3
-rw-r--r--chromium/services/video_capture/testing_controls_impl.cc6
-rw-r--r--chromium/services/video_capture/testing_controls_impl.h6
-rw-r--r--chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc4
-rw-r--r--chromium/services/video_capture/texture_virtual_device_mojo_adapter.h5
-rw-r--r--chromium/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc7
-rw-r--r--chromium/services/video_capture/video_source_provider_impl.h1
-rw-r--r--chromium/services/video_capture/virtual_device_enabled_device_factory.cc14
-rw-r--r--chromium/services/video_capture/virtual_device_enabled_device_factory.h4
-rw-r--r--chromium/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h9
-rw-r--r--chromium/services/viz/public/interfaces/compositing/shared_quad_state.mojom3
-rw-r--r--chromium/skia/ext/skia_commit_hash.h2
-rw-r--r--chromium/third_party/blink/common/features.cc14
-rw-r--r--chromium/third_party/blink/renderer/controller/blink_initializer.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_clock.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/animation/animation_clock.h48
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/animation/compositor_animations_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/animation/document_timeline_test.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.h4
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/frame/frame_overlay.h7
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/loader/image_loader.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/loader/resource/image_resource_content.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/DEPS4
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_animator.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_animator.h2
-rw-r--r--chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client.h1
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_client_impl.h19
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h10
-rw-r--r--chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc139
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/audits/auditsPanel.css2
-rw-r--r--chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css4
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc36
-rw-r--r--chromium/third_party/blink/renderer/modules/accessibility/ax_node_object.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc6
-rw-r--r--chromium/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.h2
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/color_behavior.h12
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional.h59
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional_test.cc46
-rw-r--r--chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h14
-rw-r--r--chromium/third_party/skia/src/pdf/SkPDFFont.cpp10
-rw-r--r--chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp351
-rw-r--r--chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h2
-rw-r--r--chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp4
-rwxr-xr-xchromium/tools/mb/mb.py23
-rw-r--r--chromium/tools/metrics/actions/actions.xml110
-rw-r--r--chromium/tools/metrics/histograms/enums.xml34
-rw-r--r--chromium/tools/metrics/histograms/histograms.xml82
-rw-r--r--chromium/ui/accessibility/ax_event_generator.cc12
-rw-r--r--chromium/ui/accessibility/ax_event_generator.h6
-rw-r--r--chromium/ui/accessibility/ax_node.cc20
-rw-r--r--chromium/ui/accessibility/ax_node_position.cc24
-rw-r--r--chromium/ui/accessibility/ax_node_position.h1
-rw-r--r--chromium/ui/accessibility/ax_node_position_unittest.cc151
-rw-r--r--chromium/ui/accessibility/ax_position.h48
-rw-r--r--chromium/ui/accessibility/ax_table_info_unittest.cc2
-rw-r--r--chromium/ui/accessibility/ax_tree.cc1146
-rw-r--r--chromium/ui/accessibility/ax_tree.h72
-rw-r--r--chromium/ui/accessibility/ax_tree_observer.h60
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc699
-rw-r--r--chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc20
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc10
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc22
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc51
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_unittest.cc32
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc36
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.h3
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc357
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb2
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js44
-rw-r--r--chromium/v8/include/v8-version.h2
-rw-r--r--chromium/v8/src/builtins/base.tq6
-rw-r--r--chromium/v8/src/codegen/code-stub-assembler.cc5
-rw-r--r--chromium/v8/src/codegen/code-stub-assembler.h1
-rw-r--r--chromium/v8/src/compiler/js-native-context-specialization.cc5
-rw-r--r--chromium/v8/src/inspector/custom-preview.cc2
-rw-r--r--chromium/v8/src/inspector/custom-preview.h6
-rw-r--r--chromium/v8/src/inspector/injected-script.cc2
-rw-r--r--chromium/v8/src/regexp/regexp-compiler.cc73
245 files changed, 4876 insertions, 2155 deletions
diff --git a/chromium/AUTHORS b/chromium/AUTHORS
index d65fb3966b8..ba8282073f6 100644
--- a/chromium/AUTHORS
+++ b/chromium/AUTHORS
@@ -74,6 +74,7 @@ Andrei Parvu <andrei.prv@gmail.com>
Andrei Parvu <parvu@adobe.com>
Andrew Boyarshin <andrew.boyarshin@gmail.com>
Andrew Brampton <me@bramp.net>
+Andrew Brindamour <abrindamour@bluejeans.com>
Andrew Hung <andrhung@amazon.com>
Andrew Jorgensen <ajorgens@amazon.com>
Andrew MacPherson <andrew.macpherson@soundtrap.com>
@@ -421,6 +422,7 @@ Jianjun Zhu <jianjun.zhu@intel.com>
Jianneng Zhong <muzuiget@gmail.com>
Jiawei Shao <jiawei.shao@intel.com>
Jie Chen <jie.a.chen@intel.com>
+Jihan Chao <jihan@bluejeans.com>
Jihoon Chung <j.c@navercorp.com>
Jihoon Chung <jihoon@gmail.com>
Jihun Brent Kim <devgrapher@gmail.com>
diff --git a/chromium/DEPS b/chromium/DEPS
index 24627c6c404..d6d3cb1f992 100644
--- a/chromium/DEPS
+++ b/chromium/DEPS
@@ -146,11 +146,11 @@ vars = {
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Skia
# and whatever else without interference from each other.
- 'skia_revision': '2417cee95d9097a19d759a2267d4c3e51786e873',
+ 'skia_revision': 'a10014304cba4f24b7af17191f59490faa8aee77',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling V8
# and whatever else without interference from each other.
- 'v8_revision': '1e6ebba9def991e536159fa658bf5564c054733f',
+ 'v8_revision': '027689dbfcb2a9bbc8ceec4db2631c558e879633',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling swarming_client
# and whatever else without interference from each other.
@@ -1417,7 +1417,7 @@ deps = {
Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'),
'src-internal': {
- 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f40660faddf716870875beaac3f96911a9c4a554',
+ 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@18095bdf3eb60c3e121aac53a2c92eba6c37c3a9',
'condition': 'checkout_src_internal',
},
diff --git a/chromium/build/toolchain/win/setup_toolchain.py b/chromium/build/toolchain/win/setup_toolchain.py
index ef8aeda5645..9ee69df7d21 100644
--- a/chromium/build/toolchain/win/setup_toolchain.py
+++ b/chromium/build/toolchain/win/setup_toolchain.py
@@ -28,15 +28,21 @@ def _ExtractImportantEnvironment(output_of_set):
"""Extracts environment variables required for the toolchain to run from
a textual dump output by the cmd.exe 'set' command."""
envvars_to_save = (
+ 'cipd_cache_dir', # needed by vpython
+ 'homedrive', # needed by vpython
+ 'homepath', # needed by vpython
'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
'include',
'lib',
'libpath',
+ 'luci_context', # needed by vpython
'path',
'pathext',
'systemroot',
'temp',
'tmp',
+ 'userprofile', # needed by vpython
+ 'vpython_virtualenv_root' # needed by vpython
)
env = {}
# This occasionally happens and leads to misleading SYSTEMROOT error messages
diff --git a/chromium/build/util/LASTCHANGE b/chromium/build/util/LASTCHANGE
index a95aad93539..033ddb4ac97 100644
--- a/chromium/build/util/LASTCHANGE
+++ b/chromium/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=f7668708a327d2ab897cd802bbbc8a8b67283ec8-refs/branch-heads/3865@{#680}
+LASTCHANGE=89700f0d311d189a766a3532c1e6de2c94d429f9-refs/branch-heads/3865@{#842}
diff --git a/chromium/build/util/LASTCHANGE.committime b/chromium/build/util/LASTCHANGE.committime
index fc9ffb58c2e..27cab847d5e 100644
--- a/chromium/build/util/LASTCHANGE.committime
+++ b/chromium/build/util/LASTCHANGE.committime
@@ -1 +1 @@
-1567125764 \ No newline at end of file
+1569197526 \ No newline at end of file
diff --git a/chromium/chrome/VERSION b/chromium/chrome/VERSION
index 5e9ec237228..2ba5d0d4c2a 100644
--- a/chromium/chrome/VERSION
+++ b/chromium/chrome/VERSION
@@ -1,4 +1,4 @@
MAJOR=77
MINOR=0
BUILD=3865
-PATCH=59
+PATCH=98
diff --git a/chromium/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chromium/chrome/android/features/tab_ui/tab_management_java_sources.gni
index d287f692074..e524786980c 100644
--- a/chromium/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chromium/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -7,6 +7,7 @@ import(
public_tab_management_java_sources = [
"//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurface.java",
+ "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/EmptyTabGroupModelFilterObserver.java",
"//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupModelFilter.java",
"//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/SilenceLintErrors.java",
"//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUi.java",
diff --git a/chromium/chrome/app/resources/chromium_strings_sl.xtb b/chromium/chrome/app/resources/chromium_strings_sl.xtb
index 7639f108ba8..44ad5806bcf 100644
--- a/chromium/chrome/app/resources/chromium_strings_sl.xtb
+++ b/chromium/chrome/app/resources/chromium_strings_sl.xtb
@@ -36,7 +36,7 @@ Nekatere funkcije morda niso na voljo in spremembe nastavitev ne bodo shranjene.
<translation id="2347108572062610441">Zaradi te razširitve se je spremenila stran, ki je prikazana, ko zaženete Chromium.</translation>
<translation id="2396765026452590966">Zaradi razširitve »<ph name="EXTENSION_NAME" />« se je spremenila stran, ki je prikazana, ko zaženete Chromium.</translation>
<translation id="2483889755041906834">V Chromiumu</translation>
-<translation id="2485422356828889247">Odstranjevanje</translation>
+<translation id="2485422356828889247">Odmeščanje</translation>
<translation id="2527042973354814951">Znova zaženite Chromium, če želite omogočiti <ph name="PLUGIN_NAME" /></translation>
<translation id="2535480412977113886">Chromium OS ni mogel sinhronizirati podatkov, ker so podatki za prijavo v račun zastareli.</translation>
<translation id="2560420686485554789">Chromium potrebuje za prenos datotek dostop do shrambe</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_es.xtb b/chromium/chrome/app/resources/generated_resources_es.xtb
index b3d14f2c6cb..a124286b6ed 100644
--- a/chromium/chrome/app/resources/generated_resources_es.xtb
+++ b/chromium/chrome/app/resources/generated_resources_es.xtb
@@ -1672,7 +1672,7 @@ Si no cambias la configuración predeterminada, <ph name="USER_DISPLAY_NAME" />
<translation id="3493486281776271508">Se necesita conexión a Internet</translation>
<translation id="3493881266323043047">Validez</translation>
<translation id="3494769164076977169">Preguntar cuando un sitio intente descargar archivos automáticamente después del primer archivo (recomendado)</translation>
-<translation id="3495660573538963482">Configuración del Asistente de Google</translation>
+<translation id="3495660573538963482">Ajustes del Asistente de Google</translation>
<translation id="3496213124478423963">Alejar</translation>
<translation id="3497560059572256875">Compartir doodle</translation>
<translation id="3505030558724226696">Revocar acceso al dispositivo</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_kn.xtb b/chromium/chrome/app/resources/generated_resources_kn.xtb
index 17c843e5d5d..964c9a5b207 100644
--- a/chromium/chrome/app/resources/generated_resources_kn.xtb
+++ b/chromium/chrome/app/resources/generated_resources_kn.xtb
@@ -3318,7 +3318,7 @@
<translation id="5959471481388474538">ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿಲ್ಲ</translation>
<translation id="595959584676692139">ಈ ವಿಸ್ತರಣೆಯನ್ನು ಬಳಸಲು ಪುಟವನ್ನು ಪುನಃ ಲೋಡ್ ಮಾಡಿ</translation>
<translation id="5963453369025043595"><ph name="NUM_HANDLES" /> (<ph name="NUM_KILOBYTES_LIVE" /> ಪೀಕ್)</translation>
-<translation id="5965661248935608907">ನೀವು ಹೋಮ್ ಬಟನ್ ಕ್ಲಿಕ್ ಮಾಡಿದಾಗ ಅಥವಾ ಓಮ್ನಿಬಾಕ್ಸ್‌ನಿಂದ ಹುಡುಕಿದಾಗ ತೋರಿಸಬೇಕಾದ ಪುಟವನ್ನು ಕೂಡಾ ಇದು ನಿಯಂತ್ರಿಸುತ್ತದೆ.</translation>
+<translation id="5965661248935608907">ನೀವು ಹೋಮ್ ಬಟನ್ ಕ್ಲಿಕ್ ಮಾಡಿದಾಗ ಅಥವಾ ಆಮ್ನಿಬಾಕ್ಸ್ ‌ನಿಂದ ಹುಡುಕಿದಾಗ ತೋರಿಸಬೇಕಾದ ಪುಟವನ್ನು ಕೂಡಾ ಇದು ನಿಯಂತ್ರಿಸುತ್ತದೆ.</translation>
<translation id="5971037678316050792">ಬ್ಲೂಟೂತ್‌ ಅಡಾಪ್ಟರ್ ಸ್ಥಿತಿ ಮತ್ತು ಜೋಡಿಸುವಿಕೆಯನ್ನು ನಿಯಂತ್ರಿಸಿ</translation>
<translation id="5972017421290582825">MIDI ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ...</translation>
<translation id="597235323114979258">ಇನ್ನಷ್ಟು ಗಮ್ಯಸ್ಥಾನಗಳನ್ನು ನೋಡಿ</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_sl.xtb b/chromium/chrome/app/resources/generated_resources_sl.xtb
index e17e8e09cb1..6bc0b9e5264 100644
--- a/chromium/chrome/app/resources/generated_resources_sl.xtb
+++ b/chromium/chrome/app/resources/generated_resources_sl.xtb
@@ -1006,7 +1006,7 @@
<translation id="2480868415629598489">Spreminjanje podatkov, ki jih kopirate in prilepite</translation>
<translation id="2482878487686419369">Obvestila</translation>
<translation id="2484959914739448251">Če želite izbrisati podatke brskanja iz vseh sinhroniziranih naprav in Google Računa, <ph name="BEGIN_LINK" />vnesite geslo<ph name="END_LINK" />.</translation>
-<translation id="2485422356828889247">Odstranjevanje</translation>
+<translation id="2485422356828889247">Odmeščanje</translation>
<translation id="2487067538648443797">Dodaj nov zaznamek</translation>
<translation id="2489829450872380594">Naslednjič bo nov telefon odklenil to napravo <ph name="DEVICE_TYPE" />. Funkcijo Smart Lock lahko izklopite v nastavitvah.</translation>
<translation id="2489918096470125693">Dodaj &amp;mapo ...</translation>
@@ -4901,7 +4901,7 @@ Datoteko s ključem shranite na varnem. Potrebovali jo boste za izdelavo novih r
<translation id="8286036467436129157">Prijava</translation>
<translation id="8286963743045814739">Z oknom brez beleženja zgodovine lahko zasebno brskate</translation>
<translation id="8287902281644548111">Iskanje po klicu API-jul/URL-ju</translation>
-<translation id="8288032458496410887">Odstranjevanje aplikacije <ph name="APP" /> …</translation>
+<translation id="8288032458496410887">Odmeščanje aplikacije <ph name="APP" /> …</translation>
<translation id="8291967909914612644">Država domačega ponudnika</translation>
<translation id="8294431847097064396">Vir</translation>
<translation id="8297006494302853456">Šibek</translation>
diff --git a/chromium/chrome/app/resources/generated_resources_tr.xtb b/chromium/chrome/app/resources/generated_resources_tr.xtb
index dbf9a619968..dad96e31314 100644
--- a/chromium/chrome/app/resources/generated_resources_tr.xtb
+++ b/chromium/chrome/app/resources/generated_resources_tr.xtb
@@ -2810,7 +2810,7 @@ Sunucunun mesajı: <ph name="SERVER_MSG" /></translation>
<translation id="5222676887888702881">Çıkış</translation>
<translation id="52232769093306234">Paketleme başarısız oldu.</translation>
<translation id="5225324770654022472">Uygulamalar kısayolunu göster</translation>
-<translation id="5227679487546032910">Varsayılan koyu camgöbeği avatar</translation>
+<translation id="5227679487546032910">Varsayılan koyu turkuaz avatar</translation>
<translation id="5228076606934445476">Cihazda bir sorun var. Bu hatadan kurtulmak için cihazı yeniden başlatıp tekrar denemeniz gerekir.</translation>
<translation id="5229189185761556138">Giriş yöntemlerini yönet</translation>
<translation id="5230516054153933099">Pencere</translation>
diff --git a/chromium/chrome/app/resources/google_chrome_strings_sl.xtb b/chromium/chrome/app/resources/google_chrome_strings_sl.xtb
index 30f0d40e17c..055ddf179f9 100644
--- a/chromium/chrome/app/resources/google_chrome_strings_sl.xtb
+++ b/chromium/chrome/app/resources/google_chrome_strings_sl.xtb
@@ -66,7 +66,7 @@ Nekatere funkcije morda niso na voljo in spremembe nastavitev ne bodo shranjene.
<translation id="2348335408836342058">Chrome potrebuje dovoljenje za dostop do fotoaparata in mikrofona za to spletno mesto</translation>
<translation id="2429317896000329049">Google Chrome ni mogel sinhronizirati podatkov, ker sinhronizacija ni na voljo za vašo domeno.</translation>
<translation id="2467438592969358367">Google Chrome želi izvoziti gesla. Če želite omogočiti to, vnesite geslo za Windows.</translation>
-<translation id="2485422356828889247">Odstranjevanje</translation>
+<translation id="2485422356828889247">Odmeščanje</translation>
<translation id="2534507159460261402">Google Pay (kopirano v Chrome)</translation>
<translation id="2535429035253759792">Skrbnik prosi, da za uveljavitev te posodobitve znova zaženete Chrome</translation>
<translation id="2580411288591421699">Ni mogoče namestiti različice Google Chroma, enake tisti, ki se trenutno izvaja. Zaprite Google Chrome in poskusite znova.</translation>
diff --git a/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc b/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
index 9d49d65504c..633d8ff73d2 100644
--- a/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
@@ -13,9 +13,12 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h"
#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/video_capture_service.h"
+#include "content/public/browser/system_connector.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace extensions {
@@ -65,18 +68,22 @@ void MediaPerceptionAPIDelegateChromeOS::LoadCrOSComponent(
base::BindOnce(OnLoadComponent, std::move(load_callback)));
}
-void MediaPerceptionAPIDelegateChromeOS::BindVideoSourceProvider(
- mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver) {
+void MediaPerceptionAPIDelegateChromeOS::
+ BindDeviceFactoryProviderToVideoCaptureService(
+ video_capture::mojom::DeviceFactoryProviderPtr* provider) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // In unit test environments, there may not be any connector.
+ service_manager::Connector* connector = content::GetSystemConnector();
+ if (!connector)
+ return;
+ connector->BindInterface(video_capture::mojom::kServiceName, provider);
+
video_capture::mojom::AcceleratorFactoryPtr accelerator_factory;
mojo::MakeStrongBinding(
std::make_unique<
content::DelegateToBrowserGpuServiceAcceleratorFactory>(),
mojo::MakeRequest(&accelerator_factory));
-
- auto& service = content::GetVideoCaptureService();
- service.InjectGpuDependencies(std::move(accelerator_factory));
- service.ConnectToVideoSourceProvider(std::move(receiver));
+ (*provider)->InjectGpuDependencies(std::move(accelerator_factory));
}
void MediaPerceptionAPIDelegateChromeOS::SetMediaPerceptionRequestHandler(
diff --git a/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h b/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h
index 45abc51201e..1d765110283 100644
--- a/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h
+++ b/chromium/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h
@@ -20,9 +20,8 @@ class MediaPerceptionAPIDelegateChromeOS
void LoadCrOSComponent(
const api::media_perception_private::ComponentType& type,
LoadCrOSComponentCallback load_callback) override;
- void BindVideoSourceProvider(
- mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
- override;
+ void BindDeviceFactoryProviderToVideoCaptureService(
+ video_capture::mojom::DeviceFactoryProviderPtr* provider) override;
void SetMediaPerceptionRequestHandler(
MediaPerceptionRequestHandler handler) override;
void ForwardMediaPerceptionRequest(
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json
index d58562d990f..079eca1a6bb 100644
--- a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json
+++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json
@@ -1,5 +1,5 @@
{
- "x-version": 41,
+ "x-version": 42,
"adobe-flash-player": {
"mime_types": [
"application/futuresplash",
@@ -10,9 +10,9 @@
],
"versions": [
{
- "version": "32.0.0.207",
+ "version": "32.0.0.255",
"status": "up_to_date",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-30.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-46.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json
index eb67de53c11..0351e901fab 100644
--- a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json
+++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json
@@ -1,5 +1,5 @@
{
- "x-version": 47,
+ "x-version": 48,
"adobe-flash-player": {
"mime_types": [
"application/futuresplash",
@@ -7,9 +7,9 @@
],
"versions": [
{
- "version": "32.0.0.207",
+ "version": "32.0.0.255",
"status": "requires_authorization",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-30.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-46.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json
index ecf05d88a44..5df5cacdb68 100644
--- a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json
+++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@
{
- "x-version": 56,
+ "x-version": 57,
"adobe-flash-player": {
"mime_types": [
"application/futuresplash",
@@ -7,9 +7,9 @@
],
"versions": [
{
- "version": "32.0.0.207",
+ "version": "32.0.0.255",
"status": "requires_authorization",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-30.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-46.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/common/webui_url_constants.cc b/chromium/chrome/common/webui_url_constants.cc
index 4ea75d777ba..9aafec47750 100644
--- a/chromium/chrome/common/webui_url_constants.cc
+++ b/chromium/chrome/common/webui_url_constants.cc
@@ -168,6 +168,11 @@ const char kChromeUIVersionURL[] = "chrome://version/";
const char kChromeUIWelcomeHost[] = "welcome";
const char kChromeUIWelcomeURL[] = "chrome://welcome/";
+#if defined(OS_WIN)
+// TODO(crbug.com/1003960): Remove when issue is resolved.
+const char kChromeUIWelcomeWin10Host[] = "welcome-win10";
+#endif // defined(OS_WIN)
+
#if defined(OS_ANDROID)
const char kChromeUIExploreSitesInternalsHost[] = "explore-sites-internals";
const char kChromeUIJavaCrashURL[] = "chrome://java-crash/";
diff --git a/chromium/chrome/common/webui_url_constants.h b/chromium/chrome/common/webui_url_constants.h
index f6935a34532..7d60fd45b9b 100644
--- a/chromium/chrome/common/webui_url_constants.h
+++ b/chromium/chrome/common/webui_url_constants.h
@@ -170,6 +170,11 @@ extern const char kChromeUIVersionURL[];
extern const char kChromeUIWelcomeHost[];
extern const char kChromeUIWelcomeURL[];
+#if defined(OS_WIN)
+// TODO(crbug.com/1003960): Remove when issue is resolved.
+extern const char kChromeUIWelcomeWin10Host[];
+#endif // defined(OS_WIN)
+
#if defined(OS_ANDROID)
extern const char kChromeUIExploreSitesInternalsHost[];
extern const char kChromeUIJavaCrashURL[];
diff --git a/chromium/chrome/credential_provider/gaiacp/gaia_resources.grd b/chromium/chrome/credential_provider/gaiacp/gaia_resources.grd
index b44f6f614f2..54f712f3b92 100644
--- a/chromium/chrome/credential_provider/gaiacp/gaia_resources.grd
+++ b/chromium/chrome/credential_provider/gaiacp/gaia_resources.grd
@@ -106,6 +106,9 @@
<message name="IDS_NO_NETWORK" desc="">
Make sure you have a network connection and try again.
</message>
+ <message name="IDS_FAILED_CREATE_LOGON_STUB" desc="">
+ Unable to load Google sign in screen. Please contact your administrator.
+ </message>
<message name="IDS_PASSWORD_UPDATE_NEEDED" desc="">
Your account password has changed. Please enter your current Windows password in order to sync your Windows account with your work account.
</message>
diff --git a/chromium/chrome/test/BUILD.gn b/chromium/chrome/test/BUILD.gn
index 39a8fc30840..954efb53669 100644
--- a/chromium/chrome/test/BUILD.gn
+++ b/chromium/chrome/test/BUILD.gn
@@ -3067,6 +3067,7 @@ test("unit_tests") {
"../browser/previews/previews_lite_page_predictor_unittest.cc",
"../browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc",
"../browser/previews/previews_offline_helper_unittest.cc",
+ "../browser/previews/previews_service_render_view_unittest.cc",
"../browser/previews/previews_service_unittest.cc",
"../browser/previews/previews_top_host_provider_unittest.cc",
"../browser/previews/previews_ui_tab_helper_unittest.cc",
diff --git a/chromium/components/arc/ime/DEPS b/chromium/components/arc/ime/DEPS
index 2b08010744b..ab2c42a02ab 100644
--- a/chromium/components/arc/ime/DEPS
+++ b/chromium/components/arc/ime/DEPS
@@ -7,5 +7,4 @@ include_rules = [
"+ui/gfx/geometry",
# Revisit this dependency when crbug.com/890403 is resovled.
"+ui/views",
- "+ui/wm",
]
diff --git a/chromium/components/arc/ime/arc_ime_service.cc b/chromium/components/arc/ime/arc_ime_service.cc
index ebe0b002f9d..5b4a0c02da5 100644
--- a/chromium/components/arc/ime/arc_ime_service.cc
+++ b/chromium/components/arc/ime/arc_ime_service.cc
@@ -26,7 +26,6 @@
#include "ui/gfx/range/range.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"
-#include "ui/wm/core/ime_util_chromeos.h"
namespace arc {
@@ -490,13 +489,6 @@ bool ArcImeService::GetTextFromRange(const gfx::Range& range,
return true;
}
-void ArcImeService::EnsureCaretNotInRect(const gfx::Rect& rect_in_screen) {
- if (focused_arc_window_ == nullptr)
- return;
- aura::Window* top_level_window = focused_arc_window_->GetToplevelWindow();
- wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
-}
-
ui::TextInputMode ArcImeService::GetTextInputMode() const {
return ui::TEXT_INPUT_MODE_DEFAULT;
}
diff --git a/chromium/components/arc/ime/arc_ime_service.h b/chromium/components/arc/ime/arc_ime_service.h
index 2b3276ee623..c8f20c8c8fe 100644
--- a/chromium/components/arc/ime/arc_ime_service.h
+++ b/chromium/components/arc/ime/arc_ime_service.h
@@ -121,7 +121,6 @@ class ArcImeService : public KeyedService,
bool GetEditableSelectionRange(gfx::Range* range) const override;
bool GetTextFromRange(const gfx::Range& range,
base::string16* text) const override;
- void EnsureCaretNotInRect(const gfx::Rect& rect) override;
// Overridden from ui::TextInputClient (with default implementation):
// TODO(kinaba): Support each of these methods to the extent possible in
@@ -141,6 +140,7 @@ class ArcImeService : public KeyedService,
bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) override;
void ExtendSelectionAndDelete(size_t before, size_t after) override;
+ void EnsureCaretNotInRect(const gfx::Rect& rect) override {}
bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override {
}
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
index 3280327f767..84eecdc0f29 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -908,14 +908,14 @@ TEST(CreditCardTest,
b.set_guid(base::GenerateGUID());
b.set_origin(test::kEmptyOrigin);
b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
- b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
+ b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2023"));
EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
EXPECT_EQ("Chrome settings", a.origin());
EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
a.GetRawInfo(CREDIT_CARD_NAME_FULL));
EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
- EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
+ EXPECT_EQ(ASCIIToUTF16("2023"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
}
TEST(CreditCardTest,
diff --git a/chromium/components/autofill_assistant/browser/actions/get_payment_information_action.cc b/chromium/components/autofill_assistant/browser/actions/get_payment_information_action.cc
index fd31bccc08f..4f647963cc8 100644
--- a/chromium/components/autofill_assistant/browser/actions/get_payment_information_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/get_payment_information_action.cc
@@ -120,9 +120,9 @@ void GetPaymentInformationAction::OnGetPaymentInformation(
autofill::AutofillProfile contact_profile;
contact_profile.SetRawInfo(
autofill::ServerFieldType::NAME_FULL,
- base::ASCIIToUTF16(payment_information->payer_name));
+ base::UTF8ToUTF16(payment_information->payer_name));
autofill::data_util::NameParts parts = autofill::data_util::SplitName(
- base::ASCIIToUTF16(payment_information->payer_name));
+ base::UTF8ToUTF16(payment_information->payer_name));
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FIRST,
parts.given);
contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_MIDDLE,
@@ -131,10 +131,10 @@ void GetPaymentInformationAction::OnGetPaymentInformation(
parts.family);
contact_profile.SetRawInfo(
autofill::ServerFieldType::EMAIL_ADDRESS,
- base::ASCIIToUTF16(payment_information->payer_email));
+ base::UTF8ToUTF16(payment_information->payer_email));
contact_profile.SetRawInfo(
autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
- base::ASCIIToUTF16(payment_information->payer_phone));
+ base::UTF8ToUTF16(payment_information->payer_phone));
if (!contact_details_proto.contact_details_name().empty()) {
delegate_->GetClientMemory()->set_selected_address(
contact_details_proto.contact_details_name(),
diff --git a/chromium/components/dom_distiller/DEPS b/chromium/components/dom_distiller/DEPS
index ea653ead7d3..9e2dcd6f5c0 100644
--- a/chromium/components/dom_distiller/DEPS
+++ b/chromium/components/dom_distiller/DEPS
@@ -8,6 +8,7 @@ include_rules = [
"+components/sync/protocol",
"+components/sync_preferences",
"+components/variations",
+ "+crypto", # For sha256
"+google", # For third_party/protobuf.
"+third_party/dom_distiller_js",
"+third_party/re2",
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index 53de6967aaf..27c0ac02e58 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -55,8 +55,7 @@ class DomDistillerViewerSource::RequestViewerHandle
public content::WebContentsObserver {
public:
RequestViewerHandle(content::WebContents* web_contents,
- const std::string& expected_scheme,
- const std::string& expected_request_path,
+ const GURL& expected_url,
DistilledPagePrefs* distilled_page_prefs,
DistillerUIHandle* ui_handle);
~RequestViewerHandle() override;
@@ -83,11 +82,8 @@ class DomDistillerViewerSource::RequestViewerHandle
// cancelled.
void Cancel();
- // The scheme hosting the current view request;
- std::string expected_scheme_;
-
- // The query path for the current view request.
- std::string expected_request_path_;
+ // The URL hosting the current view request;
+ const GURL expected_url_;
// Whether the page is sufficiently initialized to handle updates from the
// distiller.
@@ -108,13 +104,11 @@ class DomDistillerViewerSource::RequestViewerHandle
DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
content::WebContents* web_contents,
- const std::string& expected_scheme,
- const std::string& expected_request_path,
+ const GURL& expected_url,
DistilledPagePrefs* distilled_page_prefs,
DistillerUIHandle* ui_handle)
: DomDistillerRequestViewBase(distilled_page_prefs),
- expected_scheme_(expected_scheme),
- expected_request_path_(expected_request_path),
+ expected_url_(expected_url),
waiting_for_page_ready_(true),
distiller_ui_handle_(ui_handle) {
content::WebContentsObserver::Observe(web_contents);
@@ -146,9 +140,7 @@ void DomDistillerViewerSource::RequestViewerHandle::DidFinishNavigation(
return;
const GURL& navigation = navigation_handle->GetURL();
- bool expected_main_view_request =
- navigation.SchemeIs(expected_scheme_) &&
- expected_request_path_ == navigation.query();
+ bool expected_main_view_request = navigation == expected_url_;
if (navigation_handle->IsSameDocument() || expected_main_view_request) {
// In-page navigations, as well as the main view request can be ignored.
if (expected_main_view_request) {
@@ -260,21 +252,29 @@ void DomDistillerViewerSource::StartDataRequest(
}
}
- // An empty |path| is invalid, but guard against it. If not empty, assume
- // |path| starts with '?', which is stripped away.
- const std::string path_after_query_separator =
- path.size() > 0 ? path.substr(1) : "";
+ // We need the host part to validate the parameter, but it's not available
+ // from |URLDataSource|. |web_contents| is the most convenient place to
+ // obtain the full URL.
+ // TODO(crbug.com/991888): pass GURL in URLDataSource::StartDataRequest().
+ const std::string query = GURL("https://host/" + path).query();
+ GURL request_url = web_contents->GetVisibleURL();
+ // The query should match what's seen in |web_contents|.
+ // For javascript:window.open(), it's not the case, but it's not a supported
+ // use case.
+ if (request_url.query() != query || request_url.path() != "/") {
+ request_url = GURL();
+ }
RequestViewerHandle* request_viewer_handle =
- new RequestViewerHandle(web_contents, scheme_, path_after_query_separator,
+ new RequestViewerHandle(web_contents, request_url,
dom_distiller_service_->GetDistilledPagePrefs(),
distiller_ui_handle_.get());
std::unique_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
- dom_distiller_service_, path, request_viewer_handle,
+ dom_distiller_service_, request_url, request_viewer_handle,
web_contents->GetContainerBounds().size());
- GURL current_url(url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey));
+ GURL current_url(url_utils::GetOriginalUrlFromDistillerUrl(request_url));
std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
- url_utils::GetOriginalUrlFromDistillerUrl(current_url).spec(),
+ current_url.spec(),
dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(),
dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily());
diff --git a/chromium/components/dom_distiller/core/url_utils.cc b/chromium/components/dom_distiller/core/url_utils.cc
index cac08dd1b7c..cd7fc39bf94 100644
--- a/chromium/components/dom_distiller/core/url_utils.cc
+++ b/chromium/components/dom_distiller/core/url_utils.cc
@@ -8,11 +8,14 @@
#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "components/dom_distiller/core/url_constants.h"
#include "components/grit/components_resources.h"
+#include "crypto/sha2.h"
#include "net/base/url_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/gurl.h"
+#include "url/url_util.h"
namespace dom_distiller {
@@ -21,6 +24,12 @@ namespace url_utils {
namespace {
const char kDummyInternalUrlPrefix[] = "chrome-distiller-internal://dummy/";
+const char kSeparator[] = "_";
+
+std::string SHA256InHex(base::StringPiece str) {
+ std::string sha256 = crypto::SHA256HashString(str);
+ return base::ToLowerASCII(base::HexEncode(sha256.c_str(), sha256.size()));
+}
} // namespace
@@ -31,28 +40,44 @@ const GURL GetDistillerViewUrlFromEntryId(const std::string& scheme,
}
const GURL GetDistillerViewUrlFromUrl(const std::string& scheme,
- const GURL& view_url,
+ const GURL& url,
int64_t start_time_ms) {
- GURL url(scheme + "://" + base::GenerateGUID());
+ GURL view_url(scheme + "://" + base::GenerateGUID() + kSeparator +
+ SHA256InHex(url.spec()));
if (start_time_ms > 0) {
- url = net::AppendOrReplaceQueryParameter(
- url, kTimeKey, base::NumberToString(start_time_ms));
+ view_url = net::AppendOrReplaceQueryParameter(
+ view_url, kTimeKey, base::NumberToString(start_time_ms));
}
- return net::AppendOrReplaceQueryParameter(url, kUrlKey, view_url.spec());
+ return net::AppendOrReplaceQueryParameter(view_url, kUrlKey, url.spec());
}
const GURL GetOriginalUrlFromDistillerUrl(const GURL& url) {
- if (!dom_distiller::url_utils::IsDistilledPage(url))
+ if (!IsDistilledPage(url))
return url;
std::string original_url_str;
net::GetValueForKeyInQuery(url, kUrlKey, &original_url_str);
- return GURL(original_url_str);
+ // Make sure kDomDistillerScheme is considered standard scheme for
+ // |GURL::host_piece()| to work correctly.
+ DCHECK(url::IsStandard(kDomDistillerScheme,
+ url::Component(0, strlen(kDomDistillerScheme))));
+ std::vector<base::StringPiece> pieces =
+ base::SplitStringPiece(url.host_piece(), kSeparator,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ if (pieces.size() != 2)
+ return GURL();
+ if (SHA256InHex(original_url_str) != pieces[1])
+ return GURL();
+ const GURL original_url(original_url_str);
+ if (!IsUrlDistillable(original_url))
+ return GURL();
+
+ return original_url;
}
int64_t GetTimeFromDistillerUrl(const GURL& url) {
- if (!dom_distiller::url_utils::IsDistilledPage(url))
+ if (!IsDistilledPage(url))
return 0;
std::string time_str;
diff --git a/chromium/components/dom_distiller/core/url_utils.h b/chromium/components/dom_distiller/core/url_utils.h
index d0beeb8a127..8f94a56d3a3 100644
--- a/chromium/components/dom_distiller/core/url_utils.h
+++ b/chromium/components/dom_distiller/core/url_utils.h
@@ -25,7 +25,9 @@ const GURL GetDistillerViewUrlFromUrl(const std::string& scheme,
int64_t start_time_ms = 0);
// Returns the original URL from the distilled URL.
-// If the URL is not distilled, it is returned as is.
+// If |distilled_url| is not distilled, it is returned as is.
+// If |distilled_url| looks like distilled, but no original URL can be found,
+// an empty, invalid URL is returned.
const GURL GetOriginalUrlFromDistillerUrl(const GURL& distilled_url);
// Returns the starting time from the distilled URL.
diff --git a/chromium/components/dom_distiller/core/url_utils_unittest.cc b/chromium/components/dom_distiller/core/url_utils_unittest.cc
index ed10e23b908..5dd2100491b 100644
--- a/chromium/components/dom_distiller/core/url_utils_unittest.cc
+++ b/chromium/components/dom_distiller/core/url_utils_unittest.cc
@@ -5,8 +5,10 @@
#include "components/dom_distiller/core/url_utils.h"
#include "components/dom_distiller/core/url_constants.h"
+#include "net/base/url_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+#include "url/url_util.h"
namespace dom_distiller {
@@ -15,9 +17,12 @@ namespace url_utils {
TEST(DomDistillerUrlUtilsTest, TestPathUtil) {
const std::string single_key = "mypath?foo=bar";
EXPECT_EQ("bar", GetValueForKeyInUrlPathQuery(single_key, "foo"));
+
const std::string two_keys = "mypath?key1=foo&key2=bar";
EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(two_keys, "key1"));
EXPECT_EQ("bar", GetValueForKeyInUrlPathQuery(two_keys, "key2"));
+
+ // First occurrence wins.
const std::string multiple_same_key = "mypath?key=foo&key=bar";
EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(multiple_same_key, "key"));
}
@@ -41,16 +46,43 @@ TEST(DomDistillerUrlUtilsTest, TestGetValueForKeyInUrlPathQuery) {
EXPECT_EQ("foo", GetValueForKeyInUrlPathQuery(valid_url_two_keys, "key"));
}
-std::string ThroughDistiller(const std::string& url) {
- return GetOriginalUrlFromDistillerUrl(
- GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123))
- .spec();
+void AssertEqualExceptHost(const GURL& a, const GURL& b) {
+ url::Replacements<char> no_host;
+ no_host.ClearHost();
+ EXPECT_EQ(a.ReplaceComponents(no_host), b.ReplaceComponents(no_host));
+}
+
+TEST(DomDistillerUrlUtilsTest, TestGetDistillerViewUrlFromUrl) {
+ AssertEqualExceptHost(
+ GURL("chrome-distiller://any/"
+ "?time=123&url=http%3A%2F%2Fexample.com%2Fpath%3Fq%3Dabc%26p%3D1%"
+ "23anchor"),
+ GetDistillerViewUrlFromUrl(
+ kDomDistillerScheme, GURL("http://example.com/path?q=abc&p=1#anchor"),
+ 123));
}
std::string GetOriginalUrlFromDistillerUrl(const std::string& url) {
return GetOriginalUrlFromDistillerUrl(GURL(url)).spec();
}
+TEST(DomDistillerUrlUtilsTest, TestGetOriginalUrlFromDistillerUrl) {
+ EXPECT_EQ(
+ "http://example.com/path?q=abc&p=1#anchor",
+ GetOriginalUrlFromDistillerUrl(
+ "chrome-distiller://"
+ "any_"
+ "d091ebf8f841eae9ca23822c3d0f369c16d3748478d0b74111be176eb96722e5/"
+ "?time=123&url=http%3A%2F%2Fexample.com%2Fpath%3Fq%3Dabc%26p%3D1%"
+ "23anchor"));
+}
+
+std::string ThroughDistiller(const std::string& url) {
+ return GetOriginalUrlFromDistillerUrl(
+ GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123))
+ .spec();
+}
+
TEST(DomDistillerUrlUtilsTest, TestDistillerEndToEnd) {
// Tests a normal url.
const std::string url = "http://example.com/";
@@ -65,8 +97,24 @@ TEST(DomDistillerUrlUtilsTest, TestDistillerEndToEnd) {
// Tests a url with file:// scheme.
const std::string url_file = "file:///home/userid/path/index.html";
- EXPECT_EQ(url_file, ThroughDistiller(url_file));
+ EXPECT_EQ("", ThroughDistiller(url_file));
EXPECT_EQ(url_file, GetOriginalUrlFromDistillerUrl(url_file));
+
+ // Tests a nested url.
+ const std::string nested_url =
+ GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url)).spec();
+ EXPECT_EQ("", ThroughDistiller(nested_url));
+ EXPECT_EQ(url, GetOriginalUrlFromDistillerUrl(nested_url));
+}
+
+TEST(DomDistillerUrlUtilsTest, TestRejectInvalidURLs) {
+ const std::string url = "http://example.com/";
+ const std::string url2 = "http://example.org/";
+ const GURL view_url =
+ GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url), 123);
+ GURL bad_view_url =
+ net::AppendOrReplaceQueryParameter(view_url, kUrlKey, url2);
+ EXPECT_EQ(GURL(), GetOriginalUrlFromDistillerUrl(bad_view_url));
}
} // namespace url_utils
diff --git a/chromium/components/dom_distiller/core/viewer.cc b/chromium/components/dom_distiller/core/viewer.cc
index 6f5739d8a54..6fa470261ba 100644
--- a/chromium/components/dom_distiller/core/viewer.cc
+++ b/chromium/components/dom_distiller/core/viewer.cc
@@ -250,17 +250,17 @@ const std::string GetJavaScript() {
std::unique_ptr<ViewerHandle> CreateViewRequest(
DomDistillerServiceInterface* dom_distiller_service,
- const std::string& path,
+ const GURL& url,
ViewRequestDelegate* view_request_delegate,
const gfx::Size& render_view_size) {
- std::string entry_id =
- url_utils::GetValueForKeyInUrlPathQuery(path, kEntryIdKey);
+ if (!url_utils::IsDistilledPage(url)) {
+ return nullptr;
+ }
+ std::string entry_id = url_utils::GetValueForKeyInUrl(url, kEntryIdKey);
bool has_valid_entry_id = !entry_id.empty();
entry_id = base::ToUpperASCII(entry_id);
- std::string requested_url_str =
- url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey);
- GURL requested_url(requested_url_str);
+ GURL requested_url(url_utils::GetOriginalUrlFromDistillerUrl(url));
bool has_valid_url = url_utils::IsUrlDistillable(requested_url);
if (has_valid_entry_id && has_valid_url) {
diff --git a/chromium/components/dom_distiller/core/viewer.h b/chromium/components/dom_distiller/core/viewer.h
index 724e95aa0d8..96269ddc897 100644
--- a/chromium/components/dom_distiller/core/viewer.h
+++ b/chromium/components/dom_distiller/core/viewer.h
@@ -12,6 +12,7 @@
#include "base/strings/string16.h"
#include "components/dom_distiller/core/distilled_page_prefs.h"
#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
namespace dom_distiller {
@@ -75,7 +76,7 @@ const std::string GetJavaScript();
// viewing distilled content based on the |path|.
std::unique_ptr<ViewerHandle> CreateViewRequest(
DomDistillerServiceInterface* dom_distiller_service,
- const std::string& path,
+ const GURL& url,
ViewRequestDelegate* view_request_delegate,
const gfx::Size& render_view_size);
diff --git a/chromium/components/dom_distiller/core/viewer_unittest.cc b/chromium/components/dom_distiller/core/viewer_unittest.cc
index 1e69a43440c..493daad1ff2 100644
--- a/chromium/components/dom_distiller/core/viewer_unittest.cc
+++ b/chromium/components/dom_distiller/core/viewer_unittest.cc
@@ -9,11 +9,24 @@
#include "components/dom_distiller/core/dom_distiller_test_util.h"
#include "components/dom_distiller/core/task_tracker.h"
#include "components/dom_distiller/core/url_constants.h"
+#include "components/dom_distiller/core/url_utils.h"
+#include "net/base/url_util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/url_util.h"
namespace dom_distiller {
-const char kTestScheme[] = "myscheme";
+namespace {
+
+const GURL GetDistillerViewUrlFromUrl(const std::string& url) {
+ return url_utils::GetDistillerViewUrlFromUrl(kDomDistillerScheme, GURL(url));
+}
+
+const GURL GetDistillerViewUrlFromEntryId(const std::string& id) {
+ return url_utils::GetDistillerViewUrlFromEntryId(kDomDistillerScheme, id);
+}
+
+} // namespace
class FakeViewRequestDelegate : public ViewRequestDelegate {
public:
@@ -78,10 +91,10 @@ class DomDistillerViewerTest : public testing::Test {
protected:
std::unique_ptr<ViewerHandle> CreateViewRequest(
- const std::string& path,
+ const GURL& url,
ViewRequestDelegate* view_request_delegate) {
- return viewer::CreateViewRequest(service_.get(), path,
- view_request_delegate, gfx::Size());
+ return viewer::CreateViewRequest(service_.get(), url, view_request_delegate,
+ gfx::Size());
}
std::unique_ptr<TestDomDistillerService> service_;
@@ -94,9 +107,8 @@ TEST_F(DomDistillerViewerTest, TestCreatingViewUrlRequest) {
EXPECT_CALL(*service_, ViewUrlImpl())
.WillOnce(testing::Return(viewer_handle));
EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
- CreateViewRequest(
- std::string("?") + kUrlKey + "=http%3A%2F%2Fwww.example.com%2F",
- view_request_delegate.get());
+ CreateViewRequest(GetDistillerViewUrlFromUrl("http://www.example.com/"),
+ view_request_delegate.get());
}
TEST_F(DomDistillerViewerTest, TestCreatingViewEntryRequest) {
@@ -106,7 +118,7 @@ TEST_F(DomDistillerViewerTest, TestCreatingViewEntryRequest) {
EXPECT_CALL(*service_, ViewEntryImpl())
.WillOnce(testing::Return(viewer_handle));
EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
- CreateViewRequest(std::string("?") + kEntryIdKey + "=abc-def",
+ CreateViewRequest(GetDistillerViewUrlFromEntryId("abc-def"),
view_request_delegate.get());
}
@@ -116,19 +128,24 @@ TEST_F(DomDistillerViewerTest, TestCreatingInvalidViewRequest) {
EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
// Specify none of the required query parameters.
- CreateViewRequest("?foo=bar", view_request_delegate.get());
+ CreateViewRequest(GURL(std::string(kDomDistillerScheme) + "://host?foo=bar"),
+ view_request_delegate.get());
// Specify both of the required query parameters.
- CreateViewRequest("?" + std::string(kUrlKey) +
- "=http%3A%2F%2Fwww.example.com%2F&" +
- std::string(kEntryIdKey) + "=abc-def",
+ CreateViewRequest(net::AppendOrReplaceQueryParameter(
+ GetDistillerViewUrlFromUrl("http://www.example.com/"),
+ kEntryIdKey, "abc-def"),
view_request_delegate.get());
// Specify an internal Chrome page.
- CreateViewRequest("?" + std::string(kUrlKey) + "=chrome%3A%2F%2Fsettings%2F",
+ CreateViewRequest(GetDistillerViewUrlFromUrl("chrome://settings/"),
view_request_delegate.get());
// Specify a recursive URL.
- CreateViewRequest("?" + std::string(kUrlKey) + "=" +
- std::string(kTestScheme) + "%3A%2F%2Fabc-def%2F",
+ CreateViewRequest(GetDistillerViewUrlFromUrl(
+ GetDistillerViewUrlFromEntryId("abc-def").spec()),
view_request_delegate.get());
+ // Specify a non-distilled URL.
+ CreateViewRequest(GURL("https://example.com"), view_request_delegate.get());
+ // Specify an empty URL.
+ CreateViewRequest(GURL(), view_request_delegate.get());
}
DistilledPagePrefs* TestDomDistillerService::GetDistilledPagePrefs() {
diff --git a/chromium/components/download/internal/common/download_create_info.cc b/chromium/components/download/internal/common/download_create_info.cc
index b875d995273..20881b0be7b 100644
--- a/chromium/components/download/internal/common/download_create_info.cc
+++ b/chromium/components/download/internal/common/download_create_info.cc
@@ -31,7 +31,8 @@ DownloadCreateInfo::DownloadCreateInfo(
accept_range(RangeRequestSupportType::kNoSupport),
connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
method("GET"),
- ukm_source_id(ukm::kInvalidSourceId) {}
+ ukm_source_id(ukm::kInvalidSourceId),
+ is_content_initiated(false) {}
DownloadCreateInfo::DownloadCreateInfo()
: DownloadCreateInfo(base::Time(), base::WrapUnique(new DownloadSaveInfo)) {
diff --git a/chromium/components/download/internal/common/resource_downloader.cc b/chromium/components/download/internal/common/resource_downloader.cc
index aaeef1a691f..15de44ecd42 100644
--- a/chromium/components/download/internal/common/resource_downloader.cc
+++ b/chromium/components/download/internal/common/resource_downloader.cc
@@ -139,7 +139,8 @@ ResourceDownloader::ResourceDownloader(
tab_referrer_url_(tab_referrer_url),
delegate_task_runner_(task_runner),
url_loader_factory_getter_(std::move(url_loader_factory_getter)),
- url_security_policy_(url_security_policy) {
+ url_security_policy_(url_security_policy),
+ is_content_initiated_(false) {
RequestWakeLock(connector.get());
}
@@ -152,6 +153,7 @@ void ResourceDownloader::Start(
callback_ = download_url_parameters->callback();
upload_callback_ = download_url_parameters->upload_callback();
guid_ = download_url_parameters->guid();
+ is_content_initiated_ = download_url_parameters->content_initiated();
// Set up the URLLoaderClient.
url_loader_client_ = std::make_unique<DownloadResponseHandler>(
@@ -235,6 +237,7 @@ void ResourceDownloader::OnResponseStarted(
download_create_info->render_process_id = render_process_id_;
download_create_info->render_frame_id = render_frame_id_;
download_create_info->has_user_gesture = resource_request_->has_user_gesture;
+ download_create_info->is_content_initiated = is_content_initiated_;
delegate_task_runner_->PostTask(
FROM_HERE,
diff --git a/chromium/components/download/internal/common/resource_downloader.h b/chromium/components/download/internal/common/resource_downloader.h
index ed355ee35be..230269b856d 100644
--- a/chromium/components/download/internal/common/resource_downloader.h
+++ b/chromium/components/download/internal/common/resource_downloader.h
@@ -169,6 +169,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
// Used to check if the URL is safe to request.
URLSecurityPolicy url_security_policy_;
+ // Whether download is initated by the content on the page.
+ bool is_content_initiated_;
+
// Used to keep the system from sleeping while a download is ongoing. If the
// system enters power saving mode while a download is alive, it can cause
// download to be interrupted.
diff --git a/chromium/components/download/public/common/download_create_info.h b/chromium/components/download/public/common/download_create_info.h
index 0e97e309a85..84553dc1b97 100644
--- a/chromium/components/download/public/common/download_create_info.h
+++ b/chromium/components/download/public/common/download_create_info.h
@@ -178,6 +178,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo {
// Source of the download, used in metrics.
DownloadSource download_source = DownloadSource::UNKNOWN;
+ // Whether download is initated by the content on the page.
+ bool is_content_initiated;
+
private:
DISALLOW_COPY_AND_ASSIGN(DownloadCreateInfo);
};
diff --git a/chromium/components/exo/client_controlled_shell_surface.cc b/chromium/components/exo/client_controlled_shell_surface.cc
index 1ef2e94d6dd..77a07221861 100644
--- a/chromium/components/exo/client_controlled_shell_surface.cc
+++ b/chromium/components/exo/client_controlled_shell_surface.cc
@@ -811,6 +811,8 @@ void ClientControlledShellSurface::SetWidgetBounds(const gfx::Rect& bounds) {
display::Display display;
if (screen->GetDisplayWithDisplayId(display_id_, &display)) {
bool is_display_stale = display_id_ != current_display.id();
+ LOG(ERROR) << "DisplayId:" << display_id_
+ << ", current:" << current_display.id();
// Preserve widget bounds until client acknowledges display move.
if (preserve_widget_bounds_ && is_display_stale)
@@ -844,6 +846,7 @@ void ClientControlledShellSurface::SetWidgetBounds(const gfx::Rect& bounds) {
bool set_bounds_locally =
GetWindowState()->is_dragged() && !is_display_move_pending;
+ LOG(ERROR) << "Updating Locally";
if (set_bounds_locally || client_controlled_state_->set_bounds_locally()) {
// Convert from screen to display coordinates.
@@ -858,6 +861,7 @@ void ClientControlledShellSurface::SetWidgetBounds(const gfx::Rect& bounds) {
UpdateSurfaceBounds();
return;
}
+ LOG(ERROR) << "Updating Remotely";
{
ScopedSetBoundsLocally scoped_set_bounds(this);
@@ -865,6 +869,8 @@ void ClientControlledShellSurface::SetWidgetBounds(const gfx::Rect& bounds) {
}
if (bounds != adjusted_bounds || is_display_move_pending) {
+ LOG(ERROR) << "Sending Bounds:" << bounds.ToString()
+ << ", adjusted=" << adjusted_bounds.ToString();
// Notify client that bounds were adjusted or window moved across displays.
auto state_type = GetWindowState()->GetStateType();
OnBoundsChangeEvent(state_type, state_type, target_display.id(),
@@ -937,13 +943,13 @@ bool ClientControlledShellSurface::OnPreWidgetCommit() {
}
ash::WindowState* window_state = GetWindowState();
- if (window_state->GetStateType() == pending_window_state_) {
+ state_changed_ = window_state->GetStateType() != pending_window_state_;
+ if (!state_changed_) {
// Animate PIP window movement unless it is being dragged.
if (window_state->IsPip() && !window_state->is_dragged()) {
client_controlled_state_->set_next_bounds_change_animation_type(
ash::ClientControlledState::kAnimationAnimated);
}
-
return true;
}
@@ -1043,9 +1049,11 @@ void ClientControlledShellSurface::UpdateFrame() {
bool enable_wide_frame = GetFrameView()->GetVisible() &&
window_state->IsMaximizedOrFullscreenOrPinned() &&
work_area.width() != geometry().width();
-
+ bool update_frame = state_changed_;
+ state_changed_ = false;
if (enable_wide_frame) {
if (!wide_frame_) {
+ update_frame = true;
wide_frame_ = std::make_unique<ash::WideFrameView>(widget_);
ash::ImmersiveFullscreenController::EnableForWidget(widget_, false);
wide_frame_->Init(immersive_fullscreen_controller_.get());
@@ -1063,6 +1071,7 @@ void ClientControlledShellSurface::UpdateFrame() {
}
} else {
if (wide_frame_) {
+ update_frame = true;
ash::ImmersiveFullscreenController::EnableForWidget(widget_, false);
wide_frame_.reset();
GetFrameView()->InitImmersiveFullscreenControllerForView(
@@ -1077,7 +1086,8 @@ void ClientControlledShellSurface::UpdateFrame() {
// The autohide should be applied when the window state is in
// maximzied, fullscreen or pinned. Update the auto hide state
// inside commit.
- UpdateAutoHideFrame();
+ if (update_frame)
+ UpdateAutoHideFrame();
}
void ClientControlledShellSurface::UpdateCaptionButtonModel() {
diff --git a/chromium/components/exo/client_controlled_shell_surface.h b/chromium/components/exo/client_controlled_shell_surface.h
index 5600be9419a..3fccb24a28c 100644
--- a/chromium/components/exo/client_controlled_shell_surface.h
+++ b/chromium/components/exo/client_controlled_shell_surface.h
@@ -335,6 +335,9 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
bool ignore_bounds_change_request_ = false;
+ // True if the window state has changed during the commit.
+ bool state_changed_ = false;
+
DISALLOW_COPY_AND_ASSIGN(ClientControlledShellSurface);
};
diff --git a/chromium/components/exo/client_controlled_shell_surface_unittest.cc b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
index 9d18b869617..4749a904dce 100644
--- a/chromium/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
@@ -477,6 +477,8 @@ TEST_F(ClientControlledShellSurfaceTest, ShadowStartMaximized) {
}
TEST_F(ClientControlledShellSurfaceTest, Frame) {
+ UpdateDisplay("800x600");
+
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
@@ -484,7 +486,7 @@ TEST_F(ClientControlledShellSurfaceTest, Frame) {
std::unique_ptr<Surface> surface(new Surface);
gfx::Rect client_bounds(20, 50, 300, 200);
- gfx::Rect fullscreen_bounds(0, 0, 800, 500);
+ gfx::Rect fullscreen_bounds(0, 0, 800, 600);
// The window bounds is the client bounds + frame size.
gfx::Rect normal_window_bounds(20, 18, 300, 232);
@@ -508,13 +510,13 @@ TEST_F(ClientControlledShellSurfaceTest, Frame) {
// Maximized
shell_surface->SetMaximized();
- shell_surface->SetGeometry(gfx::Rect(0, 0, 800, 468));
+ shell_surface->SetGeometry(gfx::Rect(0, 0, 800, 568));
surface->Commit();
EXPECT_TRUE(frame_view->GetVisible());
EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
EXPECT_EQ(
- gfx::Size(800, 468),
+ gfx::Size(800, 568),
frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds).size());
// AutoHide
@@ -534,6 +536,15 @@ TEST_F(ClientControlledShellSurfaceTest, Frame) {
EXPECT_EQ(fullscreen_bounds,
frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds));
+ // Updating frame, then window state should still update the frame state.
+ surface->SetFrame(SurfaceFrameType::NORMAL);
+ surface->Commit();
+ EXPECT_FALSE(frame_view->GetHeaderView()->GetVisible());
+
+ shell_surface->SetMaximized();
+ surface->Commit();
+ EXPECT_TRUE(frame_view->GetHeaderView()->GetVisible());
+
// Restore to normal state.
shell_surface->SetRestored();
shell_surface->SetGeometry(client_bounds);
diff --git a/chromium/components/previews/core/previews_experiments.cc b/chromium/components/previews/core/previews_experiments.cc
index 57c76ad649d..82e1272397e 100644
--- a/chromium/components/previews/core/previews_experiments.cc
+++ b/chromium/components/previews/core/previews_experiments.cc
@@ -382,6 +382,15 @@ bool ShouldExcludeMediaSuffix(const GURL& url) {
return false;
}
+bool DetectDeferRedirectLoopsUsingCache() {
+ if (!IsDeferAllScriptPreviewsEnabled())
+ return false;
+
+ return GetFieldTrialParamByFeatureAsBool(features::kDeferAllScriptPreviews,
+ "detect_redirect_loop_using_cache",
+ true);
+}
+
} // namespace params
std::string GetStringNameForType(PreviewsType type) {
diff --git a/chromium/components/previews/core/previews_experiments.h b/chromium/components/previews/core/previews_experiments.h
index 44b6659d02c..464d011feed 100644
--- a/chromium/components/previews/core/previews_experiments.h
+++ b/chromium/components/previews/core/previews_experiments.h
@@ -206,6 +206,10 @@ bool ShouldOverrideNavigationCoinFlipToAllowed();
// Returns true if the given url matches an excluded media suffix.
bool ShouldExcludeMediaSuffix(const GURL& url);
+// Returns true if the logic to detect redirect loops with defer all script
+// preview using a cache is enabled.
+bool DetectDeferRedirectLoopsUsingCache();
+
} // namespace params
} // namespace previews
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.cc b/chromium/components/printing/renderer/print_render_frame_helper.cc
index ef580254bd8..84c11dcdb4f 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper.cc
@@ -710,6 +710,8 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
options->SetDouble("height", page_size.height);
options->SetDouble("topMargin", page_layout.margin_top);
options->SetDouble("bottomMargin", page_layout.margin_bottom);
+ options->SetDouble("leftMargin", page_layout.margin_left);
+ options->SetDouble("rightMargin", page_layout.margin_right);
options->SetInteger("pageNumber", page_number);
options->SetInteger("totalPages", total_pages);
options->SetString("url", params.url);
diff --git a/chromium/components/printing/resources/print_header_footer_template_page.html b/chromium/components/printing/resources/print_header_footer_template_page.html
index 5fee7a64f36..3c79b51abf6 100644
--- a/chromium/components/printing/resources/print_header_footer_template_page.html
+++ b/chromium/components/printing/resources/print_header_footer_template_page.html
@@ -61,6 +61,24 @@
</style>
<script>
+function getComputedStyleAsFloat(style, value) {
+ return parseFloat(style.getPropertyValue(value).slice(0, -2));
+}
+
+function elementIntersects(element, topPos, bottomPos, leftPos, rightPos) {
+ const rect = element.getBoundingClientRect();
+ const style = window.getComputedStyle(element);
+
+ // Only consider the size of |element|, so remove the padding from |rect|.
+ // The padding is used for positioning.
+ rect.top += getComputedStyleAsFloat(style, 'padding-top');
+ rect.bottom -= getComputedStyleAsFloat(style, 'padding-bottom');
+ rect.left += getComputedStyleAsFloat(style, 'padding-left');
+ rect.right -= getComputedStyleAsFloat(style, 'padding-right');
+ return leftPos < rect.right && rightPos > rect.left && topPos < rect.bottom &&
+ bottomPos > rect.top;
+}
+
function setupHeaderFooterTemplate(options) {
const body = document.querySelector('body');
const header = document.querySelector('#header');
@@ -71,6 +89,11 @@ function setupHeaderFooterTemplate(options) {
header.style.height = `${options.topMargin}px`;
footer.style.height = `${options.bottomMargin}px`;
+ const topMargin = options.topMargin;
+ const bottomMargin = options.height - options.bottomMargin;
+ const leftMargin = options.leftMargin;
+ const rightMargin = options.width - options.rightMargin;
+
header.innerHTML = options['headerTemplate'] || `
<div class='date text left'></div>
<div class='title text center'></div>`;
@@ -86,6 +109,11 @@ function setupHeaderFooterTemplate(options) {
element.textContent = options[cssClass];
if (options.isRtl)
element.dir = 'rtl';
+
+ if (elementIntersects(element, topMargin, bottomMargin, leftMargin,
+ rightMargin)) {
+ element.style.visibility = 'hidden';
+ }
}
}
}
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
index b93ac74d222..6919f8af1f2 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
@@ -77,7 +77,8 @@ PasswordProtectionRequest::PasswordProtectionRequest(
bool password_field_exists,
PasswordProtectionService* pps,
int request_timeout_in_ms)
- : web_contents_(web_contents),
+ : content::WebContentsObserver(web_contents),
+ web_contents_(web_contents),
main_frame_url_(main_frame_url),
password_form_action_(password_form_action),
password_form_frame_url_(password_form_frame_url),
@@ -509,4 +510,8 @@ void PasswordProtectionRequest::HandleDeferredNavigations() {
throttles_.clear();
}
+void PasswordProtectionRequest::WebContentsDestroyed() {
+ Cancel(/*timed_out=*/false);
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.h b/chromium/components/safe_browsing/password_protection/password_protection_request.h
index 2dc4b4a0cba..e823d874532 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_request.h
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.h
@@ -17,6 +17,7 @@
#include "components/safe_browsing/password_protection/password_protection_service.h"
#include "components/safe_browsing/proto/csd.pb.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents_observer.h"
#include "third_party/skia/include/core/SkBitmap.h"
class GURL;
@@ -50,10 +51,10 @@ using password_manager::metrics_util::PasswordType;
// (8) | UI | On receiving response, handle response and finish.
// | | On request timeout, cancel request.
// | | On deletion of |password_protection_service_|, cancel request.
-class PasswordProtectionRequest
- : public base::RefCountedThreadSafe<
- PasswordProtectionRequest,
- content::BrowserThread::DeleteOnUIThread> {
+class PasswordProtectionRequest : public base::RefCountedThreadSafe<
+ PasswordProtectionRequest,
+ content::BrowserThread::DeleteOnUIThread>,
+ public content::WebContentsObserver {
public:
PasswordProtectionRequest(content::WebContents* web_contents,
const GURL& main_frame_url,
@@ -116,6 +117,9 @@ class PasswordProtectionRequest
// Cancels navigation if there is modal warning showing, resumes it otherwise.
void HandleDeferredNavigations();
+ // WebContentsObserver implementation
+ void WebContentsDestroyed() override;
+
protected:
friend class base::RefCountedThreadSafe<PasswordProtectionRequest>;
@@ -125,7 +129,7 @@ class PasswordProtectionRequest
friend class base::DeleteHelper<PasswordProtectionRequest>;
friend class PasswordProtectionServiceTest;
friend class ChromePasswordProtectionServiceTest;
- virtual ~PasswordProtectionRequest();
+ ~PasswordProtectionRequest() override;
// Start checking the whitelist.
void CheckWhitelist();
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 2ee6343bc35..2c6e54609c1 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -1207,6 +1207,14 @@ TEST_P(PasswordProtectionServiceTest, TestRequestCancelNotOnTimeout) {
EXPECT_EQ(0U, GetNumberOfNavigationThrottles());
}
+TEST_P(PasswordProtectionServiceTest, TestWebContentsDestroyed) {
+ content::WebContents* web_contents = GetWebContents();
+ InitializeAndStartPasswordOnFocusRequest(
+ false /* match whitelist */, 10000 /* timeout in ms */, web_contents);
+ delete web_contents;
+ base::RunLoop().RunUntilIdle();
+}
+
INSTANTIATE_TEST_SUITE_P(Regular,
PasswordProtectionServiceTest,
::testing::Values(false));
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index 169d254bffa..f77532e83c5 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -190,7 +190,7 @@
<translation id="187918866476621466">Buka halaman awal</translation>
<translation id="1883255238294161206">Ciutkan daftar</translation>
<translation id="1898423065542865115">Pemfilteran</translation>
-<translation id="1914326953223720820">Layanan Unzip</translation>
+<translation id="1914326953223720820">Layanan Ekstraksi File</translation>
<translation id="1916770123977586577">Untuk menerapkan setelan yang telah diupdate pada situs ini, muat ulang halaman ini</translation>
<translation id="1919345977826869612">Iklan</translation>
<translation id="1919367280705858090">Mendapatkan bantuan terkait pesan error tertentu</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index 818edbd17a6..d16e3a8d4b7 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -388,7 +388,7 @@
<translation id="2969319727213777354">Klokken må være riktig stilt før du kan opprette sikre tilkoblinger. Grunnen til dette er at sertifikatene nettsteder identifiserer seg med, bare er gyldige i visse tidsperioder. Ettersom klokken på enheten din er feil, kan ikke Google Chrome bekrefte disse sertifikatene.</translation>
<translation id="2972581237482394796">Gjø&amp;r om</translation>
<translation id="2977665033722899841"><ph name="ROW_NAME" />, for øyeblikket valgt. <ph name="ROW_CONTENT" /></translation>
-<translation id="2982481275546140226">Fjern data</translation>
+<translation id="2982481275546140226">Slett data</translation>
<translation id="2985306909656435243">Hvis du slår på dette alternativet, lagrer Chromium en kopi av kortet ditt på denne enheten, slik at det går raskere å fylle ut skjemaer.</translation>
<translation id="2985398929374701810">Angi en gyldig adresse</translation>
<translation id="2986368408720340940">Denne hentemetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index bbdefb4ef4d..225a4344334 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -1110,7 +1110,7 @@
<translation id="7050187094878475250"><ph name="DOMAIN" /> alan adına erişmeyi denediniz, ancak sunucu, geçerlilik dönemi güvenilir olmayacak kadar uzun olan bir sertifika sundu.</translation>
<translation id="705310974202322020">{NUM_CARDS,plural, =1{Bu kart şu anda kaydedilemiyor}other{Bu kartlar şu anda kaydedilemiyor}}</translation>
<translation id="7053983685419859001">Engelle</translation>
-<translation id="7062635574500127092">Turkuvaz</translation>
+<translation id="7062635574500127092">Turkuaz</translation>
<translation id="7064851114919012435">İletişim bilgileri</translation>
<translation id="7075452647191940183">İstek çok büyük</translation>
<translation id="7079718277001814089">Bu site kötü amaçlı yazılım içeriyor</translation>
diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc
index 5abe50de8a6..c35a39c14b7 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator.cc
@@ -388,9 +388,11 @@ std::string VariationsFieldTrialCreator::GetShortHardwareClass() {
board.resize(index);
return base::ToUpperASCII(board);
+#elif defined(OS_ANDROID)
+ return base::SysInfo::HardwareModelName();
#else
return std::string();
-#endif // OS_CHROMEOS
+#endif
}
bool VariationsFieldTrialCreator::LoadSeed(VariationsSeed* seed,
diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h
index 5159583fc77..40456a0c3c1 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.h
+++ b/chromium/components/variations/service/variations_field_trial_creator.h
@@ -123,8 +123,8 @@ class VariationsFieldTrialCreator {
const std::string& application_locale() const { return application_locale_; }
// Returns the short hardware class value used to evaluate variations hardware
- // class filters. Only implemented on CrOS - returns empty string on other
- // platforms.
+ // class filters. Only implemented on CrOS and Android - returns empty string
+ // on other platforms.
static std::string GetShortHardwareClass();
private:
diff --git a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
index 8da72309ea6..4925a3b0fd4 100644
--- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -519,6 +519,24 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) {
EXPECT_EQ(kTestSeedExperimentName,
base::FieldTrialList::FindFullName(kTestSeedStudyName));
}
+
+// Tests that the hardware class is set on Android.
+TEST_F(FieldTrialCreatorTest, ClientFilterableState_HardwareClass) {
+ testing::NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
+ .WillByDefault(Return(false));
+
+ TestVariationsServiceClient variations_service_client;
+ TestVariationsFieldTrialCreator field_trial_creator(
+ &prefs_, &variations_service_client, &safe_seed_manager);
+
+ const base::Version& current_version = version_info::GetVersion();
+ EXPECT_TRUE(current_version.IsValid());
+
+ std::unique_ptr<ClientFilterableState> client_filterable_state =
+ field_trial_creator.GetClientFilterableStateForVersion(current_version);
+ EXPECT_NE(client_filterable_state->hardware_class, std::string());
+}
#endif // OS_ANDROID
} // namespace variations
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index abab71621e5..b7a29046cac 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -22,7 +22,7 @@ const base::Feature kEnableSurfaceSynchronization{
// (OOP-D).
// TODO(dnicoara): Look at enabling Chromecast support when ChromeOS support is
// ready.
-#if defined(IS_CHROMECAST)
+#if defined(IS_CHROMECAST) || defined(OS_CHROMEOS)
const base::Feature kVizDisplayCompositor{"VizDisplayCompositor",
base::FEATURE_DISABLED_BY_DEFAULT};
#else
diff --git a/chromium/components/viz/common/quads/shared_quad_state.h b/chromium/components/viz/common/quads/shared_quad_state.h
index b64893faef9..647fd47047e 100644
--- a/chromium/components/viz/common/quads/shared_quad_state.h
+++ b/chromium/components/viz/common/quads/shared_quad_state.h
@@ -66,9 +66,9 @@ class VIZ_COMMON_EXPORT SharedQuadState {
float opacity;
SkBlendMode blend_mode;
int sorting_context_id;
- // Used by SurfaceAggregator to decide whether to merge quads for a surface
- // into their target render pass. It is a performance optimization by avoiding
- // render passes as much as possible.
+ // An internal flag used only by the SurfaceAggregator to decide whether to
+ // merge quads for a surface into their target render pass. It is a
+ // performance optimization by avoiding render passes as much as possible.
bool is_fast_rounded_corner = false;
// This is for underlay optimization and used only in the SurfaceAggregator
// and the OverlayProcessor. This damage rect contains union of damage from
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn
index aff5de7521d..32fa9e47d47 100644
--- a/chromium/content/browser/BUILD.gn
+++ b/chromium/content/browser/BUILD.gn
@@ -184,6 +184,7 @@ jumbo_source_set("browser") {
"//services/tracing/public/cpp",
"//services/video_capture:lib",
"//services/video_capture/public/cpp",
+ "//services/video_capture/public/cpp:manifest",
"//services/video_capture/public/mojom:constants",
"//services/video_capture/public/uma",
"//services/viz/privileged/interfaces",
@@ -1892,7 +1893,6 @@ jumbo_source_set("browser") {
"url_loader_factory_getter.h",
"utility_process_host.cc",
"utility_process_host.h",
- "video_capture_service.cc",
"wake_lock/wake_lock_context_host.cc",
"wake_lock/wake_lock_context_host.h",
"wake_lock/wake_lock_service_impl.cc",
diff --git a/chromium/content/browser/accessibility/browser_accessibility.h b/chromium/content/browser/accessibility/browser_accessibility.h
index 7016c3f3e7d..a1d4afc6aa1 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.h
+++ b/chromium/content/browser/accessibility/browser_accessibility.h
@@ -91,8 +91,6 @@ class CONTENT_EXPORT BrowserAccessibility : public ui::AXPlatformNodeDelegate {
// its data changes.
virtual void OnDataChanged() {}
- virtual void OnSubtreeWillBeDeleted() {}
-
// Called when the location changed.
virtual void OnLocationChanged() {}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
index a2927a31d6b..4889a5c2f5d 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -38,6 +38,8 @@
using BrowserAccessibilityPositionInstance =
content::BrowserAccessibilityPosition::AXPositionInstance;
+using SerializedPosition =
+ content::BrowserAccessibilityPosition::SerializedPosition;
using AXPlatformRange =
ui::AXRange<BrowserAccessibilityPositionInstance::element_type>;
using AXTextMarkerRangeRef = CFTypeRef;
@@ -54,6 +56,10 @@ using content::OneShotAccessibilityTreeSearch;
using ui::AXNodeData;
using ui::AXTreeIDRegistry;
+static_assert(
+ std::is_trivially_copyable<SerializedPosition>::value,
+ "SerializedPosition must be POD because it's used to back an AXTextMarker");
+
namespace {
// Private WebKit accessibility attributes.
@@ -172,21 +178,24 @@ AXTextMarkerRef AXTextMarkerRangeCopyEndMarker(
// AXTextMarkerCreate copies from data buffer given to it.
id CreateTextMarker(BrowserAccessibilityPositionInstance position) {
+ SerializedPosition serialized = position->Serialize();
AXTextMarkerRef text_marker = AXTextMarkerCreate(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(position.get()),
- sizeof(BrowserAccessibilityPosition));
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&serialized),
+ sizeof(SerializedPosition));
return [static_cast<id>(text_marker) autorelease];
}
// |range| is destructed at the end of this method. |anchor| and |focus| are
// copied into the individual text markers.
id CreateTextMarkerRange(const AXPlatformRange range) {
+ SerializedPosition serialized_anchor = range.anchor()->Serialize();
+ SerializedPosition serialized_focus = range.focus()->Serialize();
base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(AXTextMarkerCreate(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.anchor()),
- sizeof(BrowserAccessibilityPosition)));
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&serialized_anchor),
+ sizeof(SerializedPosition)));
base::ScopedCFTypeRef<AXTextMarkerRef> end_marker(AXTextMarkerCreate(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.focus()),
- sizeof(BrowserAccessibilityPosition)));
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&serialized_focus),
+ sizeof(SerializedPosition)));
AXTextMarkerRangeRef marker_range =
AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker);
return [static_cast<id>(marker_range) autorelease];
@@ -195,22 +204,15 @@ id CreateTextMarkerRange(const AXPlatformRange range) {
BrowserAccessibilityPositionInstance CreatePositionFromTextMarker(
AXTextMarkerRef text_marker) {
DCHECK(text_marker);
- if (AXTextMarkerGetLength(text_marker) !=
- sizeof(BrowserAccessibilityPosition))
+ if (AXTextMarkerGetLength(text_marker) != sizeof(SerializedPosition))
return BrowserAccessibilityPosition::CreateNullPosition();
+
const UInt8* source_buffer = AXTextMarkerGetBytePtr(text_marker);
if (!source_buffer)
return BrowserAccessibilityPosition::CreateNullPosition();
- UInt8* destination_buffer = new UInt8[sizeof(BrowserAccessibilityPosition)];
- std::memcpy(destination_buffer, source_buffer,
- sizeof(BrowserAccessibilityPosition));
- BrowserAccessibilityPosition::AXPositionInstance position(
- reinterpret_cast<
- BrowserAccessibilityPosition::AXPositionInstance::pointer>(
- destination_buffer));
- if (!position)
- return BrowserAccessibilityPosition::CreateNullPosition();
- return position;
+
+ return BrowserAccessibilityPosition::Unserialize(
+ *reinterpret_cast<const SerializedPosition*>(source_buffer));
}
AXPlatformRange CreateRangeFromTextMarkerRange(
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.cc b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
index 1e07bc2e39c..7ffe23034a6 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1213,11 +1213,7 @@ void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXTree* tree,
}
void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree,
- ui::AXNode* node) {
- DCHECK(node);
- if (BrowserAccessibility* wrapper = GetFromAXNode(node))
- wrapper->OnSubtreeWillBeDeleted();
-}
+ ui::AXNode* node) {}
void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
ui::AXNode* node) {
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index ef4b81e43f4..428610edbec 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -234,20 +234,20 @@ static void EstablishEmbeddedRelationship(AtkObject* document_object) {
document_platform_node->SetEmbeddingWindow(window);
}
-void BrowserAccessibilityManagerAuraLinux::OnStateChanged(
+void BrowserAccessibilityManagerAuraLinux::OnNodeDataWillChange(
ui::AXTree* tree,
- ui::AXNode* node,
- ax::mojom::State state,
- bool new_value) {
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) {
DCHECK_EQ(ax_tree(), tree);
// Since AuraLinux needs to send the children-changed::remove event with the
// index in parent, the event must be fired before the node becomes ignored.
// children-changed:add is handled with the generated Event::IGNORED_CHANGED.
- if (state == ax::mojom::State::kIgnored && new_value) {
- DCHECK(!node->data().HasState(ax::mojom::State::kIgnored));
- BrowserAccessibility* obj = GetFromAXNode(node);
+ if (!old_node_data.HasState(ax::mojom::State::kIgnored) &&
+ new_node_data.HasState(ax::mojom::State::kIgnored)) {
+ BrowserAccessibility* obj = GetFromID(old_node_data.id);
if (obj && obj->IsNative() && obj->GetParent()) {
+ DCHECK(!obj->HasState(ax::mojom::State::kIgnored));
g_signal_emit_by_name(obj->GetParent(), "children-changed::remove",
obj->GetIndexInParent(),
obj->GetNativeViewAccessible());
@@ -258,7 +258,6 @@ void BrowserAccessibilityManagerAuraLinux::OnStateChanged(
void BrowserAccessibilityManagerAuraLinux::OnSubtreeWillBeDeleted(
ui::AXTree* tree,
ui::AXNode* node) {
- BrowserAccessibilityManager::OnSubtreeWillBeDeleted(tree, node);
// Sending events on load/destruction would create a lot of spam, avoid that.
if (!GetTreeData().loaded)
return;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
index 4f002468799..3826fd5334c 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
@@ -42,10 +42,9 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAuraLinux
protected:
// AXTreeObserver methods.
- void OnStateChanged(ui::AXTree* tree,
- ui::AXNode* node,
- ax::mojom::State state,
- bool new_value) override;
+ void OnNodeDataWillChange(ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(
ui::AXTree* tree,
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
index d444d88d857..7bbfed5a507 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -75,19 +75,6 @@ HWND BrowserAccessibilityManagerWin::GetParentHWND() {
return delegate->AccessibilityGetAcceleratedWidget();
}
-void BrowserAccessibilityManagerWin::OnSubtreeWillBeDeleted(ui::AXTree* tree,
- ui::AXNode* node) {
- BrowserAccessibilityManager::OnSubtreeWillBeDeleted(tree, node);
-
- BrowserAccessibility* obj = GetFromAXNode(node);
- FireWinAccessibilityEvent(EVENT_OBJECT_HIDE, obj);
- FireUiaStructureChangedEvent(StructureChangeType_ChildRemoved, obj);
- if (obj && obj->GetRole() == ax::mojom::Role::kMenu) {
- FireWinAccessibilityEvent(EVENT_SYSTEM_MENUPOPUPEND, obj);
- FireUiaAccessibilityEvent(UIA_MenuClosedEventId, obj);
- }
-}
-
void BrowserAccessibilityManagerWin::UserIsReloading() {
if (GetRoot())
FireWinAccessibilityEvent(IA2_EVENT_DOCUMENT_RELOAD, GetRoot());
@@ -576,6 +563,20 @@ gfx::Rect BrowserAccessibilityManagerWin::GetViewBounds() {
return gfx::Rect();
}
+void BrowserAccessibilityManagerWin::OnSubtreeWillBeDeleted(ui::AXTree* tree,
+ ui::AXNode* node) {
+ BrowserAccessibility* obj = GetFromAXNode(node);
+ DCHECK(obj);
+ if (obj) {
+ FireWinAccessibilityEvent(EVENT_OBJECT_HIDE, obj);
+ FireUiaStructureChangedEvent(StructureChangeType_ChildRemoved, obj);
+ if (obj->GetRole() == ax::mojom::Role::kMenu) {
+ FireWinAccessibilityEvent(EVENT_SYSTEM_MENUPOPUPEND, obj);
+ FireUiaAccessibilityEvent(UIA_MenuClosedEventId, obj);
+ }
+ }
+}
+
void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
index bb2457badef..9b8a9387207 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -43,9 +43,6 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// Get the closest containing HWND.
HWND GetParentHWND();
- // AXEventGenerator methods
- void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
-
// BrowserAccessibilityManager methods
void UserIsReloading() override;
BrowserAccessibility* GetFocus() const override;
@@ -82,6 +79,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
protected:
// AXTreeObserver methods.
+ void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
diff --git a/chromium/content/browser/accessibility/browser_accessibility_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_unittest.cc
index bab809c51d1..eff14f455d4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -210,63 +210,63 @@ TEST_F(BrowserAccessibilityTest, TestGetDescendants) {
TEST_F(BrowserAccessibilityTest, PlatformChildIterator) {
// (i) => node is ignored
- // 0
+ // 1
// |__________
// | | |
- // 1(i) 2 3
+ // 2(i) 3 4
// |_______________________
// | | | |
- // 4 5 6(i) 7(i)
+ // 5 6 7(i) 8(i)
// | | |________
// | | | |
- // 8 9(i) 10(i) 11
+ // 9 10(i) 11(i) 12
// | |____
// | | |
- // 12(i) 13 14
+ // 13(i) 14 15
ui::AXTreeUpdate tree_update;
- tree_update.root_id = 0;
+ tree_update.root_id = 1;
tree_update.nodes.resize(15);
- tree_update.nodes[0].id = 0;
- tree_update.nodes[0].child_ids = {1, 2, 3};
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
- tree_update.nodes[1].id = 1;
- tree_update.nodes[1].child_ids = {4, 5, 6, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].child_ids = {5, 6, 7, 8};
tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[2].id = 2;
- tree_update.nodes[3].id = 3;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[3].id = 4;
- tree_update.nodes[4].id = 4;
- tree_update.nodes[4].child_ids = {8};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].child_ids = {9};
- tree_update.nodes[5].id = 5;
- tree_update.nodes[5].child_ids = {9};
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].child_ids = {10};
- tree_update.nodes[6].id = 6;
- tree_update.nodes[6].child_ids = {10, 11};
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].child_ids = {11, 12};
tree_update.nodes[6].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[7].id = 7;
+ tree_update.nodes[7].id = 8;
tree_update.nodes[7].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[8].id = 8;
+ tree_update.nodes[8].id = 9;
- tree_update.nodes[9].id = 9;
- tree_update.nodes[9].child_ids = {12};
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].child_ids = {13};
tree_update.nodes[9].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[10].id = 10;
- tree_update.nodes[10].child_ids = {13, 14};
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].child_ids = {14, 15};
tree_update.nodes[10].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[11].id = 11;
+ tree_update.nodes[11].id = 12;
- tree_update.nodes[12].id = 12;
+ tree_update.nodes[12].id = 13;
tree_update.nodes[12].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[13].id = 13;
+ tree_update.nodes[13].id = 14;
- tree_update.nodes[14].id = 14;
+ tree_update.nodes[14].id = 15;
std::unique_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
@@ -275,61 +275,61 @@ TEST_F(BrowserAccessibilityTest, PlatformChildIterator) {
BrowserAccessibility* root_obj = manager->GetRoot();
// Test traversal
- // PlatformChildren(root_obj) = {4, 5, 13, 14, 11, 2, 3}
+ // PlatformChildren(root_obj) = {5, 6, 14, 15, 12, 3, 4}
BrowserAccessibility::PlatformChildIterator platform_iterator =
root_obj->PlatformChildrenBegin();
- EXPECT_EQ(4, platform_iterator->GetId());
-
- ++platform_iterator;
EXPECT_EQ(5, platform_iterator->GetId());
++platform_iterator;
- EXPECT_EQ(13, platform_iterator->GetId());
+ EXPECT_EQ(6, platform_iterator->GetId());
++platform_iterator;
EXPECT_EQ(14, platform_iterator->GetId());
- --platform_iterator;
- EXPECT_EQ(13, platform_iterator->GetId());
+ ++platform_iterator;
+ EXPECT_EQ(15, platform_iterator->GetId());
--platform_iterator;
- EXPECT_EQ(5, platform_iterator->GetId());
+ EXPECT_EQ(14, platform_iterator->GetId());
- ++platform_iterator;
- EXPECT_EQ(13, platform_iterator->GetId());
+ --platform_iterator;
+ EXPECT_EQ(6, platform_iterator->GetId());
++platform_iterator;
EXPECT_EQ(14, platform_iterator->GetId());
++platform_iterator;
- EXPECT_EQ(11, platform_iterator->GetId());
+ EXPECT_EQ(15, platform_iterator->GetId());
++platform_iterator;
- EXPECT_EQ(2, platform_iterator->GetId());
+ EXPECT_EQ(12, platform_iterator->GetId());
++platform_iterator;
EXPECT_EQ(3, platform_iterator->GetId());
++platform_iterator;
+ EXPECT_EQ(4, platform_iterator->GetId());
+
+ ++platform_iterator;
EXPECT_EQ(root_obj->PlatformChildrenEnd(), platform_iterator);
// test empty list
// PlatformChildren(2) = {}
- BrowserAccessibility* node2 = manager->GetFromID(2);
+ BrowserAccessibility* node2 = manager->GetFromID(3);
platform_iterator = node2->PlatformChildrenBegin();
EXPECT_EQ(node2->PlatformChildrenEnd(), platform_iterator);
// empty list from ignored node
// PlatformChildren(7) = {}
- BrowserAccessibility* node7 = manager->GetFromID(7);
+ BrowserAccessibility* node7 = manager->GetFromID(8);
platform_iterator = node7->PlatformChildrenBegin();
EXPECT_EQ(node7->PlatformChildrenEnd(), platform_iterator);
// non-empty list from ignored node
- // PlatformChildren(10) = {13, 14}
- BrowserAccessibility* node10 = manager->GetFromID(10);
+ // PlatformChildren(10) = {14, 15}
+ BrowserAccessibility* node10 = manager->GetFromID(11);
platform_iterator = node10->PlatformChildrenBegin();
- EXPECT_EQ(13, platform_iterator->GetId());
+ EXPECT_EQ(14, platform_iterator->GetId());
// Two UnignoredChildIterators from the same parent at the same position
// should be equivalent, even in end position.
diff --git a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index db623358e04..3ed0354ecca 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -2043,6 +2043,10 @@ IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
RunHtmlTest(FILE_PATH_LITERAL("button-with-listbox-popup.html"));
}
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DeleteSelectionCrash) {
+ RunHtmlTest(FILE_PATH_LITERAL("delete-selection-crash.html"));
+}
+
//
// Regression tests. These don't test a specific web platform feature,
// they test a specific web page that crashed or had some bad behavior
diff --git a/chromium/content/browser/builtin_service_manifests.cc b/chromium/content/browser/builtin_service_manifests.cc
index 5fb43e95ba5..07e202925d5 100644
--- a/chromium/content/browser/builtin_service_manifests.cc
+++ b/chromium/content/browser/builtin_service_manifests.cc
@@ -30,6 +30,7 @@
#include "services/service_manager/public/cpp/manifest_builder.h"
#include "services/shape_detection/public/cpp/manifest.h"
#include "services/tracing/manifest.h"
+#include "services/video_capture/public/cpp/manifest.h"
#if defined(OS_LINUX)
#include "components/services/font/public/cpp/manifest.h" // nogncheck
@@ -90,6 +91,12 @@ const std::vector<service_manager::Manifest>& GetBuiltinServiceManifests() {
resource_coordinator::GetManifest(),
shape_detection::GetManifest(),
tracing::GetManifest(),
+ video_capture::GetManifest(
+ features::IsVideoCaptureServiceEnabledForOutOfProcess()
+ ? service_manager::Manifest::ExecutionMode::
+ kOutOfProcessBuiltin
+ : service_manager::Manifest::ExecutionMode::
+ kInProcessBuiltin),
#if defined(OS_LINUX)
font_service::GetManifest(),
#endif
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index ac10788e493..50ca50ae5c6 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -623,6 +623,38 @@ class ErrorStreamCountingObserver : download::DownloadItem::Observer {
base::Closure completion_closure_;
};
+// Class to wait for a WebContents to kick off a specified number of
+// navigations.
+class NavigationStartObserver : public WebContentsObserver {
+ public:
+ explicit NavigationStartObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+ ~NavigationStartObserver() override {}
+
+ void WaitForFinished(int navigation_count) {
+ if (start_count_ >= navigation_count)
+ return;
+ navigation_count_ = navigation_count;
+ base::RunLoop run_loop;
+ completion_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ private:
+ // WebContentsObserver implementations.
+ void DidStartNavigation(NavigationHandle* navigation_handle) override {
+ start_count_++;
+ if (start_count_ >= navigation_count_ && !completion_closure_.is_null()) {
+ std::move(completion_closure_).Run();
+ }
+ }
+
+ int navigation_count_ = 0;
+ int start_count_ = 0;
+ base::Closure completion_closure_;
+ DISALLOW_COPY_AND_ASSIGN(NavigationStartObserver);
+};
+
bool IsDownloadInState(download::DownloadItem::DownloadState state,
download::DownloadItem* item) {
return item->GetState() == state;
@@ -3356,8 +3388,54 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
std::vector<download::DownloadItem*> downloads;
DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
ASSERT_EQ(0u, downloads.size());
+ ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+ ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
+}
+
+// Tests that if a renderer initiated download triggers cross origin in the
+// redirect chain, the visible URL of the current tab shouldn't change.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+ DownloadAttributeSameOriginRedirectNavigationTimeOut) {
+ net::EmbeddedTestServer origin_one;
+ net::EmbeddedTestServer origin_two;
+ ASSERT_TRUE(origin_one.InitializeAndListen());
+ ASSERT_TRUE(origin_two.InitializeAndListen());
+ // The download-attribute.html page contains an anchor element whose href is
+ // set to the value of the query parameter (specified as |target| in the URL
+ // below). The suggested filename for the anchor is 'suggested-filename'. When
+ // the page is loaded, a script simulates a click on the anchor, triggering a
+ // download of the target URL.
+ //
+ // We construct two test servers; origin_one and origin_two. Once started, the
+ // server URLs will differ by the port number. Therefore they will be in
+ // different origins.
+ GURL download_url = origin_one.GetURL("/ping");
+ GURL referrer_url = origin_one.GetURL(
+ std::string("/download-attribute.html?target=") + download_url.spec());
+ origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
+
+ // <origin_one>/download-attribute.html initiates a download of
+ // <origin_one>/ping, which redirects to <origin_two>/download. The latter
+ // will time out.
+ origin_one.RegisterRequestHandler(
+ CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
+
+ origin_one.StartAcceptingConnections();
+
+ NavigationStartObserver obs(shell()->web_contents());
+ NavigationController::LoadURLParams params(referrer_url);
+ params.transition_type = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ shell()->web_contents()->GetController().LoadURLWithParams(params);
+ shell()->web_contents()->Focus();
+
+ // Waiting for 2 navigation to happen, one for the original request, one for
+ // the redirect.
+ obs.WaitForFinished(2);
+ EXPECT_EQ(referrer_url, shell()->web_contents()->GetVisibleURL());
ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+ origin_two.StartAcceptingConnections();
ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
}
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index 2d597182720..624af7658eb 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -556,6 +556,7 @@ bool DownloadManagerImpl::InterceptDownload(
info.render_process_id, info.render_frame_id);
params.from_download_cross_origin_redirect = true;
params.initiator_origin = info.request_initiator;
+ params.is_renderer_initiated = info.is_content_initiated;
web_contents->GetController().LoadURLWithParams(params);
}
if (info.request_handle)
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.cc b/chromium/content/browser/frame_host/navigation_handle_impl.cc
index 50ee263651f..3b11c0e1abe 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_handle_impl.cc
@@ -450,6 +450,7 @@ void NavigationHandleImpl::InitServiceWorkerHandle(
}
void NavigationHandleImpl::RenderProcessBlockedStateChanged(bool blocked) {
+ AddNetworkServiceDebugEvent(std::string("B") + (blocked ? "1" : "0"));
if (blocked)
StopCommitTimeout();
else
@@ -484,6 +485,7 @@ void NavigationHandleImpl::RestartCommitTimeout() {
void NavigationHandleImpl::OnCommitTimeout() {
DCHECK_EQ(NavigationRequest::READY_TO_COMMIT, state());
+ AddNetworkServiceDebugEvent("T");
#if defined(OS_ANDROID)
// Rate limit the number of stack dumps so we don't overwhelm our crash
// reports.
@@ -510,6 +512,12 @@ void NavigationHandleImpl::OnCommitTimeout() {
base::debug::ScopedCrashKeyString scoped_memory(
memory_key,
base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB()));
+
+ static base::debug::CrashKeyString* debug_string_key =
+ base::debug::AllocateCrashKeyString("ns_debug_events",
+ base::debug::CrashKeySize::Size256);
+ base::debug::ScopedCrashKeyString scoped_debug_string(
+ debug_string_key, GetNetworkServiceDebugEventsString());
base::debug::DumpWithoutCrashing();
if (IsOutOfProcessNetworkService())
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc
index 4bb7b470e7f..8175ccc7dc7 100644
--- a/chromium/content/browser/frame_host/navigation_request.cc
+++ b/chromium/content/browser/frame_host/navigation_request.cc
@@ -2048,6 +2048,8 @@ void NavigationRequest::CommitNavigation() {
commit_params_.prefetched_signed_exchanges =
std::move(subresource_loader_params_->prefetched_signed_exchanges);
}
+
+ AddNetworkServiceDebugEvent("COM");
render_frame_host_->CommitNavigation(
this, common_params_, commit_params_, response_head_.get(),
std::move(response_body_), std::move(url_loader_client_endpoints_),
@@ -2107,6 +2109,16 @@ void NavigationRequest::RenderProcessHostDestroyed(RenderProcessHost* host) {
ResetExpectedProcess();
}
+void NavigationRequest::RenderProcessReady(RenderProcessHost* host) {
+ AddNetworkServiceDebugEvent("RPR");
+}
+
+void NavigationRequest::RenderProcessExited(
+ RenderProcessHost* host,
+ const ChildProcessTerminationInfo& info) {
+ AddNetworkServiceDebugEvent("RPE");
+}
+
void NavigationRequest::UpdateSiteURL(
RenderProcessHost* post_redirect_process) {
GURL new_site_url = GetSiteForCommonParamsURL();
@@ -2729,6 +2741,7 @@ void NavigationRequest::DidCommitNavigation(
bool did_replace_entry,
const GURL& previous_url,
NavigationType navigation_type) {
+ AddNetworkServiceDebugEvent("DCN");
common_params_.url = params.url;
did_replace_entry_ = did_replace_entry;
should_update_history_ = params.should_update_history;
@@ -2847,6 +2860,9 @@ void NavigationRequest::ReadyToCommitNavigation(bool is_error) {
TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
"ReadyToCommitNavigation");
+ AddNetworkServiceDebugEvent(
+ std::string("RTCN") +
+ (render_frame_host_->GetProcess()->IsReady() ? "1" : "0"));
handle_state_ = READY_TO_COMMIT;
ready_to_commit_time_ = base::TimeTicks::Now();
navigation_handle_->RestartCommitTimeout();
diff --git a/chromium/content/browser/frame_host/navigation_request.h b/chromium/content/browser/frame_host/navigation_request.h
index 67c95139821..92c2c4fba60 100644
--- a/chromium/content/browser/frame_host/navigation_request.h
+++ b/chromium/content/browser/frame_host/navigation_request.h
@@ -19,6 +19,7 @@
#include "content/browser/initiator_csp_context.h"
#include "content/browser/loader/navigation_url_loader_delegate.h"
#include "content/browser/navigation_subresource_loader_params.h"
+#include "content/browser/network_service_instance_impl.h"
#include "content/browser/web_package/bundled_exchanges_factory.h"
#include "content/common/content_export.h"
#include "content/common/frame_message_enums.h"
@@ -688,6 +689,9 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate,
bool IsSelfReferentialURL();
// RenderProcessHostObserver implementation.
+ void RenderProcessReady(RenderProcessHost* host) override;
+ void RenderProcessExited(RenderProcessHost* host,
+ const ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
void RecordNavigationMetrics() const;
diff --git a/chromium/content/browser/network_service_instance_impl.cc b/chromium/content/browser/network_service_instance_impl.cc
index 4c8203f4a97..53832bbbfe7 100644
--- a/chromium/content/browser/network_service_instance_impl.cc
+++ b/chromium/content/browser/network_service_instance_impl.cc
@@ -54,6 +54,12 @@ network::NetworkConnectionTracker* g_network_connection_tracker;
bool g_network_service_is_responding = false;
base::Time g_last_network_service_crash;
+std::deque<std::pair<std::string, base::Time>>& GetDebugEvents() {
+ static base::NoDestructor<std::deque<std::pair<std::string, base::Time>>>
+ debug_events;
+ return *debug_events;
+}
+
std::unique_ptr<network::NetworkService>& GetLocalNetworkService() {
static base::NoDestructor<
base::SequenceLocalStorageSlot<std::unique_ptr<network::NetworkService>>>
@@ -120,6 +126,7 @@ void OnNetworkServiceCrash() {
DCHECK(g_network_service_ptr->encountered_error());
g_last_network_service_crash = base::Time::Now();
GetCrashHandlersList().Notify();
+ AddNetworkServiceDebugEvent("ONSC");
}
// Parses the desired granularity of NetLog capturing specified by the command
@@ -206,6 +213,7 @@ CONTENT_EXPORT network::mojom::NetworkService* GetNetworkServiceFromConnector(
mojo::MakeRequest(g_network_service_ptr)));
}
+ AddNetworkServiceDebugEvent("START");
network::mojom::NetworkServiceClientPtr client_ptr;
auto client_request = mojo::MakeRequest(&client_ptr);
// Call SetClient before creating NetworkServiceClient, as the latter
@@ -215,6 +223,7 @@ CONTENT_EXPORT network::mojom::NetworkService* GetNetworkServiceFromConnector(
g_network_service_is_responding = false;
g_network_service_ptr->QueryVersion(base::BindRepeating(
[](base::Time start_time, uint32_t) {
+ AddNetworkServiceDebugEvent("RESP");
g_network_service_is_responding = true;
base::TimeDelta delta = base::Time::Now() - start_time;
UMA_HISTOGRAM_MEDIUM_TIMES("NetworkService.TimeToFirstResponse",
@@ -411,4 +420,24 @@ void PingNetworkService(base::OnceClosure closure) {
base::Passed(std::move(closure))));
}
+void AddNetworkServiceDebugEvent(const std::string& event) {
+ auto& events = GetDebugEvents();
+ events.push_front({event, base::Time::Now()});
+ // Keep at most 20 most recent events.
+ if (events.size() > 20)
+ events.pop_back();
+}
+
+std::string GetNetworkServiceDebugEventsString() {
+ auto& events = GetDebugEvents();
+ if (events.empty())
+ return std::string();
+ std::stringstream stream;
+ base::Time now = base::Time::Now();
+ for (const auto& info : events) {
+ stream << info.first << ":" << (now - info.second).InSecondsF() << ",";
+ }
+ return stream.str();
+}
+
} // namespace content
diff --git a/chromium/content/browser/network_service_instance_impl.h b/chromium/content/browser/network_service_instance_impl.h
index f3c93c1bea4..0c401f8d9a5 100644
--- a/chromium/content/browser/network_service_instance_impl.h
+++ b/chromium/content/browser/network_service_instance_impl.h
@@ -44,6 +44,8 @@ enum class NetworkServiceAvailability {
CONTENT_EXPORT NetworkServiceAvailability GetNetworkServiceAvailability();
CONTENT_EXPORT base::TimeDelta GetTimeSinceLastNetworkServiceCrash();
CONTENT_EXPORT void PingNetworkService(base::OnceClosure closure);
+CONTENT_EXPORT void AddNetworkServiceDebugEvent(const std::string& event);
+CONTENT_EXPORT std::string GetNetworkServiceDebugEventsString();
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager.cc b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
index 8a61f6c8e00..61ec39f62d4 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
@@ -548,6 +548,7 @@ MediaStreamManager::MediaStreamManager(
if (base::FeatureList::IsEnabled(features::kMojoVideoCapture)) {
video_capture_provider = std::make_unique<VideoCaptureProviderSwitcher>(
std::make_unique<ServiceVideoCaptureProvider>(
+ GetSystemConnector(),
base::BindRepeating(&SendVideoCaptureLogMessage)),
InProcessVideoCaptureProvider::CreateInstanceForNonDeviceCapture(
std::move(device_task_runner),
diff --git a/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.cc b/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.cc
index 5d5e0dca013..b02fcc94cc6 100644
--- a/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.cc
+++ b/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.cc
@@ -4,14 +4,14 @@
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
-#include "content/public/browser/video_capture_service.h"
-
namespace content {
RefCountedVideoSourceProvider::RefCountedVideoSourceProvider(
video_capture::mojom::VideoSourceProviderPtr source_provider,
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider,
base::OnceClosure destruction_cb)
: source_provider_(std::move(source_provider)),
+ device_factory_provider_(std::move(device_factory_provider)),
destruction_cb_(std::move(destruction_cb)) {}
RefCountedVideoSourceProvider::~RefCountedVideoSourceProvider() {
@@ -23,8 +23,12 @@ RefCountedVideoSourceProvider::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
+void RefCountedVideoSourceProvider::ShutdownServiceAsap() {
+ device_factory_provider_->ShutdownServiceAsap();
+}
+
void RefCountedVideoSourceProvider::SetRetryCount(int32_t count) {
- GetVideoCaptureService().SetRetryCount(count);
+ device_factory_provider_->SetRetryCount(count);
}
void RefCountedVideoSourceProvider::ReleaseProviderForTesting() {
diff --git a/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.h b/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.h
index d1b8eacfbe6..105843f3406 100644
--- a/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.h
+++ b/chromium/content/browser/renderer_host/media/ref_counted_video_source_provider.h
@@ -7,6 +7,7 @@
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
namespace content {
@@ -21,6 +22,7 @@ class CONTENT_EXPORT RefCountedVideoSourceProvider
public:
RefCountedVideoSourceProvider(
video_capture::mojom::VideoSourceProviderPtr source_provider,
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider,
base::OnceClosure destruction_cb);
base::WeakPtr<RefCountedVideoSourceProvider> GetWeakPtr();
@@ -29,6 +31,7 @@ class CONTENT_EXPORT RefCountedVideoSourceProvider
return source_provider_;
}
+ void ShutdownServiceAsap();
void SetRetryCount(int32_t count);
void ReleaseProviderForTesting();
@@ -37,6 +40,7 @@ class CONTENT_EXPORT RefCountedVideoSourceProvider
~RefCountedVideoSourceProvider();
video_capture::mojom::VideoSourceProviderPtr source_provider_;
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
base::OnceClosure destruction_cb_;
base::WeakPtrFactory<RefCountedVideoSourceProvider> weak_ptr_factory_{this};
diff --git a/chromium/content/browser/renderer_host/media/service_launched_video_capture_device.h b/chromium/content/browser/renderer_host/media/service_launched_video_capture_device.h
index 4f05f15d273..b6a605e5059 100644
--- a/chromium/content/browser/renderer_host/media/service_launched_video_capture_device.h
+++ b/chromium/content/browser/renderer_host/media/service_launched_video_capture_device.h
@@ -11,8 +11,8 @@
namespace content {
-// Implementation of LaunchedVideoCaptureDevice that uses
-// video_capture::mojom::VideoCaptureService.
+// Implementation of LaunchedVideoCaptureDevice that uses the "video_capture"
+// service.
class ServiceLaunchedVideoCaptureDevice : public LaunchedVideoCaptureDevice {
public:
ServiceLaunchedVideoCaptureDevice(
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.h b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.h
index c080c1a909b..7e87e6463bb 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.h
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.h
@@ -13,8 +13,8 @@
namespace content {
-// Implementation of VideoCaptureDeviceLauncher that uses uses
-// video_capture::mojom::VideoCaptureService.
+// Implementation of VideoCaptureDeviceLauncher that uses the "video_capture"
+// service.
class CONTENT_EXPORT ServiceVideoCaptureDeviceLauncher
: public VideoCaptureDeviceLauncher {
public:
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
index a7e6ee8a54c..63715421590 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
@@ -62,6 +62,7 @@ class ServiceVideoCaptureDeviceLauncherTest : public testing::Test {
&mock_source_provider_, mojo::MakeRequest(&source_provider_));
service_connection_ = base::MakeRefCounted<RefCountedVideoSourceProvider>(
std::move(source_provider_),
+ video_capture::mojom::DeviceFactoryProviderPtr(),
release_connection_cb_.Get());
launcher_ = std::make_unique<ServiceVideoCaptureDeviceLauncher>(
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc b/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
index c9da8b00401..d32c8e645b6 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -14,11 +14,11 @@
#include "content/common/child_process_host_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/video_capture_service.h"
-#include "content/public/common/content_features.h"
+#include "content/public/common/service_manager_connection.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/uma/video_capture_service_event.h"
#if defined(OS_CHROMEOS)
@@ -51,82 +51,38 @@ static const int kMaxRetriesForGetDeviceInfos = 1;
namespace content {
-class ServiceVideoCaptureProvider::ServiceProcessObserver
- : public ServiceProcessHost::Observer {
- public:
- ServiceProcessObserver(base::RepeatingClosure start_callback,
- base::RepeatingClosure stop_callback)
- : io_task_runner_(
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})),
- start_callback_(std::move(start_callback)),
- stop_callback_(std::move(stop_callback)) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- ServiceProcessHost::AddObserver(this);
- }
-
- ~ServiceProcessObserver() override {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- ServiceProcessHost::RemoveObserver(this);
- }
-
- private:
- // ServiceProcessHost::Observer implementation.
- void OnServiceProcessLaunched(const ServiceProcessInfo& info) override {
- if (info.IsService<video_capture::mojom::VideoCaptureService>())
- io_task_runner_->PostTask(FROM_HERE, base::BindOnce(start_callback_));
- }
-
- void OnServiceProcessTerminatedNormally(
- const ServiceProcessInfo& info) override {
- if (info.IsService<video_capture::mojom::VideoCaptureService>())
- io_task_runner_->PostTask(FROM_HERE, base::BindOnce(stop_callback_));
- }
-
- void OnServiceProcessCrashed(const ServiceProcessInfo& info) override {
- if (info.IsService<video_capture::mojom::VideoCaptureService>())
- io_task_runner_->PostTask(FROM_HERE, base::BindOnce(stop_callback_));
- }
-
- const scoped_refptr<base::TaskRunner> io_task_runner_;
- const base::RepeatingClosure start_callback_;
- const base::RepeatingClosure stop_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceProcessObserver);
-};
-
-#if defined(OS_CHROMEOS)
ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
+ service_manager::Connector* connector,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
- : ServiceVideoCaptureProvider(base::NullCallback(),
- std::move(emit_log_message_cb)) {}
+ : connector_(connector ? connector->Clone() : nullptr),
+ emit_log_message_cb_(std::move(emit_log_message_cb)),
+ launcher_has_connected_to_source_provider_(false),
+ service_listener_binding_(this) {
+ base::PostTaskWithTraits(
+ FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(
+ &ServiceVideoCaptureProvider::RegisterServiceListenerOnIOThread,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+#if defined(OS_CHROMEOS)
ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
CreateAcceleratorFactoryCallback create_accelerator_factory_cb,
+ service_manager::Connector* connector,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
- : create_accelerator_factory_cb_(std::move(create_accelerator_factory_cb)),
+ : connector_(connector ? connector->Clone() : nullptr),
+ create_accelerator_factory_cb_(std::move(create_accelerator_factory_cb)),
emit_log_message_cb_(std::move(emit_log_message_cb)),
- launcher_has_connected_to_source_provider_(false) {
-#else // defined(OS_CHROMEOS)
-ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
- base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
- : emit_log_message_cb_(std::move(emit_log_message_cb)),
- launcher_has_connected_to_source_provider_(false) {
-#endif // defined(OS_CHROMEOS)
- if (features::IsVideoCaptureServiceEnabledForOutOfProcess()) {
- service_process_observer_.emplace(
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}),
- base::BindRepeating(&ServiceVideoCaptureProvider::OnServiceStarted,
- weak_ptr_factory_.GetWeakPtr()),
- base::BindRepeating(&ServiceVideoCaptureProvider::OnServiceStopped,
- weak_ptr_factory_.GetWeakPtr()));
- } else if (features::IsVideoCaptureServiceEnabledForBrowserProcess()) {
- // Connect immediately and permanently when the service runs in-process.
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})
- ->PostTask(FROM_HERE,
- base::Bind(&ServiceVideoCaptureProvider::OnServiceStarted,
- weak_ptr_factory_.GetWeakPtr()));
- }
+ launcher_has_connected_to_source_provider_(false),
+ service_listener_binding_(this),
+ weak_ptr_factory_(this) {
+ base::PostTaskWithTraits(
+ FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(
+ &ServiceVideoCaptureProvider::RegisterServiceListenerOnIOThread,
+ weak_ptr_factory_.GetWeakPtr()));
}
+#endif // defined(OS_CHROMEOS)
ServiceVideoCaptureProvider::~ServiceVideoCaptureProvider() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -149,8 +105,13 @@ ServiceVideoCaptureProvider::CreateDeviceLauncher() {
weak_ptr_factory_.GetWeakPtr()));
}
-void ServiceVideoCaptureProvider::OnServiceStarted() {
+void ServiceVideoCaptureProvider::OnServiceStarted(
+ const ::service_manager::Identity& identity,
+ uint32_t pid) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (identity.name() != video_capture::mojom::kServiceName)
+ return;
+
// Whenever the video capture service starts, we register a
// VirtualVideoCaptureDevicesChangedObserver in order to propagate device
// change events when virtual devices are added to or removed from the
@@ -165,9 +126,13 @@ void ServiceVideoCaptureProvider::OnServiceStarted() {
true /*raise_event_if_virtual_devices_already_present*/);
}
-void ServiceVideoCaptureProvider::OnServiceStopped() {
+void ServiceVideoCaptureProvider::OnServiceStopped(
+ const ::service_manager::Identity& identity) {
#if defined(OS_MACOSX)
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (identity.name() != video_capture::mojom::kServiceName)
+ return;
+
if (stashed_result_callback_for_retry_) {
TRACE_EVENT_INSTANT0(
TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
@@ -181,6 +146,21 @@ void ServiceVideoCaptureProvider::OnServiceStopped() {
#endif
}
+void ServiceVideoCaptureProvider::RegisterServiceListenerOnIOThread() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (!connector_)
+ return;
+
+ service_manager::mojom::ServiceManagerListenerPtr listener;
+ service_listener_binding_.Bind(mojo::MakeRequest(&listener));
+
+ service_manager::mojom::ServiceManagerPtr service_manager;
+ connector_->BindInterface(service_manager::mojom::kServiceName,
+ &service_manager);
+ service_manager->AddListener(std::move(listener));
+}
+
void ServiceVideoCaptureProvider::OnLauncherConnectingToSourceProvider(
scoped_refptr<RefCountedVideoSourceProvider>* out_provider) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -212,8 +192,14 @@ ServiceVideoCaptureProvider::LazyConnectToService() {
launcher_has_connected_to_source_provider_ = false;
time_of_last_connect_ = base::TimeTicks::Now();
- auto ui_task_runner =
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI});
+ DCHECK(connector_)
+ << "Attempted to connect to the video capture service from "
+ "a process that does not provide a "
+ "ServiceManagerConnection";
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider;
+ connector_->BindInterface(video_capture::mojom::kServiceName,
+ &device_factory_provider);
+
#if defined(OS_CHROMEOS)
video_capture::mojom::AcceleratorFactoryPtr accelerator_factory;
if (!create_accelerator_factory_cb_)
@@ -221,18 +207,18 @@ ServiceVideoCaptureProvider::LazyConnectToService() {
base::BindRepeating(&CreateAcceleratorFactory);
mojo::MakeStrongBinding(create_accelerator_factory_cb_.Run(),
mojo::MakeRequest(&accelerator_factory));
- GetVideoCaptureService().InjectGpuDependencies(
+ device_factory_provider->InjectGpuDependencies(
std::move(accelerator_factory));
#endif // defined(OS_CHROMEOS)
video_capture::mojom::VideoSourceProviderPtr source_provider;
- GetVideoCaptureService().ConnectToVideoSourceProvider(
+ device_factory_provider->ConnectToVideoSourceProvider(
mojo::MakeRequest(&source_provider));
source_provider.set_connection_error_handler(base::BindOnce(
&ServiceVideoCaptureProvider::OnLostConnectionToSourceProvider,
weak_ptr_factory_.GetWeakPtr()));
auto result = base::MakeRefCounted<RefCountedVideoSourceProvider>(
- std::move(source_provider),
+ std::move(source_provider), std::move(device_factory_provider),
base::BindOnce(&ServiceVideoCaptureProvider::OnServiceConnectionClosed,
weak_ptr_factory_.GetWeakPtr(),
ReasonForDisconnect::kUnused));
@@ -288,13 +274,13 @@ void ServiceVideoCaptureProvider::OnDeviceInfosReceived(
video_capture::uma::LogMacbookRetryGetDeviceInfosEvent(
video_capture::uma::PROVIDER_RECEIVED_ZERO_INFOS_STOPPING_SERVICE);
TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
- "Waiting for video capture service to shut down.",
+ "Asking video capture service to shut down.",
TRACE_EVENT_SCOPE_PROCESS);
+ service_connection->ShutdownServiceAsap();
stashed_result_callback_for_retry_ = std::move(result_callback);
stashed_retry_count_ = retry_count;
-
- // We may try again once |OnServiceStopped()| is invoked via our
- // ServiceProcessHost observer.
+ // Continue when service manager reports that service has shut down via
+ // OnServiceStopped().
return;
}
}
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider.h b/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
index 71a3f6ed3b5..7318d843210 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
@@ -5,38 +5,42 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_PROVIDER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SERVICE_VIDEO_CAPTURE_PROVIDER_H_
-#include "base/threading/sequence_bound.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/media/ref_counted_video_source_provider.h"
#include "content/browser/renderer_host/media/video_capture_provider.h"
-#include "content/public/browser/service_process_host.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace content {
-// Implementation of VideoCaptureProvider that uses
-// video_capture::mojom::VideoCaptureService.
-//
+// Implementation of VideoCaptureProvider that uses the "video_capture" service.
// Connects to the service lazily on demand and disconnects from the service as
// soon as all previously handed out VideoCaptureDeviceLauncher instances have
// been released and no more answers to GetDeviceInfosAsync() calls are pending.
+// It is legal to create instances using |nullptr| as |connector| but for
+// instances produced this way, it is illegal to subsequently call any of the
+// public methods.
class CONTENT_EXPORT ServiceVideoCaptureProvider
: public VideoCaptureProvider,
- public ServiceProcessHost::Observer {
+ public service_manager::mojom::ServiceManagerListener {
public:
// This constructor uses a default factory for instances of
// viz::mojom::Gpu which produces instances of class content::GpuClient.
- explicit ServiceVideoCaptureProvider(
+ ServiceVideoCaptureProvider(
+ service_manager::Connector* connector,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
#if defined(OS_CHROMEOS)
using CreateAcceleratorFactoryCallback = base::RepeatingCallback<
std::unique_ptr<video_capture::mojom::AcceleratorFactory>()>;
- // Lets clients provide a custom factory method for creating instances of
- // viz::mojom::Gpu.
+ // Lets clients provide a custom mojo::Connector and factory method for
+ // creating instances of viz::mojom::Gpu.
ServiceVideoCaptureProvider(
CreateAcceleratorFactoryCallback create_accelerator_factory_cb,
+ service_manager::Connector* connector,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
#endif // defined(OS_CHROMEOS)
@@ -46,12 +50,25 @@ class CONTENT_EXPORT ServiceVideoCaptureProvider
void GetDeviceInfosAsync(GetDeviceInfosCallback result_callback) override;
std::unique_ptr<VideoCaptureDeviceLauncher> CreateDeviceLauncher() override;
- private:
- void OnServiceStarted();
- void OnServiceStopped();
+ // service_manager::mojom::ServiceManagerListener implementation.
+ void OnInit(std::vector<service_manager::mojom::RunningServiceInfoPtr>
+ running_services) override {}
+ void OnServiceCreated(
+ service_manager::mojom::RunningServiceInfoPtr service) override {}
+ void OnServiceStarted(const ::service_manager::Identity& identity,
+ uint32_t pid) override;
+ void OnServicePIDReceived(const ::service_manager::Identity& identity,
+ uint32_t pid) override {}
+ void OnServiceFailedToStart(
+ const ::service_manager::Identity& identity) override {}
+ void OnServiceStopped(const ::service_manager::Identity& identity) override;
+ private:
enum class ReasonForDisconnect { kShutdown, kUnused, kConnectionLost };
+ void RegisterServiceListenerOnIOThread();
+ // Note, this needs to have void return value because of "weak_ptrs can only
+ // bind to methods without return values".
void OnLauncherConnectingToSourceProvider(
scoped_refptr<RefCountedVideoSourceProvider>* out_provider);
// Discarding the returned RefCountedVideoSourceProvider indicates that the
@@ -74,6 +91,7 @@ class CONTENT_EXPORT ServiceVideoCaptureProvider
void OnLostConnectionToSourceProvider();
void OnServiceConnectionClosed(ReasonForDisconnect reason);
+ std::unique_ptr<service_manager::Connector> connector_;
#if defined(OS_CHROMEOS)
CreateAcceleratorFactoryCallback create_accelerator_factory_cb_;
#endif // defined(OS_CHROMEOS)
@@ -85,16 +103,14 @@ class CONTENT_EXPORT ServiceVideoCaptureProvider
base::TimeTicks time_of_last_connect_;
base::TimeTicks time_of_last_uninitialize_;
+ mojo::Binding<service_manager::mojom::ServiceManagerListener>
+ service_listener_binding_;
+
#if defined(OS_MACOSX)
GetDeviceInfosCallback stashed_result_callback_for_retry_;
int stashed_retry_count_;
#endif
- // We own this but it must operate on the UI thread.
- class ServiceProcessObserver;
- base::Optional<base::SequenceBound<ServiceProcessObserver>>
- service_process_observer_;
-
base::WeakPtrFactory<ServiceVideoCaptureProvider> weak_ptr_factory_{this};
};
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
index 41df3156200..ca82f24746d 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -9,20 +9,22 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
#include "base/test/mock_callback.h"
#include "base/threading/thread.h"
#include "content/public/browser/video_capture_device_launcher.h"
-#include "content/public/browser/video_capture_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_binding.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
+#include "services/video_capture/public/cpp/mock_device_factory_provider.h"
#include "services/video_capture/public/cpp/mock_push_subscription.h"
-#include "services/video_capture/public/cpp/mock_video_capture_service.h"
#include "services/video_capture/public/cpp/mock_video_source.h"
#include "services/video_capture/public/cpp/mock_video_source_provider.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,6 +40,49 @@ static const base::WeakPtr<media::VideoFrameReceiver> kNullReceiver;
static const auto kIgnoreLogMessageCB =
base::BindRepeating([](const std::string&) {});
+class FakeVideoCaptureService : public service_manager::Service {
+ public:
+ explicit FakeVideoCaptureService(
+ service_manager::mojom::ServiceRequest request)
+ : binding_(this, std::move(request)) {}
+
+ void OnStart() {
+ registry_.AddInterface<video_capture::mojom::DeviceFactoryProvider>(
+ // Unretained |this| is safe because |registry_| is owned by |this|.
+ base::BindRepeating(
+ &FakeVideoCaptureService::OnDeviceFactoryProviderRequest,
+ base::Unretained(this)));
+ }
+
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
+ }
+
+ void OnDeviceFactoryProviderRequest(
+ video_capture::mojom::DeviceFactoryProviderRequest request) {
+ BindFactoryProvider(&request);
+ }
+
+ MOCK_METHOD1(
+ BindFactoryProvider,
+ void(video_capture::mojom::DeviceFactoryProviderRequest* request));
+
+ private:
+ service_manager::ServiceBinding binding_;
+ service_manager::BinderRegistry registry_;
+};
+
+class NullService : public service_manager::Service {
+ public:
+ explicit NullService(service_manager::mojom::ServiceRequest request)
+ : binding_(this, std::move(request)) {}
+
+ private:
+ service_manager::ServiceBinding binding_;
+};
+
class MockVideoCaptureDeviceLauncherCallbacks
: public VideoCaptureDeviceLauncher::Callbacks {
public:
@@ -55,13 +100,14 @@ class MockVideoCaptureDeviceLauncherCallbacks
class ServiceVideoCaptureProviderTest : public testing::Test {
public:
ServiceVideoCaptureProviderTest()
- : source_provider_binding_(&mock_source_provider_) {
- OverrideVideoCaptureServiceForTesting(&mock_video_capture_service_);
- }
-
- ~ServiceVideoCaptureProviderTest() override {
- OverrideVideoCaptureServiceForTesting(nullptr);
- }
+ : fake_video_capture_service_(connector_factory_.RegisterInstance(
+ video_capture::mojom::kServiceName)),
+ fake_service_manager_(connector_factory_.RegisterInstance(
+ service_manager::mojom::kServiceName)),
+ factory_provider_binding_(&mock_device_factory_provider_),
+ factory_provider_is_bound_(false),
+ source_provider_binding_(&mock_source_provider_) {}
+ ~ServiceVideoCaptureProviderTest() override {}
protected:
void SetUp() override {
@@ -70,13 +116,28 @@ class ServiceVideoCaptureProviderTest : public testing::Test {
base::BindRepeating([]() {
return std::unique_ptr<video_capture::mojom::AcceleratorFactory>();
}),
- kIgnoreLogMessageCB);
+ connector_factory_.GetDefaultConnector(), kIgnoreLogMessageCB);
#else
- provider_ =
- std::make_unique<ServiceVideoCaptureProvider>(kIgnoreLogMessageCB);
+ provider_ = std::make_unique<ServiceVideoCaptureProvider>(
+ connector_factory_.GetDefaultConnector(), kIgnoreLogMessageCB);
#endif // defined(OS_CHROMEOS)
- ON_CALL(mock_video_capture_service_, DoConnectToVideoSourceProvider(_))
+ ON_CALL(fake_video_capture_service_, BindFactoryProvider(_))
+ .WillByDefault(Invoke(
+ [this](
+ video_capture::mojom::DeviceFactoryProviderRequest* request) {
+ if (factory_provider_binding_.is_bound())
+ factory_provider_binding_.Close();
+ factory_provider_binding_.Bind(std::move(*request));
+ factory_provider_is_bound_ = true;
+ factory_provider_binding_.set_connection_error_handler(
+ base::BindOnce(
+ [](bool* factory_provider_is_bound) {
+ *factory_provider_is_bound = false;
+ },
+ &factory_provider_is_bound_));
+ }));
+ ON_CALL(mock_device_factory_provider_, DoConnectToVideoSourceProvider(_))
.WillByDefault(Invoke(
[this](video_capture::mojom::VideoSourceProviderRequest& request) {
if (source_provider_binding_.is_bound())
@@ -120,7 +181,13 @@ class ServiceVideoCaptureProviderTest : public testing::Test {
void TearDown() override {}
content::TestBrowserThreadBundle test_browser_thread_bundle_;
- video_capture::MockVideoCaptureService mock_video_capture_service_;
+ service_manager::TestConnectorFactory connector_factory_;
+ FakeVideoCaptureService fake_video_capture_service_;
+ NullService fake_service_manager_;
+ video_capture::MockDeviceFactoryProvider mock_device_factory_provider_;
+ mojo::Binding<video_capture::mojom::DeviceFactoryProvider>
+ factory_provider_binding_;
+ bool factory_provider_is_bound_;
video_capture::MockVideoSourceProvider mock_source_provider_;
mojo::Binding<video_capture::mojom::VideoSourceProvider>
source_provider_binding_;
@@ -175,6 +242,8 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Simulate that the service goes down by cutting the connections.
source_provider_binding_.Close();
+ factory_provider_binding_.Close();
+
wait_for_callback_from_service.Run();
}
@@ -204,9 +273,13 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Setup part 2: Now that the connection to the service is established, we can
// listen for disconnects.
base::RunLoop wait_for_connection_to_source_provider_to_close;
+ base::RunLoop wait_for_connection_to_device_factory_provider_to_close;
source_provider_binding_.set_connection_error_handler(
base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
&wait_for_connection_to_source_provider_to_close));
+ factory_provider_binding_.set_connection_error_handler(
+ base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
+ &wait_for_connection_to_device_factory_provider_to_close));
// Exercise part 2: The service responds
std::vector<media::VideoCaptureDeviceInfo> arbitrarily_empty_results;
@@ -214,6 +287,9 @@ TEST_F(ServiceVideoCaptureProviderTest,
// Verification: Expect |provider_| to close the connection to the service.
wait_for_connection_to_source_provider_to_close.Run();
+ if (factory_provider_is_bound_) {
+ wait_for_connection_to_device_factory_provider_to_close.Run();
+ }
}
// Tests that |ServiceVideoCaptureProvider| does not close the connection to the
@@ -241,6 +317,11 @@ TEST_F(ServiceVideoCaptureProviderTest,
*connection_has_been_closed = true;
},
&connection_has_been_closed));
+ factory_provider_binding_.set_connection_error_handler(base::BindOnce(
+ [](bool* connection_has_been_closed) {
+ *connection_has_been_closed = true;
+ },
+ &connection_has_been_closed));
// Exercise part 2: Make a few GetDeviceInfosAsync requests
base::RunLoop wait_for_get_device_infos_response_1;
@@ -332,6 +413,11 @@ TEST_F(ServiceVideoCaptureProviderTest,
*connection_has_been_closed = true;
},
&connection_has_been_closed));
+ factory_provider_binding_.set_connection_error_handler(base::BindOnce(
+ [](bool* connection_has_been_closed) {
+ *connection_has_been_closed = true;
+ },
+ &connection_has_been_closed));
// The service now responds to the first request.
std::vector<media::VideoCaptureDeviceInfo> arbitrarily_empty_results;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager.cc b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
index c5fa1a0e74e..14b318cbd78 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
@@ -236,16 +236,14 @@ void VideoCaptureManager::DoStopDevice(VideoCaptureController* controller) {
// If start request has not yet started processing, i.e. if it is not at the
// beginning of the queue, remove it from the queue.
- auto request_iter = device_start_request_queue_.begin();
- if (request_iter != device_start_request_queue_.end()) {
- request_iter =
- std::find_if(++request_iter, device_start_request_queue_.end(),
- [controller](const CaptureDeviceStartRequest& request) {
- return request.controller() == controller;
- });
- if (request_iter != device_start_request_queue_.end()) {
- device_start_request_queue_.erase(request_iter);
- return;
+ if (!device_start_request_queue_.empty()) {
+ auto second_request = std::next(device_start_request_queue_.begin());
+
+ for (auto it = second_request; it != device_start_request_queue_.end();) {
+ if (it->controller() == controller)
+ it = device_start_request_queue_.erase(it);
+ else
+ ++it;
}
}
@@ -641,8 +639,7 @@ void VideoCaptureManager::GetPhotoState(
media::VideoCaptureDevice::GetPhotoStateCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- const VideoCaptureController* controller =
- LookupControllerBySessionId(session_id);
+ VideoCaptureController* controller = LookupControllerBySessionId(session_id);
if (!controller)
return;
if (controller->IsDeviceAlive()) {
@@ -653,7 +650,7 @@ void VideoCaptureManager::GetPhotoState(
photo_request_queue_.emplace_back(
session_id,
base::Bind(&VideoCaptureController::GetPhotoState,
- base::Unretained(controller), base::Passed(&callback)));
+ controller->GetWeakPtrForIOThread(), base::Passed(&callback)));
}
void VideoCaptureManager::SetPhotoOptions(
@@ -672,7 +669,7 @@ void VideoCaptureManager::SetPhotoOptions(
// Queue up a request for later.
photo_request_queue_.emplace_back(
session_id, base::Bind(&VideoCaptureController::SetPhotoOptions,
- base::Unretained(controller),
+ controller->GetWeakPtrForIOThread(),
base::Passed(&settings), base::Passed(&callback)));
}
@@ -698,7 +695,7 @@ void VideoCaptureManager::TakePhoto(
photo_request_queue_.emplace_back(
session_id,
base::Bind(&VideoCaptureController::TakePhoto,
- base::Unretained(controller), base::Passed(&callback)));
+ controller->GetWeakPtrForIOThread(), base::Passed(&callback)));
}
void VideoCaptureManager::OnOpened(
diff --git a/chromium/content/browser/service_manager/service_manager_context.cc b/chromium/content/browser/service_manager/service_manager_context.cc
index 2ac4547aabd..c747a954ef7 100644
--- a/chromium/content/browser/service_manager/service_manager_context.cc
+++ b/chromium/content/browser/service_manager/service_manager_context.cc
@@ -87,6 +87,8 @@
#include "services/tracing/public/cpp/tracing_features.h"
#include "services/tracing/public/mojom/constants.mojom.h"
#include "services/tracing/tracing_service.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/service_impl.h"
#include "ui/base/buildflags.h"
#include "ui/base/ui_base_features.h"
@@ -317,6 +319,13 @@ void RegisterInProcessService(
&LaunchInProcessService, std::move(task_runner), factory);
}
+std::unique_ptr<service_manager::Service> CreateVideoCaptureService(
+ service_manager::mojom::ServiceRequest request) {
+ return std::make_unique<video_capture::ServiceImpl>(
+ std::move(request), base::CreateSingleThreadTaskRunnerWithTraits(
+ {content::BrowserThread::UI}));
+}
+
void CreateInProcessAudioService(
scoped_refptr<base::SequencedTaskRunner> task_runner,
service_manager::mojom::ServiceRequest request) {
@@ -634,6 +643,20 @@ ServiceManagerContext::ServiceManagerContext(
base::BindRepeating(&CreateMediaSessionService));
}
+ if (features::IsVideoCaptureServiceEnabledForBrowserProcess()) {
+ RegisterInProcessService(
+ video_capture::mojom::kServiceName,
+#if defined(OS_WIN)
+ base::CreateCOMSTATaskRunnerWithTraits(
+#else
+ base::CreateSingleThreadTaskRunnerWithTraits(
+#endif
+ base::TaskTraits({base::MayBlock(), base::WithBaseSyncPrimitives(),
+ base::TaskPriority::BEST_EFFORT}),
+ base::SingleThreadTaskRunnerThreadMode::DEDICATED),
+ base::BindRepeating(&CreateVideoCaptureService));
+ }
+
#if defined(OS_LINUX)
RegisterInProcessService(
font_service::mojom::kServiceName,
diff --git a/chromium/content/browser/service_process_host_impl.cc b/chromium/content/browser/service_process_host_impl.cc
index 50034eadc8f..f41cf58a87c 100644
--- a/chromium/content/browser/service_process_host_impl.cc
+++ b/chromium/content/browser/service_process_host_impl.cc
@@ -173,7 +173,6 @@ void LaunchServiceProcessOnIOThread(mojo::GenericPendingReceiver receiver,
: base::UTF8ToUTF16(*receiver.interface_name()));
host->SetMetricsName(*receiver.interface_name());
host->SetSandboxType(options.sandbox_type);
- host->SetExtraCommandLineSwitches(std::move(options.extra_switches));
if (options.child_flags)
host->set_child_flags(*options.child_flags);
host->Start();
diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc
index c11b6b26102..f1760434998 100644
--- a/chromium/content/browser/service_worker/service_worker_version.cc
+++ b/chromium/content/browser/service_worker/service_worker_version.cc
@@ -1183,6 +1183,15 @@ void ServiceWorkerVersion::OpenPaymentHandlerWindow(
return;
}
+ if (!url.is_valid() ||
+ !url::Origin::Create(url).IsSameOriginWith(script_origin_)) {
+ mojo::ReportBadMessage(
+ "Received PaymentRequestEvent#openWindow() request for a cross-origin "
+ "URL.");
+ binding_.Close();
+ return;
+ }
+
PaymentHandlerSupport::ShowPaymentHandlerWindow(
url, context_.get(),
base::BindOnce(&DidShowPaymentHandlerWindow, url, context_),
diff --git a/chromium/content/browser/utility_process_host.cc b/chromium/content/browser/utility_process_host.cc
index 85b12bc86b7..73aca4bb8ec 100644
--- a/chromium/content/browser/utility_process_host.cc
+++ b/chromium/content/browser/utility_process_host.cc
@@ -298,11 +298,6 @@ void UtilityProcessHost::SetServiceIdentity(
service_identity_ = identity;
}
-void UtilityProcessHost::SetExtraCommandLineSwitches(
- std::vector<std::string> switches) {
- extra_switches_ = std::move(switches);
-}
-
mojom::ChildProcess* UtilityProcessHost::GetChildProcess() {
return static_cast<ChildProcessHostImpl*>(process_->GetHost())
->child_process();
@@ -455,9 +450,6 @@ bool UtilityProcessHost::StartProcess() {
*service_identity_, cmd_line.get());
}
- for (const auto& extra_switch : extra_switches_)
- cmd_line->AppendSwitch(extra_switch);
-
std::unique_ptr<UtilitySandboxedProcessLauncherDelegate> delegate =
std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
sandbox_type_, env_, *cmd_line);
diff --git a/chromium/content/browser/utility_process_host.h b/chromium/content/browser/utility_process_host.h
index 8233364fdf6..e3417c485a9 100644
--- a/chromium/content/browser/utility_process_host.h
+++ b/chromium/content/browser/utility_process_host.h
@@ -117,9 +117,6 @@ class CONTENT_EXPORT UtilityProcessHost
// the identity of the service being launched.
void SetServiceIdentity(const service_manager::Identity& identity);
- // Provides extra switches to append to the process's command line.
- void SetExtraCommandLineSwitches(std::vector<std::string> switches);
-
// Returns a control interface for the running child process.
mojom::ChildProcess* GetChildProcess();
@@ -164,9 +161,6 @@ class CONTENT_EXPORT UtilityProcessHost
// service.
base::Optional<service_manager::Identity> service_identity_;
- // Extra command line switches to append.
- std::vector<std::string> extra_switches_;
-
// Indicates whether the process has been successfully launched yet, or if
// launch failed.
enum class LaunchState {
diff --git a/chromium/content/browser/video_capture_service.cc b/chromium/content/browser/video_capture_service.cc
deleted file mode 100644
index 4f9cdfb270b..00000000000
--- a/chromium/content/browser/video_capture_service.cc
+++ /dev/null
@@ -1,150 +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 "content/public/browser/video_capture_service.h"
-
-#include "base/no_destructor.h"
-#include "base/task/post_task.h"
-#include "base/threading/sequence_local_storage_slot.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/service_process_host.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "services/video_capture/public/uma/video_capture_service_event.h"
-#include "services/video_capture/video_capture_service_impl.h"
-
-#if defined(OS_WIN)
-#define CREATE_IN_PROCESS_TASK_RUNNER base::CreateCOMSTATaskRunnerWithTraits
-#else
-#define CREATE_IN_PROCESS_TASK_RUNNER \
- base::CreateSingleThreadTaskRunnerWithTraits
-#endif
-
-namespace content {
-
-namespace {
-
-video_capture::mojom::VideoCaptureService* g_service_override = nullptr;
-
-void BindInProcessInstance(
- mojo::PendingReceiver<video_capture::mojom::VideoCaptureService> receiver) {
- static base::NoDestructor<video_capture::VideoCaptureServiceImpl> service(
- std::move(receiver),
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}));
-}
-
-mojo::Remote<video_capture::mojom::VideoCaptureService>& GetUIThreadRemote() {
- static base::NoDestructor<
- mojo::Remote<video_capture::mojom::VideoCaptureService>>
- remote;
- return *remote;
-}
-
-// This is a custom traits type we use in conjunction with mojo::ReceiverSetBase
-// so that all dispatched messages can be forwarded to the currently bound UI
-// thread Remote.
-struct ForwardingImplRefTraits {
- using PointerType = void*;
- static bool IsNull(PointerType) { return false; }
- static video_capture::mojom::VideoCaptureService* GetRawPointer(PointerType) {
- return &GetVideoCaptureService();
- }
-};
-
-// If |GetVideoCaptureService()| is called from off the UI thread, return a
-// sequence-local Remote. Its corresponding receiver will be bound in this set,
-// forwarding to the current UI-thread Remote.
-void BindProxyRemoteOnUIThread(
- mojo::PendingReceiver<video_capture::mojom::VideoCaptureService> receiver) {
- static base::NoDestructor<mojo::ReceiverSetBase<
- mojo::Receiver<video_capture::mojom::VideoCaptureService,
- ForwardingImplRefTraits>,
- void>>
- receivers;
- receivers->Add(nullptr, std::move(receiver));
-}
-
-} // namespace
-
-video_capture::mojom::VideoCaptureService& GetVideoCaptureService() {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- static base::NoDestructor<base::SequenceLocalStorageSlot<
- mojo::Remote<video_capture::mojom::VideoCaptureService>>>
- storage;
- auto& remote = storage->GetOrCreateValue();
- if (!remote.is_bound()) {
- base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI})
- ->PostTask(FROM_HERE,
- base::BindOnce(&BindProxyRemoteOnUIThread,
- remote.BindNewPipeAndPassReceiver()));
- }
- return *remote.get();
- }
-
- if (g_service_override)
- return *g_service_override;
-
- auto& remote = GetUIThreadRemote();
- if (!remote.is_bound()) {
- auto receiver = remote.BindNewPipeAndPassReceiver();
- if (features::IsVideoCaptureServiceEnabledForBrowserProcess()) {
- auto dedicated_task_runner = CREATE_IN_PROCESS_TASK_RUNNER(
- base::TaskTraits({base::MayBlock(), base::WithBaseSyncPrimitives(),
- base::TaskPriority::BEST_EFFORT}),
- base::SingleThreadTaskRunnerThreadMode::DEDICATED);
- dedicated_task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&BindInProcessInstance, std::move(receiver)));
- } else {
- ServiceProcessHost::Launch(
- std::move(receiver),
- ServiceProcessHost::Options()
- .WithDisplayName("Video Capture")
- .WithSandboxType(service_manager::SANDBOX_TYPE_NO_SANDBOX)
-#if defined(OS_MACOSX)
- // On Mac, the service requires a CFRunLoop which is provided by a
- // UI message loop. See https://crbug.com/834581.
- .WithExtraCommandLineSwitches({switches::kMessageLoopTypeUi})
-#endif
- .Pass());
-
-#if !defined(OS_ANDROID)
- // On Android, we do not use automatic service shutdown, because when
- // shutting down the service, we lose caching of the supported formats,
- // and re-querying these can take several seconds on certain Android
- // devices.
- remote.set_idle_handler(
- base::TimeDelta::FromSeconds(5),
- base::BindRepeating(
- [](mojo::Remote<video_capture::mojom::VideoCaptureService>*
- remote) {
- video_capture::uma::LogVideoCaptureServiceEvent(
- video_capture::uma ::
- SERVICE_SHUTTING_DOWN_BECAUSE_NO_CLIENT);
- remote->reset();
- },
- &remote));
-#endif // !defined(OS_ANDROID)
-
- // Make sure the Remote is also reset in case of e.g. service crash so we
- // can restart it as needed.
- remote.reset_on_disconnect();
- }
- }
-
- return *remote.get();
-}
-
-void OverrideVideoCaptureServiceForTesting(
- video_capture::mojom::VideoCaptureService* service) {
- g_service_override = service;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/webrtc/webrtc_video_capture_browsertest.cc b/chromium/content/browser/webrtc/webrtc_video_capture_browsertest.cc
index e2ad80cef10..03ad9fb36c8 100644
--- a/chromium/content/browser/webrtc/webrtc_video_capture_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_video_capture_browsertest.cc
@@ -7,7 +7,7 @@
#include "build/build_config.h"
#include "content/browser/webrtc/webrtc_webcam_browsertest.h"
#include "content/public/browser/browser_child_process_host.h"
-#include "content/public/browser/video_capture_service.h"
+#include "content/public/browser/system_connector.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
@@ -16,6 +16,8 @@
#include "content/shell/browser/shell.h"
#include "media/base/media_switches.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/testing_controls.mojom.h"
namespace content {
@@ -79,8 +81,8 @@ IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureBrowserTest,
// Simulate crash in video capture process
video_capture::mojom::TestingControlsPtr service_controls;
- GetVideoCaptureService().BindControlsForTesting(
- mojo::MakeRequest(&service_controls));
+ GetSystemConnector()->BindInterface(video_capture::mojom::kServiceName,
+ mojo::MakeRequest(&service_controls));
service_controls->Crash();
// Wait for video element to turn black
diff --git a/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc b/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
index 9c76c55d9d9..2dee5d94b66 100644
--- a/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
@@ -10,7 +10,7 @@
#include "cc/base/math_util.h"
#include "components/viz/common/gpu/context_provider.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/video_capture_service.h"
+#include "content/public/browser/system_connector.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -26,8 +26,10 @@
#include "media/capture/video/shared_memory_handle_provider.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/service_manager/public/cpp/connector.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "services/video_capture/public/mojom/scoped_access_permission.mojom.h"
#include "services/video_capture/public/mojom/virtual_device.mojom.h"
@@ -393,11 +395,11 @@ class SharedMemoryDeviceExerciser : public VirtualDeviceExerciser,
base::WeakPtrFactory<SharedMemoryDeviceExerciser> weak_factory_{this};
};
-// Integration test that obtains a connection to the video capture service. It
-// It then registers a virtual device at the service and feeds frames to it. It
-// opens the virtual device in a <video> element on a test page and verifies
-// that the element plays in the expected dimensions and the pixel content on
-// the element changes.
+// Integration test that obtains a connection to the video capture service via
+// the Browser process' service manager. It then registers a virtual device at
+// the service and feeds frames to it. It opens the virtual device in a <video>
+// element on a test page and verifies that the element plays in the expected
+// dimenstions and the pixel content on the element changes.
class WebRtcVideoCaptureServiceBrowserTest : public ContentBrowserTest {
public:
WebRtcVideoCaptureServiceBrowserTest()
@@ -411,14 +413,8 @@ class WebRtcVideoCaptureServiceBrowserTest : public ContentBrowserTest {
void AddVirtualDeviceAndStartCapture(VirtualDeviceExerciser* device_exerciser,
base::OnceClosure finish_test_cb) {
DCHECK(virtual_device_thread_.task_runner()->RunsTasksInCurrentSequence());
-
- main_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(
- [](video_capture::mojom::DeviceFactoryRequest request) {
- GetVideoCaptureService().ConnectToDeviceFactory(
- std::move(request));
- },
- mojo::MakeRequest(&factory_)));
+ connector_->BindInterface(video_capture::mojom::kServiceName, &provider_);
+ provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_));
media::VideoCaptureDeviceInfo info;
info.descriptor.device_id = kVirtualDeviceId;
@@ -461,6 +457,7 @@ class WebRtcVideoCaptureServiceBrowserTest : public ContentBrowserTest {
LOG(INFO) << "Shutting down virtual device";
device_exerciser->ShutDown();
factory_ = nullptr;
+ provider_ = nullptr;
weak_factory_.InvalidateWeakPtrs();
std::move(continuation).Run();
}
@@ -500,10 +497,16 @@ class WebRtcVideoCaptureServiceBrowserTest : public ContentBrowserTest {
void Initialize() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
+ auto* connector = GetSystemConnector();
+ ASSERT_TRUE(connector);
+ // We need to clone it so that we can use the clone on a different thread.
+ connector_ = connector->Clone();
}
base::Thread virtual_device_thread_;
scoped_refptr<base::TaskRunner> main_task_runner_;
+ std::unique_ptr<service_manager::Connector> connector_;
private:
base::TimeDelta CalculateTimeSinceFirstInvocation() {
@@ -513,6 +516,7 @@ class WebRtcVideoCaptureServiceBrowserTest : public ContentBrowserTest {
}
base::test::ScopedFeatureList scoped_feature_list_;
+ video_capture::mojom::DeviceFactoryProviderPtr provider_;
video_capture::mojom::DeviceFactoryPtr factory_;
gfx::Size video_size_;
base::TimeTicks first_frame_time_;
diff --git a/chromium/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc b/chromium/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
index aa96d377646..7a991574051 100644
--- a/chromium/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_video_capture_service_enumeration_browsertest.cc
@@ -6,7 +6,7 @@
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/video_capture_service.h"
+#include "content/public/browser/system_connector.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -16,8 +16,11 @@
#include "media/base/media_switches.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/service_manager/public/cpp/connector.h"
#include "services/video_capture/public/cpp/mock_producer.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
@@ -72,18 +75,18 @@ class WebRtcVideoCaptureServiceEnumerationBrowserTest
~WebRtcVideoCaptureServiceEnumerationBrowserTest() override {}
void ConnectToService() {
+ connector_->BindInterface(video_capture::mojom::kServiceName, &provider_);
video_capture::mojom::DevicesChangedObserverPtr observer;
devices_changed_observer_binding_.Bind(mojo::MakeRequest(&observer));
switch (GetParam().api_to_use) {
case ServiceApi::kSingleClient:
- GetVideoCaptureService().ConnectToDeviceFactory(
- mojo::MakeRequest(&factory_));
+ provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_));
factory_->RegisterVirtualDevicesChangedObserver(
std::move(observer),
false /*raise_event_if_virtual_devices_already_present*/);
break;
case ServiceApi::kMultiClient:
- GetVideoCaptureService().ConnectToVideoSourceProvider(
+ provider_->ConnectToVideoSourceProvider(
mojo::MakeRequest(&video_source_provider_));
video_source_provider_->RegisterVirtualDevicesChangedObserver(
std::move(observer),
@@ -163,6 +166,7 @@ class WebRtcVideoCaptureServiceEnumerationBrowserTest
void DisconnectFromService() {
factory_ = nullptr;
video_source_provider_ = nullptr;
+ provider_ = nullptr;
}
void EnumerateDevicesInRendererAndVerifyDeviceCount(
@@ -214,8 +218,13 @@ class WebRtcVideoCaptureServiceEnumerationBrowserTest
NavigateToURL(shell(),
GURL(embedded_test_server()->GetURL(kVideoCaptureHtmlFile)));
+
+ auto* connector = GetSystemConnector();
+ ASSERT_TRUE(connector);
+ connector_ = connector->Clone();
}
+ std::unique_ptr<service_manager::Connector> connector_;
std::map<std::string, video_capture::mojom::TextureVirtualDevicePtr>
texture_devices_by_id_;
std::map<std::string,
@@ -227,6 +236,7 @@ class WebRtcVideoCaptureServiceEnumerationBrowserTest
mojo::Binding<video_capture::mojom::DevicesChangedObserver>
devices_changed_observer_binding_;
base::test::ScopedFeatureList scoped_feature_list_;
+ video_capture::mojom::DeviceFactoryProviderPtr provider_;
video_capture::mojom::DeviceFactoryPtr factory_;
video_capture::mojom::VideoSourceProviderPtr video_source_provider_;
base::OnceClosure closure_to_be_called_on_devices_changed_;
diff --git a/chromium/content/browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc b/chromium/content/browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc
index 5b5ae1c4163..af48c410838 100644
--- a/chromium/content/browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_video_capture_shared_device_browsertest.cc
@@ -6,16 +6,19 @@
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
-#include "content/public/browser/video_capture_service.h"
+#include "content/public/browser/system_connector.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "media/base/media_switches.h"
+#include "services/service_manager/public/cpp/connector.h"
#include "services/video_capture/public/cpp/mock_receiver.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "services/video_capture/public/mojom/video_source.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -77,16 +80,18 @@ class WebRtcVideoCaptureSharedDeviceBrowserTest
~WebRtcVideoCaptureSharedDeviceBrowserTest() override {}
void OpenDeviceViaService() {
+ connector_->BindInterface(video_capture::mojom::kServiceName,
+ &device_factory_provider_);
switch (GetParam().api_to_use) {
case ServiceApi::kSingleClient:
- GetVideoCaptureService().ConnectToDeviceFactory(
+ device_factory_provider_->ConnectToDeviceFactory(
mojo::MakeRequest(&device_factory_));
device_factory_->GetDeviceInfos(base::BindOnce(
&WebRtcVideoCaptureSharedDeviceBrowserTest::OnDeviceInfosReceived,
weak_factory_.GetWeakPtr(), GetParam().buffer_type_to_request));
break;
case ServiceApi::kMultiClient:
- GetVideoCaptureService().ConnectToVideoSourceProvider(
+ device_factory_provider_->ConnectToVideoSourceProvider(
mojo::MakeRequest(&video_source_provider_));
video_source_provider_->GetSourceInfos(base::BindOnce(
&WebRtcVideoCaptureSharedDeviceBrowserTest::OnSourceInfosReceived,
@@ -125,11 +130,18 @@ class WebRtcVideoCaptureSharedDeviceBrowserTest
void Initialize() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
+ auto* connector = GetSystemConnector();
+ ASSERT_TRUE(connector);
+ // We need to clone it so that we can use the clone on a different thread.
+ connector_ = connector->Clone();
+
mock_receiver_ = std::make_unique<video_capture::MockReceiver>(
mojo::MakeRequest(&receiver_proxy_));
}
scoped_refptr<base::TaskRunner> main_task_runner_;
+ std::unique_ptr<service_manager::Connector> connector_;
std::unique_ptr<video_capture::MockReceiver> mock_receiver_;
private:
@@ -192,6 +204,7 @@ class WebRtcVideoCaptureSharedDeviceBrowserTest
}
base::test::ScopedFeatureList scoped_feature_list_;
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
// For single-client API case only
video_capture::mojom::DeviceFactoryPtr device_factory_;
diff --git a/chromium/content/public/browser/BUILD.gn b/chromium/content/public/browser/BUILD.gn
index c6bf6053793..a595c4aa6b3 100644
--- a/chromium/content/public/browser/BUILD.gn
+++ b/chromium/content/public/browser/BUILD.gn
@@ -334,7 +334,6 @@ jumbo_source_set("browser_sources") {
"url_loader_request_interceptor.h",
"video_capture_device_launcher.cc",
"video_capture_device_launcher.h",
- "video_capture_service.h",
"visibility.h",
"vpn_service_proxy.h",
"web_contents.cc",
@@ -399,7 +398,6 @@ jumbo_source_set("browser_sources") {
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
"//services/service_manager/public/cpp",
"//services/tracing/public/cpp",
- "//services/video_capture/public/mojom",
"//services/viz/public/interfaces",
"//third_party/webrtc/modules/desktop_capture",
diff --git a/chromium/content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h b/chromium/content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h
index 2f1f3a43933..46f10decfd6 100644
--- a/chromium/content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h
+++ b/chromium/content/public/browser/chromeos/delegate_to_browser_gpu_service_accelerator_factory.h
@@ -6,7 +6,7 @@
#define CONTENT_PUBLIC_BROWSER_CHROMEOS_DELEGATE_TO_BROWSER_GPU_SERVICE_ACCELERATOR_FACTORY_H_
#include "content/common/content_export.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace content {
diff --git a/chromium/content/public/browser/service_process_host.cc b/chromium/content/public/browser/service_process_host.cc
index e03e0f4dc17..c4ce6643e1b 100644
--- a/chromium/content/public/browser/service_process_host.cc
+++ b/chromium/content/public/browser/service_process_host.cc
@@ -3,8 +3,6 @@
// found in the LICENSE file.
#include "content/public/browser/service_process_host.h"
-
-#include "base/strings/utf_string_conversions.h"
#include "content/public/common/content_client.h"
namespace content {
@@ -22,12 +20,6 @@ ServiceProcessHost::Options& ServiceProcessHost::Options::WithSandboxType(
}
ServiceProcessHost::Options& ServiceProcessHost::Options::WithDisplayName(
- const std::string& name) {
- display_name = base::UTF8ToUTF16(name);
- return *this;
-}
-
-ServiceProcessHost::Options& ServiceProcessHost::Options::WithDisplayName(
const base::string16& name) {
display_name = name;
return *this;
@@ -45,13 +37,6 @@ ServiceProcessHost::Options& ServiceProcessHost::Options::WithChildFlags(
return *this;
}
-ServiceProcessHost::Options&
-ServiceProcessHost::Options::WithExtraCommandLineSwitches(
- std::vector<std::string> switches) {
- extra_switches = std::move(switches);
- return *this;
-}
-
ServiceProcessHost::Options ServiceProcessHost::Options::Pass() {
return std::move(*this);
}
diff --git a/chromium/content/public/browser/service_process_host.h b/chromium/content/public/browser/service_process_host.h
index 25d3b3e3f6e..0f76b8be798 100644
--- a/chromium/content/public/browser/service_process_host.h
+++ b/chromium/content/public/browser/service_process_host.h
@@ -6,7 +6,6 @@
#define CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_H_
#include <memory>
-#include <string>
#include <utility>
#include <vector>
@@ -59,7 +58,6 @@ class CONTENT_EXPORT ServiceProcessHost {
// Specifies the display name of the service process. This should generally
// be a human readable and meaningful application or service name and will
// appear in places like the system task viewer.
- Options& WithDisplayName(const std::string& name);
Options& WithDisplayName(const base::string16& name);
Options& WithDisplayName(int resource_id);
@@ -67,9 +65,6 @@ class CONTENT_EXPORT ServiceProcessHost {
// ChildProcessHost for flag definitions.
Options& WithChildFlags(int flags);
- // Specifies extra command line switches to append before launch.
- Options& WithExtraCommandLineSwitches(std::vector<std::string> switches);
-
// Passes the contents of this Options object to a newly returned Options
// value. This must be called when moving a built Options object into a call
// to |Launch()|.
@@ -78,7 +73,6 @@ class CONTENT_EXPORT ServiceProcessHost {
SandboxType sandbox_type = service_manager::SANDBOX_TYPE_UTILITY;
base::string16 display_name;
base::Optional<int> child_flags;
- std::vector<std::string> extra_switches;
};
// An interface which can be implemented and registered/unregistered with
diff --git a/chromium/content/public/browser/video_capture_service.h b/chromium/content/public/browser/video_capture_service.h
deleted file mode 100644
index 9753d1b67a1..00000000000
--- a/chromium/content/public/browser/video_capture_service.h
+++ /dev/null
@@ -1,31 +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 CONTENT_PUBLIC_BROWSER_VIDEO_CAPTURE_SERVICE_H_
-#define CONTENT_PUBLIC_BROWSER_VIDEO_CAPTURE_SERVICE_H_
-
-#include "content/common/content_export.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
-
-namespace content {
-
-// Acquires a VideoCaptureService interface connected either to an in-process
-// instance or an out-of-process instance. If out-of-process, the service
-// process is launched lazily as needed and shut down when idle.
-//
-// This is callable from any thread, though when called from off of the UI
-// thread, messages sent on the interface will incur an extra thread hop before
-// going to the service.
-CONTENT_EXPORT video_capture::mojom::VideoCaptureService&
-GetVideoCaptureService();
-
-// Provides an override for the reference returned by
-// |GetVideoCaptureService()|. Call again with null to cancel the override
-// before |service| is destroyed.
-CONTENT_EXPORT void OverrideVideoCaptureServiceForTesting(
- video_capture::mojom::VideoCaptureService* service);
-
-} // namespace content
-
-#endif // CONTENT_PUBLIC_BROWSER_VIDEO_CAPTURE_SERVICE_H_
diff --git a/chromium/content/renderer/loader/resource_dispatcher.cc b/chromium/content/renderer/loader/resource_dispatcher.cc
index 03bf4a8b7f5..e12289e5962 100644
--- a/chromium/content/renderer/loader/resource_dispatcher.cc
+++ b/chromium/content/renderer/loader/resource_dispatcher.cc
@@ -65,10 +65,13 @@ void CheckSchemeForReferrerPolicy(const network::ResourceRequest& request) {
net::URLRequest::
CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE) &&
request.referrer.SchemeIsCryptographic() &&
+ !url::Origin::Create(request.url).opaque() &&
!IsOriginSecure(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;
}
}
diff --git a/chromium/content/utility/services.cc b/chromium/content/utility/services.cc
index 39f3d532518..44e7b19cd5a 100644
--- a/chromium/content/utility/services.cc
+++ b/chromium/content/utility/services.cc
@@ -6,11 +6,7 @@
#include <utility>
-#include "base/no_destructor.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "content/public/utility/content_utility_client.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
-#include "services/video_capture/video_capture_service_impl.h"
namespace content {
@@ -29,13 +25,6 @@ void HandleServiceRequestOnIOThread(
}
void HandleServiceRequestOnMainThread(mojo::GenericPendingReceiver receiver) {
- if (auto video_capture_receiver =
- receiver.As<video_capture::mojom::VideoCaptureService>()) {
- static base::NoDestructor<video_capture::VideoCaptureServiceImpl> service(
- std::move(video_capture_receiver), base::ThreadTaskRunnerHandle::Get());
- return;
- }
-
// If the request was handled already, we should not reach this point.
DCHECK(receiver.is_valid());
GetContentClient()->utility()->RunMainThreadService(std::move(receiver));
diff --git a/chromium/content/utility/utility_service_factory.cc b/chromium/content/utility/utility_service_factory.cc
index e4c8405fb17..e9c336020ea 100644
--- a/chromium/content/utility/utility_service_factory.cc
+++ b/chromium/content/utility/utility_service_factory.cc
@@ -32,6 +32,8 @@
#include "services/tracing/public/cpp/tracing_features.h"
#include "services/tracing/public/mojom/constants.mojom.h"
#include "services/tracing/tracing_service.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/service_impl.h"
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "media/cdm/cdm_adapter_factory.h" // nogncheck
@@ -166,6 +168,9 @@ void UtilityServiceFactory::RunService(
std::move(network_registry_),
base::SequencedTaskRunnerHandle::Get()));
return;
+ } else if (service_name == video_capture::mojom::kServiceName) {
+ service = std::make_unique<video_capture::ServiceImpl>(
+ std::move(request), base::ThreadTaskRunnerHandle::Get());
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
else if (service_name == media::mojom::kCdmServiceName) {
diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
index 0a82196539d..56e789f4329 100644
--- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
+++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
@@ -11,8 +11,8 @@
#include "base/files/file_path.h"
#include "chromeos/services/media_perception/public/mojom/media_perception_service.mojom.h"
#include "extensions/common/api/media_perception_private.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
+#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace content {
@@ -40,12 +40,12 @@ class MediaPerceptionAPIDelegate {
const api::media_perception_private::ComponentType& type,
LoadCrOSComponentCallback load_callback) = 0;
- // Provides an interface to the Video Capture service (started lazily by the
- // browser) to connect the MediaPerceptionService to it and establish a direct
- // Mojo IPC-based connection.
- virtual void BindVideoSourceProvider(
- mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider>
- receiver) = 0;
+ // Provides an interface to the VideoCaptureService (started lazily by the
+ // Chrome service manager) to connect the MediaPerceptionService to it and
+ // establish a direct Mojo IPC-based connection.
+ // |provider| is owned by the caller.
+ virtual void BindDeviceFactoryProviderToVideoCaptureService(
+ video_capture::mojom::DeviceFactoryProviderPtr* provider) = 0;
// Provides an interface to set a handler for an incoming
// MediaPerceptionRequest.
diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc
index f73afc87c24..e555a53d175 100644
--- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc
+++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc
@@ -11,6 +11,8 @@
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/media_analytics/media_analytics_client.h"
#include "chromeos/dbus/upstart/upstart_client.h"
@@ -23,11 +25,14 @@
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace extensions {
namespace {
+const int kStartupDelayMs = 1000;
+
extensions::api::media_perception_private::State GetStateForServiceError(
const extensions::api::media_perception_private::ServiceError
service_error) {
@@ -96,7 +101,9 @@ class MediaPerceptionAPIManager::MediaPerceptionControllerClient
void ConnectToVideoCaptureService(
video_capture::mojom::VideoSourceProviderRequest request) override {
DCHECK(delegate_) << "Delegate not set.";
- delegate_->BindVideoSourceProvider(std::move(request));
+ delegate_->BindDeviceFactoryProviderToVideoCaptureService(
+ &device_factory_provider_);
+ device_factory_provider_->ConnectToVideoSourceProvider(std::move(request));
}
private:
@@ -108,6 +115,10 @@ class MediaPerceptionAPIManager::MediaPerceptionControllerClient
chromeos::media_perception::mojom::MediaPerceptionControllerClient>
binding_;
+ // Bound to the VideoCaptureService to establish the connection to the
+ // media analytics process.
+ video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
+
DISALLOW_COPY_AND_ASSIGN(MediaPerceptionControllerClient);
};
@@ -373,7 +384,14 @@ void MediaPerceptionAPIManager::UpstartStartProcessCallback(
return;
}
- SendMojoInvitation(std::move(callback));
+ // TODO(crbug.com/1003968): Look into using
+ // ObjectProxy::WaitForServiceToBeAvailable instead, since a timeout is
+ // inherently not deterministic, even if it works in practice.
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&MediaPerceptionAPIManager::SendMojoInvitation,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
+ base::TimeDelta::FromMilliseconds(kStartupDelayMs));
}
void MediaPerceptionAPIManager::SendMojoInvitation(
diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
index 76ecfa5b798..51c3644bc63 100644
--- a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
+++ b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
@@ -48,9 +48,8 @@ class TestMediaPerceptionAPIDelegate : public MediaPerceptionAPIDelegate {
base::BindOnce(std::move(load_callback), false, base::FilePath()));
}
- void BindVideoSourceProvider(
- mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
- override {
+ void BindDeviceFactoryProviderToVideoCaptureService(
+ video_capture::mojom::DeviceFactoryProviderPtr* provider) override {
NOTIMPLEMENTED();
}
diff --git a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
index 7dade372570..e5f9ae51104 100644
--- a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
+++ b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -419,6 +419,11 @@ ui::AXTree::Selection AutomationAXTreeWrapper::GetUnignoredSelection() {
return unignored_selection;
}
+ui::AXNode* AutomationAXTreeWrapper::GetUnignoredNodeFromId(int32_t id) {
+ ui::AXNode* node = tree_.GetFromId(id);
+ return (node && !node->IsIgnored()) ? node : nullptr;
+}
+
// static
std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
AutomationAXTreeWrapper::GetChildTreeIDReverseMap() {
@@ -427,7 +432,7 @@ AutomationAXTreeWrapper::GetChildTreeIDReverseMap() {
return *child_tree_id_reverse_map;
}
-void AutomationAXTreeWrapper::OnNodeDataWillChange(
+void AutomationAXTreeWrapper::OnNodeDataChanged(
ui::AXTree* tree,
const ui::AXNodeData& old_node_data,
const ui::AXNodeData& new_node_data) {
diff --git a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
index 1065abf90e0..c0cb83337ef 100644
--- a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
+++ b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
@@ -27,6 +27,9 @@ class AutomationAXTreeWrapper : public ui::AXTreeObserver {
// child trees, if any.
static AutomationAXTreeWrapper* GetParentOfTreeId(ui::AXTreeID tree_id);
+ static std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
+ GetChildTreeIDReverseMap();
+
ui::AXTreeID tree_id() const { return tree_id_; }
ui::AXTree* tree() { return &tree_; }
AutomationInternalCustomBindings* owner() { return owner_; }
@@ -49,14 +52,15 @@ class AutomationAXTreeWrapper : public ui::AXTreeObserver {
ui::AXTree::Selection GetUnignoredSelection();
- static std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
- GetChildTreeIDReverseMap();
+ // Returns an AXNode from the underlying tree if it both exists and is not
+ // ignored.
+ ui::AXNode* GetUnignoredNodeFromId(int32_t id);
private:
// AXTreeObserver overrides.
- void OnNodeDataWillChange(ui::AXTree* tree,
- const ui::AXNodeData& old_node_data,
- const ui::AXNodeData& new_node_data) override;
+ void OnNodeDataChanged(ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) override;
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(ui::AXTree* tree,
bool root_changed,
diff --git a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index 91d70dff48e..98111cb0fdb 100644
--- a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -200,7 +200,7 @@ class NodeIDWrapper : public base::RefCountedThreadSafe<NodeIDWrapper> {
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node = tree_wrapper->GetUnignoredNodeFromId(node_id);
if (!node)
return;
@@ -256,7 +256,7 @@ class NodeIDPlusAttributeWrapper
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node = tree_wrapper->GetUnignoredNodeFromId(node_id);
if (!node)
return;
@@ -314,7 +314,7 @@ class NodeIDPlusRangeWrapper
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node = tree_wrapper->GetUnignoredNodeFromId(node_id);
if (!node)
return;
@@ -366,7 +366,7 @@ class NodeIDPlusStringBoolWrapper
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node = tree_wrapper->GetUnignoredNodeFromId(node_id);
if (!node)
return;
@@ -422,7 +422,7 @@ class NodeIDPlusDimensionsWrapper
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node = tree_wrapper->GetUnignoredNodeFromId(node_id);
if (!node)
return;
diff --git a/chromium/gpu/config/gpu_driver_bug_list.json b/chromium/gpu/config/gpu_driver_bug_list.json
index 3757a5cfc7a..e88ecea2445 100644
--- a/chromium/gpu/config/gpu_driver_bug_list.json
+++ b/chromium/gpu/config/gpu_driver_bug_list.json
@@ -3305,6 +3305,19 @@
"features": [
"disable_delayed_copy_nv12"
]
+ },
+ {
+ "id": 310,
+ "description": "Context lost recovery often fails on Mali on CrOS.",
+ "cr_bugs": [992286],
+ "os": {
+ "type": "chromeos"
+ },
+ "gl_vendor": "ARM.*",
+ "gl_renderer": ".*Mali-.*",
+ "features": [
+ "exit_on_context_lost"
+ ]
}
]
}
diff --git a/chromium/gpu/config/gpu_lists_version.h b/chromium/gpu/config/gpu_lists_version.h
index e45237ad52f..8a83655f9c0 100644
--- a/chromium/gpu/config/gpu_lists_version.h
+++ b/chromium/gpu/config/gpu_lists_version.h
@@ -3,6 +3,6 @@
#ifndef GPU_CONFIG_GPU_LISTS_VERSION_H_
#define GPU_CONFIG_GPU_LISTS_VERSION_H_
-#define GPU_LISTS_VERSION "f7668708a327d2ab897cd802bbbc8a8b67283ec8"
+#define GPU_LISTS_VERSION "89700f0d311d189a766a3532c1e6de2c94d429f9"
#endif // GPU_CONFIG_GPU_LISTS_VERSION_H_
diff --git a/chromium/infra/config/cr-buildbucket.cfg b/chromium/infra/config/cr-buildbucket.cfg
index 3d517cb9fe9..daa2b73196f 100644
--- a/chromium/infra/config/cr-buildbucket.cfg
+++ b/chromium/infra/config/cr-buildbucket.cfg
@@ -455,7 +455,7 @@ builder_mixins {
name: "chromeos-ci"
# All CrOS building is done via cross-compilation on linux hosts, so use the
# linux mixin.
- mixins: "linux"
+ mixins: "linux-xenial"
recipe {
properties: "mastername:chromium.chromiumos"
}
@@ -465,7 +465,7 @@ builder_mixins {
name: "chromeos-try"
# All CrOS building is done via cross-compilation on linux hosts, so use the
# linux mixin.
- mixins: "linux"
+ mixins: "linux-xenial"
recipe {
properties: "mastername:tryserver.chromium.chromiumos"
}
@@ -567,7 +567,7 @@ builder_mixins {
}
builder_mixins {
- name: "linux"
+ name: "linux-trusty"
dimensions: "os:Ubuntu-14.04"
}
@@ -629,7 +629,7 @@ builder_mixins {
builder_mixins {
name: "linux-try"
- mixins: "linux"
+ mixins: "linux-xenial"
recipe {
properties: "mastername:tryserver.chromium.linux"
}
@@ -660,7 +660,7 @@ builder_mixins {
builder_mixins {
name: "linux-ci"
- mixins: "linux"
+ mixins: "linux-xenial"
mixins: "goma-many-jobs-for-ci"
recipe {
properties: "mastername:chromium.linux"
@@ -670,7 +670,7 @@ builder_mixins {
# Counterpart of "linux-ci" that uses Goma RBE Prod server.
builder_mixins {
name: "linux-ci-goma-rbe-prod"
- mixins: "linux"
+ mixins: "linux-xenial"
mixins: "goma-rbe-prod-many-jobs-for-ci"
recipe {
properties: "mastername:chromium.linux"
@@ -1141,7 +1141,6 @@ buckets {
builders {
name: "android-code-coverage"
mixins: "code-coverage"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
dimensions: "cores:32"
@@ -1351,28 +1350,24 @@ buckets {
builders {
name: "chromeos-amd64-generic-asan-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "chromeos-amd64-generic-cfi-thin-lto-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "chromeos-amd64-generic-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "chromeos-amd64-generic-rel-vm-tests"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1380,7 +1375,6 @@ buckets {
builders {
name: "chromeos-arm-generic-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1388,7 +1382,6 @@ buckets {
name: "chromeos-vm-code-coverage"
mixins: "code-coverage"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
dimensions: "cores:32"
@@ -1398,7 +1391,6 @@ buckets {
builders {
name: "chromeos-kevin-rel-hw-tests"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1406,7 +1398,6 @@ buckets {
builders {
name: "chromeos-kevin-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1414,7 +1405,6 @@ buckets {
name: "linux-chromeos-code-coverage"
mixins: "code-coverage"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
dimensions: "cores:32"
@@ -1424,7 +1414,6 @@ buckets {
builders {
name: "linux-chromeos-dbg"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1432,7 +1421,6 @@ buckets {
name: "linux-chromeos-oobe-code-coverage"
mixins: "code-coverage"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
dimensions: "cores:32"
@@ -1445,14 +1433,12 @@ buckets {
builders {
name: "linux-chromeos-rel"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux ChromiumOS Full"
mixins: "chromeos-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1460,28 +1446,24 @@ buckets {
builders {
name: "Fuchsia ARM64"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "fuchsia-arm64-cast"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Fuchsia x64"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "fuchsia-x64-cast"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1510,7 +1492,6 @@ buckets {
builders {
name: "Cast Audio Linux"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
dimensions: "ssd:1"
}
@@ -1518,7 +1499,6 @@ buckets {
builders {
name: "Cast Linux"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
recipe {
properties_j: "$build/goma:{\"jobs\": 50}"
@@ -1530,7 +1510,6 @@ buckets {
mixins: "deterministic"
mixins: "linux-ci-goma-rbe-prod"
mixins: "builderless"
- mixins: "linux-xenial"
}
builders {
@@ -1538,7 +1517,6 @@ buckets {
mixins: "deterministic"
mixins: "linux-ci-goma-rbe-prod"
mixins: "builderless"
- mixins: "linux-xenial"
# This builder does local build, so needs large number of cores.
dimensions: "cores:32"
@@ -1547,13 +1525,11 @@ buckets {
builders {
name: "Leak Detection Linux"
mixins: "linux-ci-goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux ASan LSan Builder"
- mixins: "linux"
mixins: "memory-ci"
mixins: "linux-xenial"
mixins: "builderless"
@@ -1562,7 +1538,6 @@ buckets {
builders {
name: "Linux ASan LSan Tests (1)"
- mixins: "linux"
mixins: "memory-ci"
mixins: "linux-xenial"
mixins: "builderless"
@@ -1570,7 +1545,6 @@ buckets {
builders {
name: "Linux ASan Tests (sandboxed)"
- mixins: "linux"
mixins: "memory-ci"
mixins: "linux-xenial"
mixins: "builderless"
@@ -1580,19 +1554,18 @@ buckets {
name: "linux-trusty-rel"
mixins: "linux-ci-goma-rbe-prod"
mixins: "builderless"
+ mixins: "linux-trusty"
}
builders {
name: "Linux Builder"
mixins: "linux-ci-goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux Tests"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1606,7 +1579,6 @@ buckets {
builders {
name: "linux-blink-heap-concurrent-marking-tsan-rel"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "builderless"
mixins: "linux-xenial"
}
@@ -1614,7 +1586,6 @@ buckets {
builders {
name: "linux-blink-heap-verification"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1622,7 +1593,6 @@ buckets {
builders {
name: "linux-blink-heap-unified-gc"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1630,7 +1600,6 @@ buckets {
builders {
name: "linux_chromium_component_updater"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
recipe {
name: "findit/chromium/update_components"
@@ -1641,7 +1610,6 @@ buckets {
builders {
name: "linux-chromium-tests-staging-builder"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1649,7 +1617,6 @@ buckets {
builders {
name: "linux-chromium-tests-staging-tests"
mixins: "fyi-ci"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1657,21 +1624,18 @@ buckets {
builders {
name: "linux-gcc-rel"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "linux-jumbo-rel"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "linux-ozone-rel"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -1693,27 +1657,23 @@ buckets {
builders {
name: "Linux Builder (dbg)"
mixins: "linux-ci-goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux Builder (dbg)(32)"
mixins: "linux-ci-goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux Tests (dbg)(1)"
mixins: "linux-ci"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "Linux TSan Builder"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "memory-ci"
mixins: "builderless"
@@ -1721,7 +1681,6 @@ buckets {
builders {
name: "Linux TSan Tests"
- mixins: "linux"
mixins: "linux-xenial"
mixins: "memory-ci"
mixins: "builderless"
@@ -3901,48 +3860,40 @@ buckets {
builders {
mixins: "chromeos-try"
name: "chromeos-amd64-generic-cfi-thin-lto-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "chromeos-try"
- mixins: "linux-xenial"
mixins: "builderless"
name: "chromeos-amd64-generic-rel"
}
builders {
mixins: "chromeos-try"
- mixins: "linux-xenial"
mixins: "builderless"
name: "chromeos-arm-generic-rel"
}
builders {
mixins: "chromeos-try"
name: "chromeos-kevin-compile-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "chromeos-try"
name: "chromeos-kevin-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "chromeos-try"
- mixins: "linux-xenial"
mixins: "builderless"
name: "linux-chromeos-compile-dbg"
}
builders {
mixins: "chromeos-try"
- mixins: "linux-xenial"
mixins: "builderless"
name: "linux-chromeos-dbg"
}
builders {
mixins: "chromeos-try"
- mixins: "linux-xenial"
mixins: "goma-j150"
mixins: "builderless"
name: "linux-chromeos-rel"
@@ -3951,18 +3902,15 @@ buckets {
builders {
mixins: "linux-try"
name: "cast_shell_audio_linux"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "cast_shell_linux"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
- mixins: "linux-xenial"
name: "chromium_presubmit"
mixins: "builderless"
recipe {
@@ -3982,7 +3930,6 @@ buckets {
recipe {
name: "closure_compilation"
}
- mixins: "linux-xenial"
mixins: "builderless"
}
@@ -3991,43 +3938,36 @@ buckets {
builders {
mixins: "linux-try"
name: "fuchsia_arm64"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "fuchsia-arm64-cast"
}
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "fuchsia-fyi-arm64-rel"
}
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "fuchsia-fyi-x64-dbg"
}
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "fuchsia-fyi-x64-rel"
}
builders {
mixins: "linux-try"
name: "fuchsia_x64"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "fuchsia-x64-cast"
}
builders {
@@ -4075,7 +4015,6 @@ buckets {
mixins: "linux-try"
mixins: "goma-rbe-prod"
name: "leak_detection_linux"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders { mixins: "linux-angle-try" name: "fuchsia-angle-rel" }
@@ -4094,38 +4033,32 @@ buckets {
builders {
mixins: "builderless"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "linux-blink-heap-concurrent-marking-tsan-rel"
}
builders {
mixins: "linux-try"
name: "linux-blink-heap-verification-try"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "goma-rbe-prod"
name: "linux-dcheck-off-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux-gcc-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux-jumbo-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "linux-libfuzzer-asan-rel"
mixins: "linux-try"
- mixins: "linux-xenial"
mixins: "builderless"
recipe {
name: "chromium_libfuzzer_trybot"
@@ -4135,14 +4068,12 @@ buckets {
mixins: "builderless"
mixins: "linux-try"
name: "linux-ozone-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "goma-rbe-prod"
name: "linux-webkit-msan-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
@@ -4150,24 +4081,20 @@ buckets {
# TODO(crbug.com/986191): re-enable RBE+ATS when the issue is fixed.
# mixins: "goma-rbe-prod-ats"
name: "linux_arm"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_chromium_analysis"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_chromium_archive_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
- mixins: "linux-xenial"
mixins: "goma-j150"
name: "linux_chromium_asan_rel_ng"
mixins: "builderless"
@@ -4176,7 +4103,6 @@ buckets {
builders {
mixins: "linux-try"
mixins: "goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
name: "linux_chromium_cfi_rel_ng"
dimensions: "cores:32"
@@ -4185,40 +4111,34 @@ buckets {
mixins: "linux-try"
mixins: "goma-j150"
name: "linux_chromium_chromeos_asan_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "goma-j150"
name: "linux_chromium_chromeos_msan_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "linux_chromium_clobber_deterministic",
mixins: "linux-try"
mixins: "deterministic"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_chromium_clobber_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_chromium_compile_dbg_32_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "linux-debug-cache"
mixins: "goma-j150"
- mixins: "linux-xenial"
mixins: "builderless"
name: "linux_chromium_compile_dbg_ng"
}
@@ -4226,7 +4146,6 @@ buckets {
mixins: "linux-try"
mixins: "goma-rbe-prod"
name: "linux_chromium_compile_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
@@ -4234,26 +4153,22 @@ buckets {
mixins: "goma-rbe-prod"
mixins: "linux-debug-cache"
mixins: "linux-try"
- mixins: "linux-xenial"
name: "linux_chromium_dbg_ng"
}
builders {
mixins: "linux-try"
mixins: "goma-rbe-prod-j150"
name: "linux_chromium_msan_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "goma-j150"
name: "linux-coverage-rel"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
- mixins: "linux-xenial"
mixins: "goma-j150"
mixins: "builderless"
name: "linux-rel"
@@ -4262,11 +4177,11 @@ buckets {
mixins: "linux-try"
mixins: "goma-rbe-prod-j150"
mixins: "builderless"
+ mixins: "linux-trusty"
name: "linux-trusty-rel"
}
builders {
mixins: "linux-try"
- mixins: "linux-xenial"
mixins: "goma-j150"
mixins: "builderless"
name: "linux_chromium_tsan_rel_ng"
@@ -4274,7 +4189,6 @@ buckets {
builders {
mixins: "linux-try"
name: "linux_chromium_ubsan_rel_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
@@ -4285,32 +4199,29 @@ buckets {
builders {
mixins: "linux-try"
name: "linux_layout_tests_composite_after_paint"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_layout_tests_layout_ng"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
mixins: "goma-rbe-prod"
name: "linux_mojo"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
mixins: "linux-try"
name: "linux_mojo_chromeos"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders { mixins: "linux-optional-gpu-try" name: "linux_optional_gpu_tests_rel" }
builders {
mixins: "linux-try"
mixins: "upload_clang"
+ mixins: "linux-trusty"
name: "linux_upload_clang"
dimensions: "cores:32"
}
@@ -4591,14 +4502,12 @@ buckets {
builders {
name: "linux-annotator-rel"
mixins: "linux-try"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
name: "linux_vr"
mixins: "linux-try"
mixins: "goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
@@ -4630,7 +4539,6 @@ buckets {
name: "layout_test_leak_detection"
mixins: "linux-try"
mixins: "goma-rbe-prod"
- mixins: "linux-xenial"
mixins: "builderless"
}
builders {
@@ -4652,7 +4560,6 @@ buckets {
# Blink try builders.
builders {
name: "linux-blink-rel"
- mixins: "linux"
mixins: "blink-try"
mixins: "linux-xenial"
mixins: "builderless"
@@ -4749,7 +4656,7 @@ buckets {
}
builders {
name: "WebRTC Chromium Linux Tester"
- mixins: "linux"
+ mixins: "linux-trusty"
}
# Mac
diff --git a/chromium/ios/chrome/browser/ui/dialogs/BUILD.gn b/chromium/ios/chrome/browser/ui/dialogs/BUILD.gn
index 1ae4f03ca40..ed148d8a047 100644
--- a/chromium/ios/chrome/browser/ui/dialogs/BUILD.gn
+++ b/chromium/ios/chrome/browser/ui/dialogs/BUILD.gn
@@ -52,6 +52,8 @@ source_set("dialogs_internal") {
sources = [
"dialog_presenter.h",
"dialog_presenter.mm",
+ "java_script_dialog_metrics.cc",
+ "java_script_dialog_metrics.h",
"java_script_dialog_presenter_impl.h",
"java_script_dialog_presenter_impl.mm",
"nsurl_protection_space_util.h",
diff --git a/chromium/ios/chrome/test/earl_grey/BUILD.gn b/chromium/ios/chrome/test/earl_grey/BUILD.gn
index 79ec78648ee..9eb1ac2efc8 100644
--- a/chromium/ios/chrome/test/earl_grey/BUILD.gn
+++ b/chromium/ios/chrome/test/earl_grey/BUILD.gn
@@ -254,6 +254,7 @@ source_set("test_support") {
"//ios/chrome/browser/ui/tab_grid/grid:grid_ui_constants",
"//ios/chrome/browser/ui/table_view/cells",
"//ios/chrome/browser/ui/toolbar/buttons",
+ "//ios/chrome/browser/ui/toolbar/keyboard_assist",
"//ios/chrome/browser/ui/toolbar/public",
"//ios/chrome/browser/ui/util",
"//ios/chrome/test/app:test_support",
@@ -351,6 +352,7 @@ source_set("eg_app_support+eg2") {
"//ios/chrome/browser/ui/static_content",
"//ios/chrome/browser/ui/tab_grid:tab_grid_ui_constants",
"//ios/chrome/browser/ui/tab_grid/grid:grid_ui_constants",
+ "//ios/chrome/browser/ui/toolbar/keyboard_assist",
"//ios/chrome/browser/ui/toolbar/public",
"//ios/chrome/browser/ui/util",
"//ios/chrome/test/app:test_support",
diff --git a/chromium/media/blink/webmediaplayer_impl.cc b/chromium/media/blink/webmediaplayer_impl.cc
index 17c6dbe0452..0fe502b37df 100644
--- a/chromium/media/blink/webmediaplayer_impl.cc
+++ b/chromium/media/blink/webmediaplayer_impl.cc
@@ -400,8 +400,9 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
media_metrics_provider_->SetIsAdMedia();
#if defined(OS_ANDROID)
- renderer_factory_selector_->SetRemotePlayStateChangeCB(base::BindRepeating(
- &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_));
+ renderer_factory_selector_->SetRemotePlayStateChangeCB(
+ BindToCurrentLoop(base::BindRepeating(
+ &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_)));
#endif // defined (OS_ANDROID)
}
@@ -2466,6 +2467,7 @@ void WebMediaPlayerImpl::FlingingStopped() {
void WebMediaPlayerImpl::OnRemotePlayStateChange(MediaStatus::State state) {
DCHECK(is_flinging_);
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
if (state == MediaStatus::State::PLAYING && Paused()) {
DVLOG(1) << __func__ << " requesting PLAY.";
diff --git a/chromium/media/gpu/vaapi/vp8_encoder.cc b/chromium/media/gpu/vaapi/vp8_encoder.cc
index fa1212f52fb..c2b4f03f753 100644
--- a/chromium/media/gpu/vaapi/vp8_encoder.cc
+++ b/chromium/media/gpu/vaapi/vp8_encoder.cc
@@ -162,6 +162,12 @@ void VP8Encoder::InitializeFrameHeader() {
// TODO(sprang): Make this dynamic. Value based on reference implementation
// in libyami (https://github.com/intel/libyami).
current_frame_hdr_.loopfilter_hdr.level = 19;
+
+ // b/138840822: Set mb_no_skip_coeff and loop_filter_adj_enable to 1 as a
+ // workaround of color artifacts issue with a kepler device hw decoder and
+ // ffmpeg sw decoder.
+ current_frame_hdr_.mb_no_skip_coeff = 1;
+ current_frame_hdr_.loopfilter_hdr.loop_filter_adj_enable = 1;
}
void VP8Encoder::UpdateFrameHeader(bool keyframe) {
diff --git a/chromium/media/mojo/services/mojo_cdm_service.cc b/chromium/media/mojo/services/mojo_cdm_service.cc
index 3334ac0f6d3..a49ac813b0f 100644
--- a/chromium/media/mojo/services/mojo_cdm_service.cc
+++ b/chromium/media/mojo/services/mojo_cdm_service.cc
@@ -60,7 +60,9 @@ void MojoCdmService::Initialize(const std::string& key_system,
const CdmConfig& cdm_config,
InitializeCallback callback) {
DVLOG(1) << __func__ << ": " << key_system;
- DCHECK(!cdm_);
+
+ CHECK(!has_initialize_been_called_) << "Initialize should only happen once";
+ has_initialize_been_called_ = true;
auto weak_this = weak_factory_.GetWeakPtr();
cdm_factory_->Create(
@@ -154,6 +156,7 @@ void MojoCdmService::OnCdmCreated(
return;
}
+ CHECK(!cdm_) << "CDM should only be created once.";
cdm_ = cdm;
if (context_) {
diff --git a/chromium/media/mojo/services/mojo_cdm_service.h b/chromium/media/mojo/services/mojo_cdm_service.h
index 09e00de20e4..71d5b593b83 100644
--- a/chromium/media/mojo/services/mojo_cdm_service.h
+++ b/chromium/media/mojo/services/mojo_cdm_service.h
@@ -101,6 +101,8 @@ class MEDIA_MOJO_EXPORT MojoCdmService : public mojom::ContentDecryptionModule {
// Callback for when |decryptor_| loses connectivity.
void OnDecryptorConnectionError();
+ bool has_initialize_been_called_ = false;
+
CdmFactory* cdm_factory_;
MojoCdmServiceContext* const context_ = nullptr;
scoped_refptr<::media::ContentDecryptionModule> cdm_;
diff --git a/chromium/services/content/public/cpp/navigable_contents_view.cc b/chromium/services/content/public/cpp/navigable_contents_view.cc
index 3c2036fa3f2..b2a150a9380 100644
--- a/chromium/services/content/public/cpp/navigable_contents_view.cc
+++ b/chromium/services/content/public/cpp/navigable_contents_view.cc
@@ -22,8 +22,6 @@
#endif // defined(TOOLKIT_VIEWS)
#if defined(USE_AURA)
-#include "ui/aura/client/focus_change_observer.h" // nogncheck
-#include "ui/aura/client/focus_client.h" // nogncheck
#include "ui/aura/layout_manager.h" // nogncheck
#include "ui/aura/window.h" // nogncheck
#endif
@@ -77,25 +75,14 @@ class LocalWindowLayoutManager : public aura::LayoutManager {
// Owns an Aura window which parents another Aura window in the same process,
// corresponding to a web contents view hosted in the process.
-class LocalViewHost : public views::NativeViewHost,
- public aura::WindowObserver,
- public aura::client::FocusChangeObserver {
+class LocalViewHost : public views::NativeViewHost {
public:
LocalViewHost(aura::Window* window, NavigableContents* contents)
: window_(window), contents_(contents) {
window_->SetLayoutManager(new LocalWindowLayoutManager(window_));
- window_->AddObserver(this);
-
- // We set focus behavior to |ALWAYS| to ensure that we receive window focus
- // change events when our hosted WebContents takes focus. We utilize this
- // change event to keep LocalViewHost and WebContents focus state in sync.
- SetFocusBehavior(FocusBehavior::ALWAYS);
}
- ~LocalViewHost() override {
- if (!window_destroyed_)
- window_->RemoveObserver(this);
- }
+ ~LocalViewHost() override = default;
// views::View:
void AddedToWidget() override {
@@ -116,54 +103,10 @@ class LocalViewHost : public views::NativeViewHost,
}
}
- // aura::WindowObserver:
- void OnWindowAddedToRootWindow(aura::Window* window) override {
- // Once our |window_| has been added to its root window, we can obtain a
- // reference to the root window's focus client which we observe to detect
- // window focus changed events.
- auto* focus_client = aura::client::GetFocusClient(window_);
- if (focus_client)
- focus_client->AddObserver(this);
- }
-
- void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* root_window) override {
- // We need to stop observing the root window's focus client before our
- // |window_| is removed. Otherwise, we will leak a pointer to LocalViewHost
- // to the focus client that will persist even after LocalViewHost is
- // destroyed. This will cause a crash when the focus client attempts to
- // notify our destroyed instance of focus changed events.
- auto* focus_client = aura::client::GetFocusClient(window_);
- if (focus_client)
- focus_client->RemoveObserver(this);
- }
-
- void OnWindowDestroying(aura::Window* window) override {
- window_->RemoveObserver(this);
- window_destroyed_ = true;
- }
-
- // aura::client::FocusChangeObserver:
- void OnWindowFocused(aura::Window* gained_focus,
- aura::Window* lost_focus) override {
- // We need to ensure that LocalViewHost's focus state is synced with that of
- // |window_|. This only needs to be done when gaining focus and when
- // LocalViewHost doesn't already have focus.
- if (!gained_focus || HasFocus())
- return;
-
- // When the window gaining focus is contained within |window_|, we need to
- // request focus on LocalHostView to remain in sync.
- if (window_->Contains(gained_focus))
- RequestFocus();
- }
-
private:
aura::Window* const window_;
NavigableContents* const contents_;
- bool window_destroyed_ = false;
-
DISALLOW_COPY_AND_ASSIGN(LocalViewHost);
};
diff --git a/chromium/services/network/mdns_responder.cc b/chromium/services/network/mdns_responder.cc
index a977bb62a87..63569ae6c18 100644
--- a/chromium/services/network/mdns_responder.cc
+++ b/chromium/services/network/mdns_responder.cc
@@ -36,6 +36,7 @@
#include "net/dns/record_rdata.h"
#include "net/socket/datagram_server_socket.h"
#include "net/socket/udp_server_socket.h"
+#include "services/network/public/cpp/features.h"
// TODO(qingsi): Several features to implement:
//
@@ -966,10 +967,13 @@ void MdnsResponderManager::OnMdnsQueryReceived(
// to handle only such records. Once we have expanded the API surface to
// include the service publishing, the handling logic should be unified.
const std::string qname = net::DNSDomainToString(query.qname());
- if (should_respond_to_generator_service_query_ &&
- qname == kMdnsNameGeneratorServiceInstanceName) {
- HandleMdnsNameGeneratorServiceQuery(query, recv_socket_handler_id);
- return;
+ if (base::FeatureList::IsEnabled(
+ features::kMdnsResponderGeneratedNameListing)) {
+ if (should_respond_to_generator_service_query_ &&
+ qname == kMdnsNameGeneratorServiceInstanceName) {
+ HandleMdnsNameGeneratorServiceQuery(query, recv_socket_handler_id);
+ return;
+ }
}
for (auto& responder : responders_)
diff --git a/chromium/services/network/mdns_responder_unittest.cc b/chromium/services/network/mdns_responder_unittest.cc
index dd8d31f583d..9796b22d686 100644
--- a/chromium/services/network/mdns_responder_unittest.cc
+++ b/chromium/services/network/mdns_responder_unittest.cc
@@ -16,6 +16,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_piece.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/bindings/connector.h"
#include "net/base/ip_address.h"
@@ -25,6 +26,7 @@
#include "net/dns/dns_util.h"
#include "net/dns/mock_mdns_socket_factory.h"
#include "net/dns/public/dns_protocol.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/mdns_responder.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -393,6 +395,8 @@ class MdnsResponderTest : public testing::Test {
MdnsResponderTest()
: failing_socket_factory_(
scoped_task_environment_.GetMainThreadTaskRunner()) {
+ feature_list_.InitAndEnableFeature(
+ features::kMdnsResponderGeneratedNameListing);
Reset();
}
@@ -484,6 +488,7 @@ class MdnsResponderTest : public testing::Test {
scoped_task_environment_.FastForwardBy(duration);
}
+ base::test::ScopedFeatureList feature_list_;
base::test::ScopedTaskEnvironment scoped_task_environment_{
base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME};
// Overrides the current thread task runner, so we can simulate the passage
diff --git a/chromium/services/network/public/cpp/features.cc b/chromium/services/network/public/cpp/features.cc
index d5a2195fe6e..01d581c5dda 100644
--- a/chromium/services/network/public/cpp/features.cc
+++ b/chromium/services/network/public/cpp/features.cc
@@ -99,6 +99,13 @@ const base::Feature kProactivelyThrottleLowPriorityRequests{
const base::Feature kCrossOriginEmbedderPolicy{
"CrossOriginEmbedderPolicy", base::FEATURE_DISABLED_BY_DEFAULT};
+// If this feature is enabled, the mDNS responder service responds to queries
+// for TXT records associated with
+// "Generated-Names._mdns_name_generator._udp.local" with a list of generated
+// mDNS names (random UUIDs) in the TXT record data.
+const base::Feature kMdnsResponderGeneratedNameListing{
+ "MdnsResponderGeneratedNameListing", base::FEATURE_DISABLED_BY_DEFAULT};
+
bool ShouldEnableOutOfBlinkCors() {
// OOR-CORS requires NetworkService.
if (!base::FeatureList::IsEnabled(features::kNetworkService))
diff --git a/chromium/services/network/public/cpp/features.h b/chromium/services/network/public/cpp/features.h
index a6cba6481fa..ae832475603 100644
--- a/chromium/services/network/public/cpp/features.h
+++ b/chromium/services/network/public/cpp/features.h
@@ -39,6 +39,8 @@ COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kProactivelyThrottleLowPriorityRequests;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kCrossOriginEmbedderPolicy;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kMdnsResponderGeneratedNameListing;
COMPONENT_EXPORT(NETWORK_CPP) bool ShouldEnableOutOfBlinkCors();
diff --git a/chromium/services/video_capture/BUILD.gn b/chromium/services/video_capture/BUILD.gn
index 3a0ba307d49..e8aa895f36b 100644
--- a/chromium/services/video_capture/BUILD.gn
+++ b/chromium/services/video_capture/BUILD.gn
@@ -2,14 +2,30 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//services/service_manager/public/cpp/service_executable.gni")
import("//testing/test.gni")
+service_executable("video_capture") {
+ sources = [
+ "service_main.cc",
+ ]
+
+ deps = [
+ ":lib",
+ "//mojo/public/cpp/system",
+ "//services/video_capture/public/cpp",
+ "//services/video_capture/public/mojom",
+ ]
+}
+
source_set("lib") {
sources = [
"broadcasting_receiver.cc",
"broadcasting_receiver.h",
"device_factory_media_to_mojo_adapter.cc",
"device_factory_media_to_mojo_adapter.h",
+ "device_factory_provider_impl.cc",
+ "device_factory_provider_impl.h",
"device_media_to_mojo_adapter.cc",
"device_media_to_mojo_adapter.h",
"push_video_stream_subscription_impl.cc",
@@ -18,14 +34,14 @@ source_set("lib") {
"receiver_mojo_to_media_adapter.h",
"scoped_access_permission_media_to_mojo_adapter.cc",
"scoped_access_permission_media_to_mojo_adapter.h",
+ "service_impl.cc",
+ "service_impl.h",
"shared_memory_virtual_device_mojo_adapter.cc",
"shared_memory_virtual_device_mojo_adapter.h",
"testing_controls_impl.cc",
"testing_controls_impl.h",
"texture_virtual_device_mojo_adapter.cc",
"texture_virtual_device_mojo_adapter.h",
- "video_capture_service_impl.cc",
- "video_capture_service_impl.h",
"video_source_impl.cc",
"video_source_impl.h",
"video_source_provider_impl.cc",
@@ -43,6 +59,7 @@ source_set("lib") {
"//media/capture/mojom:image_capture",
"//media/mojo/common:common",
"//mojo/public/cpp/system",
+ "//services/service_manager/public/cpp",
"//services/video_capture/public/cpp",
"//services/video_capture/public/mojom",
"//services/video_capture/public/mojom:constants",
@@ -61,6 +78,10 @@ source_set("tests") {
sources = [
"broadcasting_receiver_unittest.cc",
"device_media_to_mojo_adapter_unittest.cc",
+ "test/device_factory_provider_connectortest.cc",
+ "test/device_factory_provider_test.cc",
+ "test/device_factory_provider_test.h",
+ "test/device_factory_provider_unittest.cc",
"test/fake_device_descriptor_test.cc",
"test/fake_device_descriptor_test.h",
"test/fake_device_descriptor_unittest.cc",
@@ -73,22 +94,26 @@ source_set("tests") {
"test/mock_device_unittest.cc",
"test/mock_devices_changed_observer.cc",
"test/mock_devices_changed_observer.h",
- "test/service_lifecycle_unittest.cc",
- "test/video_capture_service_test.cc",
- "test/video_capture_service_test.h",
- "test/video_capture_service_unittest.cc",
"test/virtual_device_unittest.cc",
"texture_virtual_device_mojo_adapter_unittest.cc",
]
deps = [
":lib",
+ ":video_capture",
"//base/test:test_support",
"//media/capture:test_support",
"//media/capture/mojom:video_capture",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/cpp/test:test_support",
+ "//services/video_capture/public/cpp:manifest",
"//services/video_capture/public/cpp:mocks",
"//testing/gmock",
"//testing/gtest",
"//ui/gfx:test_support",
]
+
+ data_deps = [
+ ":video_capture",
+ ]
}
diff --git a/chromium/services/video_capture/device_factory.h b/chromium/services/video_capture/device_factory.h
index 0898a1a21a8..4fe83766339 100644
--- a/chromium/services/video_capture/device_factory.h
+++ b/chromium/services/video_capture/device_factory.h
@@ -5,6 +5,7 @@
#ifndef SERVICES_VIDEO_CAPTURE_DEVICE_FACTORY_H_
#define SERVICES_VIDEO_CAPTURE_DEVICE_FACTORY_H_
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#if defined(OS_CHROMEOS)
@@ -15,6 +16,8 @@ namespace video_capture {
class DeviceFactory : public mojom::DeviceFactory {
public:
+ virtual void SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) = 0;
#if defined(OS_CHROMEOS)
virtual void BindCrosImageCaptureRequest(
cros::mojom::CrosImageCaptureRequest request) = 0;
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 59416448e89..5b8e3f02d59 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -99,6 +99,11 @@ DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
+void DeviceFactoryMediaToMojoAdapter::SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+ service_ref_ = std::move(service_ref);
+}
+
void DeviceFactoryMediaToMojoAdapter::GetDeviceInfos(
GetDeviceInfosCallback callback) {
capture_system_->GetDeviceInfosAsync(
@@ -165,6 +170,7 @@ void DeviceFactoryMediaToMojoAdapter::CreateAndAddNewDevice(
const std::string& device_id,
mojom::DeviceRequest device_request,
CreateDeviceCallback callback) {
+ DCHECK(service_ref_);
std::unique_ptr<media::VideoCaptureDevice> media_device =
capture_system_->CreateDevice(device_id);
if (media_device == nullptr) {
@@ -178,11 +184,11 @@ void DeviceFactoryMediaToMojoAdapter::CreateAndAddNewDevice(
#if defined(OS_CHROMEOS)
device_entry.device = std::make_unique<DeviceMediaToMojoAdapter>(
- std::move(media_device), jpeg_decoder_factory_callback_,
- jpeg_decoder_task_runner_);
+ service_ref_->Clone(), std::move(media_device),
+ jpeg_decoder_factory_callback_, jpeg_decoder_task_runner_);
#else
- device_entry.device =
- std::make_unique<DeviceMediaToMojoAdapter>(std::move(media_device));
+ device_entry.device = std::make_unique<DeviceMediaToMojoAdapter>(
+ service_ref_->Clone(), std::move(media_device));
#endif // defined(OS_CHROMEOS)
device_entry.binding = std::make_unique<mojo::Binding<mojom::Device>>(
device_entry.device.get(), std::move(device_request));
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
index 28095f25e7c..07db761c705 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -10,6 +10,7 @@
#include "media/capture/video/video_capture_device_client.h"
#include "media/capture/video/video_capture_system.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/device_factory.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
@@ -40,6 +41,8 @@ class DeviceFactoryMediaToMojoAdapter : public DeviceFactory {
~DeviceFactoryMediaToMojoAdapter() override;
// DeviceFactory implementation.
+ void SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) override;
void GetDeviceInfos(GetDeviceInfosCallback callback) override;
void CreateDevice(const std::string& device_id,
mojom::DeviceRequest device_request,
@@ -80,6 +83,7 @@ class DeviceFactoryMediaToMojoAdapter : public DeviceFactory {
CreateDeviceCallback callback);
void OnClientConnectionErrorOrClose(const std::string& device_id);
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
const std::unique_ptr<media::VideoCaptureSystem> capture_system_;
std::map<std::string, ActiveDeviceEntry> active_devices_by_id_;
diff --git a/chromium/services/video_capture/video_capture_service_impl.cc b/chromium/services/video_capture/device_factory_provider_impl.cc
index b6a72388212..154a045edf3 100644
--- a/chromium/services/video_capture/video_capture_service_impl.cc
+++ b/chromium/services/video_capture/device_factory_provider_impl.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/video_capture/video_capture_service_impl.h"
+#include "services/video_capture/device_factory_provider_impl.h"
#include <utility>
@@ -15,9 +15,7 @@
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video/video_capture_buffer_tracker.h"
#include "media/capture/video/video_capture_system_impl.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/video_capture/device_factory_media_to_mojo_adapter.h"
-#include "services/video_capture/testing_controls_impl.h"
#include "services/video_capture/video_source_provider_impl.h"
#include "services/video_capture/virtual_device_enabled_device_factory.h"
#include "services/viz/public/cpp/gpu/gpu.h"
@@ -33,7 +31,7 @@ namespace video_capture {
// GetTaskRunner() via WeakPtrs provided via GetWeakPtr(). To this end,
// GetTaskRunner() and GetWeakPtr() can be called from any sequence, typically
// the same as the one calling the constructor.
-class VideoCaptureServiceImpl::GpuDependenciesContext {
+class DeviceFactoryProviderImpl::GpuDependenciesContext {
public:
GpuDependenciesContext() : weak_factory_for_gpu_io_thread_(this) {
gpu_io_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
@@ -84,13 +82,19 @@ class VideoCaptureServiceImpl::GpuDependenciesContext {
base::WeakPtrFactory<GpuDependenciesContext> weak_factory_for_gpu_io_thread_;
};
-VideoCaptureServiceImpl::VideoCaptureServiceImpl(
- mojo::PendingReceiver<mojom::VideoCaptureService> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
- : receiver_(this, std::move(receiver)),
- ui_task_runner_(std::move(ui_task_runner)) {}
+DeviceFactoryProviderImpl::DeviceFactoryProviderImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ base::OnceClosure request_service_quit_asap_cb)
+ : ui_task_runner_(std::move(ui_task_runner)),
+ request_service_quit_asap_cb_(std::move(request_service_quit_asap_cb)) {
+ // Unretained |this| is safe because |factory_bindings_| is owned by
+ // |this|.
+ factory_bindings_.set_connection_error_handler(base::BindRepeating(
+ &DeviceFactoryProviderImpl::OnFactoryOrSourceProviderClientDisconnected,
+ base::Unretained(this)));
+}
-VideoCaptureServiceImpl::~VideoCaptureServiceImpl() {
+DeviceFactoryProviderImpl::~DeviceFactoryProviderImpl() {
factory_bindings_.CloseAllBindings();
device_factory_.reset();
if (gpu_dependencies_context_) {
@@ -99,8 +103,13 @@ VideoCaptureServiceImpl::~VideoCaptureServiceImpl() {
}
}
+void DeviceFactoryProviderImpl::SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+ service_ref_ = std::move(service_ref);
+}
+
#if defined(OS_CHROMEOS)
-void VideoCaptureServiceImpl::InjectGpuDependencies(
+void DeviceFactoryProviderImpl::InjectGpuDependencies(
mojom::AcceleratorFactoryPtr accelerator_factory) {
LazyInitializeGpuDependenciesContext();
gpu_dependencies_context_->GetTaskRunner()->PostTask(
@@ -108,46 +117,47 @@ void VideoCaptureServiceImpl::InjectGpuDependencies(
gpu_dependencies_context_->GetWeakPtr(),
accelerator_factory.PassInterface()));
}
-
-void VideoCaptureServiceImpl::BindCrosImageCapture(
- mojo::PendingReceiver<cros::mojom::CrosImageCapture> receiver) {
- CHECK(device_factory_);
- device_factory_->BindCrosImageCaptureRequest(std::move(receiver));
-}
#endif // defined(OS_CHROMEOS)
-void VideoCaptureServiceImpl::ConnectToDeviceFactory(
+void DeviceFactoryProviderImpl::ConnectToDeviceFactory(
mojom::DeviceFactoryRequest request) {
+ DCHECK(service_ref_);
LazyInitializeDeviceFactory();
factory_bindings_.AddBinding(device_factory_.get(), std::move(request));
}
-void VideoCaptureServiceImpl::ConnectToVideoSourceProvider(
+void DeviceFactoryProviderImpl::ConnectToVideoSourceProvider(
mojom::VideoSourceProviderRequest request) {
LazyInitializeVideoSourceProvider();
video_source_provider_->AddClient(std::move(request));
}
-void VideoCaptureServiceImpl::SetRetryCount(int32_t count) {
+void DeviceFactoryProviderImpl::ShutdownServiceAsap() {
+ if (request_service_quit_asap_cb_)
+ std::move(request_service_quit_asap_cb_).Run();
+}
+
+void DeviceFactoryProviderImpl::SetRetryCount(int32_t count) {
#if defined(OS_MACOSX)
media::VideoCaptureDeviceFactoryMac::SetGetDeviceDescriptorsRetryCount(count);
#endif
}
-void VideoCaptureServiceImpl::BindControlsForTesting(
- mojo::PendingReceiver<mojom::TestingControls> receiver) {
- mojo::MakeSelfOwnedReceiver(std::make_unique<TestingControlsImpl>(),
- std::move(receiver));
-}
-
-void VideoCaptureServiceImpl::LazyInitializeGpuDependenciesContext() {
+void DeviceFactoryProviderImpl::LazyInitializeGpuDependenciesContext() {
if (!gpu_dependencies_context_)
gpu_dependencies_context_ = std::make_unique<GpuDependenciesContext>();
}
-void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
- if (device_factory_)
+void DeviceFactoryProviderImpl::LazyInitializeDeviceFactory() {
+ DCHECK(service_ref_);
+
+ // Factory may already exist but if no client was connected it will not have a
+ // ServiceRef.
+ if (device_factory_) {
+ if (factory_bindings_.empty())
+ device_factory_->SetServiceRef(service_ref_->Clone());
return;
+ }
LazyInitializeGpuDependenciesContext();
@@ -175,9 +185,11 @@ void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
std::make_unique<DeviceFactoryMediaToMojoAdapter>(
std::move(video_capture_system)));
#endif // defined(OS_CHROMEOS)
+
+ device_factory_->SetServiceRef(service_ref_->Clone());
}
-void VideoCaptureServiceImpl::LazyInitializeVideoSourceProvider() {
+void DeviceFactoryProviderImpl::LazyInitializeVideoSourceProvider() {
if (video_source_provider_)
return;
LazyInitializeDeviceFactory();
@@ -185,12 +197,39 @@ void VideoCaptureServiceImpl::LazyInitializeVideoSourceProvider() {
device_factory_.get(),
// Unretained(this) is safe, because |this| owns |video_source_provider_|.
base::BindRepeating(
- &VideoCaptureServiceImpl::OnLastSourceProviderClientDisconnected,
+ &DeviceFactoryProviderImpl::OnLastSourceProviderClientDisconnected,
base::Unretained(this)));
}
-void VideoCaptureServiceImpl::OnLastSourceProviderClientDisconnected() {
+void DeviceFactoryProviderImpl::OnLastSourceProviderClientDisconnected() {
video_source_provider_.reset();
+ OnFactoryOrSourceProviderClientDisconnected();
}
+void DeviceFactoryProviderImpl::OnFactoryOrSourceProviderClientDisconnected() {
+ // If |video_source_provider_| still exists, it means there is still a client
+ // connected to it, in which case we also still need |device_factory_| to
+ // stay operational.
+ if (video_source_provider_)
+ return;
+
+ // If neither |device_factory_| nor |video_source_provider_| have clients
+ // connected, release service ref so that service shutdown timeout can start
+ // if no other references are still alive. We keep the |device_factory_|
+ // instance alive in order to avoid losing state that would be expensive to
+ // reinitialize, e.g. having already enumerated the available devices.
+ if (factory_bindings_.empty()) {
+ device_factory_->SetServiceRef(nullptr);
+ }
+}
+
+#if defined(OS_CHROMEOS)
+void DeviceFactoryProviderImpl::BindCrosImageCaptureRequest(
+ cros::mojom::CrosImageCaptureRequest request) {
+ CHECK(device_factory_);
+
+ device_factory_->BindCrosImageCaptureRequest(std::move(request));
+}
+#endif // defined(OS_CHROMEOS)
+
} // namespace video_capture
diff --git a/chromium/services/video_capture/video_capture_service_impl.h b/chromium/services/video_capture/device_factory_provider_impl.h
index e98751cb170..950cd0b5464 100644
--- a/chromium/services/video_capture/video_capture_service_impl.h
+++ b/chromium/services/video_capture/device_factory_provider_impl.h
@@ -2,18 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_SERVICE_IMPL_H_
-#define SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_SERVICE_IMPL_H_
+#ifndef SERVICES_VIDEO_CAPTURE_DEVICE_FACTORY_PROVIDER_H_
+#define SERVICES_VIDEO_CAPTURE_DEVICE_FACTORY_PROVIDER_H_
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "base/threading/thread.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/device_factory.mojom.h"
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#if defined(OS_CHROMEOS)
#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
@@ -24,26 +25,31 @@ namespace video_capture {
class VirtualDeviceEnabledDeviceFactory;
class VideoSourceProviderImpl;
-class VideoCaptureServiceImpl : public mojom::VideoCaptureService {
+class DeviceFactoryProviderImpl : public mojom::DeviceFactoryProvider {
public:
- explicit VideoCaptureServiceImpl(
- mojo::PendingReceiver<mojom::VideoCaptureService> receiver,
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
- ~VideoCaptureServiceImpl() override;
+ explicit DeviceFactoryProviderImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ base::OnceClosure request_service_quit_asap_cb);
+ ~DeviceFactoryProviderImpl() override;
- // mojom::VideoCaptureService implementation.
+ void SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+
+ // mojom::DeviceFactoryProvider implementation.
#if defined(OS_CHROMEOS)
void InjectGpuDependencies(
mojom::AcceleratorFactoryPtr accelerator_factory) override;
- void BindCrosImageCapture(
- mojo::PendingReceiver<cros::mojom::CrosImageCapture> receiver) override;
#endif // defined(OS_CHROMEOS)
void ConnectToDeviceFactory(mojom::DeviceFactoryRequest request) override;
void ConnectToVideoSourceProvider(
mojom::VideoSourceProviderRequest request) override;
+ void ShutdownServiceAsap() override;
void SetRetryCount(int32_t count) override;
- void BindControlsForTesting(
- mojo::PendingReceiver<mojom::TestingControls> receiver) override;
+
+#if defined(OS_CHROMEOS)
+ void BindCrosImageCaptureRequest(
+ cros::mojom::CrosImageCaptureRequest request);
+#endif // defined(OS_CHROMEOS)
private:
class GpuDependenciesContext;
@@ -52,18 +58,20 @@ class VideoCaptureServiceImpl : public mojom::VideoCaptureService {
void LazyInitializeDeviceFactory();
void LazyInitializeVideoSourceProvider();
void OnLastSourceProviderClientDisconnected();
+ void OnFactoryOrSourceProviderClientDisconnected();
- mojo::Receiver<mojom::VideoCaptureService> receiver_;
mojo::BindingSet<mojom::DeviceFactory> factory_bindings_;
std::unique_ptr<VirtualDeviceEnabledDeviceFactory> device_factory_;
std::unique_ptr<VideoSourceProviderImpl> video_source_provider_;
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
std::unique_ptr<GpuDependenciesContext> gpu_dependencies_context_;
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ base::OnceClosure request_service_quit_asap_cb_;
- DISALLOW_COPY_AND_ASSIGN(VideoCaptureServiceImpl);
+ DISALLOW_COPY_AND_ASSIGN(DeviceFactoryProviderImpl);
};
} // namespace video_capture
-#endif // SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_SERVICE_IMPL_H_
+#endif // SERVICES_VIDEO_CAPTURE_DEVICE_FACTORY_PROVIDER_H_
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
index 1ce673c0e8d..dfb0abd8f2a 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
@@ -40,18 +40,24 @@ namespace video_capture {
#if defined(OS_CHROMEOS)
DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
std::unique_ptr<media::VideoCaptureDevice> device,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner)
- : device_(std::move(device)),
+ : service_ref_(std::move(service_ref)),
+ device_(std::move(device)),
jpeg_decoder_factory_callback_(std::move(jpeg_decoder_factory_callback)),
jpeg_decoder_task_runner_(std::move(jpeg_decoder_task_runner)),
device_started_(false),
weak_factory_(this) {}
#else
DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
std::unique_ptr<media::VideoCaptureDevice> device)
- : device_(std::move(device)), device_started_(false), weak_factory_(this) {}
+ : service_ref_(std::move(service_ref)),
+ device_(std::move(device)),
+ device_started_(false),
+ weak_factory_(this) {}
#endif // defined(OS_CHROMEOS)
DeviceMediaToMojoAdapter::~DeviceMediaToMojoAdapter() {
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.h b/chromium/services/video_capture/device_media_to_mojo_adapter.h
index 2e9d1ec2a23..4ebf2e5246c 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.h
@@ -10,6 +10,7 @@
#include "media/capture/video/video_capture_device_client.h"
#include "media/capture/video/video_capture_device_factory.h"
#include "media/capture/video_capture_types.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#if defined(OS_CHROMEOS)
@@ -27,11 +28,13 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
public:
#if defined(OS_CHROMEOS)
DeviceMediaToMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
std::unique_ptr<media::VideoCaptureDevice> device,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner);
#else
DeviceMediaToMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
std::unique_ptr<media::VideoCaptureDevice> device);
#endif // defined(OS_CHROMEOS)
~DeviceMediaToMojoAdapter() override;
@@ -54,6 +57,7 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
static int max_buffer_pool_buffer_count();
private:
+ const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
const std::unique_ptr<media::VideoCaptureDevice> device_;
#if defined(OS_CHROMEOS)
const media::MojoMjpegDecodeAcceleratorFactoryCB
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
index 7ae494ebb71..818df33c4cb 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
@@ -29,10 +29,12 @@ class DeviceMediaToMojoAdapterTest : public ::testing::Test {
mock_device_ptr_ = mock_device.get();
#if defined(OS_CHROMEOS)
adapter_ = std::make_unique<DeviceMediaToMojoAdapter>(
+ std::unique_ptr<service_manager::ServiceContextRef>(),
std::move(mock_device), base::DoNothing(),
base::ThreadTaskRunnerHandle::Get());
#else
adapter_ = std::make_unique<DeviceMediaToMojoAdapter>(
+ std::unique_ptr<service_manager::ServiceContextRef>(),
std::move(mock_device));
#endif // defined(OS_CHROMEOS)
}
diff --git a/chromium/services/video_capture/public/cpp/BUILD.gn b/chromium/services/video_capture/public/cpp/BUILD.gn
index 98462de10fd..07fdfdaa744 100644
--- a/chromium/services/video_capture/public/cpp/BUILD.gn
+++ b/chromium/services/video_capture/public/cpp/BUILD.gn
@@ -14,6 +14,7 @@ source_set("cpp") {
"//base",
"//media",
"//media/capture:capture",
+ "//services/service_manager/public/cpp",
"//services/video_capture/public/mojom",
]
@@ -22,20 +23,36 @@ source_set("cpp") {
]
}
+source_set("manifest") {
+ sources = [
+ "manifest.cc",
+ "manifest.h",
+ ]
+ deps = [
+ "//base",
+ "//services/service_manager/public/cpp",
+ "//services/video_capture/public/mojom",
+ "//services/video_capture/public/mojom:constants",
+ ]
+ if (is_chromeos) {
+ deps += [ "//media/capture/video/chromeos/mojo:cros_camera" ]
+ }
+}
+
source_set("mocks") {
testonly = true
sources = [
"mock_device_factory.cc",
"mock_device_factory.h",
+ "mock_device_factory_provider.cc",
+ "mock_device_factory_provider.h",
"mock_producer.cc",
"mock_producer.h",
"mock_push_subscription.cc",
"mock_push_subscription.h",
"mock_receiver.cc",
"mock_receiver.h",
- "mock_video_capture_service.cc",
- "mock_video_capture_service.h",
"mock_video_source.cc",
"mock_video_source.h",
"mock_video_source_provider.cc",
diff --git a/chromium/services/video_capture/public/cpp/manifest.cc b/chromium/services/video_capture/public/cpp/manifest.cc
new file mode 100644
index 00000000000..fc1b20d86a1
--- /dev/null
+++ b/chromium/services/video_capture/public/cpp/manifest.cc
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/video_capture/public/cpp/manifest.h"
+
+#if defined(OS_CHROMEOS)
+#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#endif // defined(OS_CHROMEOS)
+#include "services/service_manager/public/cpp/manifest_builder.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
+#include "services/video_capture/public/mojom/testing_controls.mojom.h"
+
+namespace video_capture {
+
+service_manager::Manifest GetManifest(
+ service_manager::Manifest::ExecutionMode execution_mode) {
+ return service_manager::Manifest {
+ service_manager::ManifestBuilder()
+ .WithServiceName(mojom::kServiceName)
+ .WithDisplayName("Video Capture")
+ .WithOptions(service_manager::ManifestOptionsBuilder()
+ .WithExecutionMode(execution_mode)
+ .WithSandboxType("none")
+ .WithInstanceSharingPolicy(
+ service_manager::Manifest::InstanceSharingPolicy::
+ kSharedAcrossGroups)
+ .Build())
+ .ExposeCapability("capture", service_manager::Manifest::InterfaceList<
+#if defined(OS_CHROMEOS)
+ cros::mojom::CrosImageCapture,
+#endif // defined(OS_CHROMEOS)
+ mojom::DeviceFactoryProvider>())
+ .ExposeCapability(
+ "tests",
+ service_manager::Manifest::InterfaceList<
+ mojom::DeviceFactoryProvider, mojom::TestingControls>())
+ .Build()
+ };
+}
+
+} // namespace video_capture
diff --git a/chromium/services/video_capture/public/cpp/manifest.h b/chromium/services/video_capture/public/cpp/manifest.h
new file mode 100644
index 00000000000..d28ef4a8078
--- /dev/null
+++ b/chromium/services/video_capture/public/cpp/manifest.h
@@ -0,0 +1,17 @@
+// 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 SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MANIFEST_H_
+#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MANIFEST_H_
+
+#include "services/service_manager/public/cpp/manifest.h"
+
+namespace video_capture {
+
+service_manager::Manifest GetManifest(
+ service_manager::Manifest::ExecutionMode execution_mode);
+
+} // namespace video_capture
+
+#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MANIFEST_H_
diff --git a/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc b/chromium/services/video_capture/public/cpp/mock_device_factory_provider.cc
index f2dbb05b3d2..2dbc71c2d18 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc
+++ b/chromium/services/video_capture/public/cpp/mock_device_factory_provider.cc
@@ -2,26 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/video_capture/public/cpp/mock_video_capture_service.h"
+#include "services/video_capture/public/cpp/mock_device_factory_provider.h"
namespace video_capture {
-MockVideoCaptureService::MockVideoCaptureService() {}
+MockDeviceFactoryProvider::MockDeviceFactoryProvider() {}
-MockVideoCaptureService::~MockVideoCaptureService() = default;
+MockDeviceFactoryProvider::~MockDeviceFactoryProvider() = default;
-void MockVideoCaptureService::ConnectToDeviceFactory(
+void MockDeviceFactoryProvider::ConnectToDeviceFactory(
video_capture::mojom::DeviceFactoryRequest request) {
DoConnectToDeviceFactory(request);
}
-void MockVideoCaptureService::ConnectToVideoSourceProvider(
+void MockDeviceFactoryProvider::ConnectToVideoSourceProvider(
video_capture::mojom::VideoSourceProviderRequest request) {
DoConnectToVideoSourceProvider(request);
}
#if defined(OS_CHROMEOS)
-void MockVideoCaptureService::InjectGpuDependencies(
+void MockDeviceFactoryProvider::InjectGpuDependencies(
video_capture::mojom::AcceleratorFactoryPtr accelerator_factory) {
DoInjectGpuDependencies(accelerator_factory);
}
diff --git a/chromium/services/video_capture/public/cpp/mock_video_capture_service.h b/chromium/services/video_capture/public/cpp/mock_device_factory_provider.h
index da63ced2b59..645a75d9353 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_capture_service.h
+++ b/chromium/services/video_capture/public/cpp/mock_device_factory_provider.h
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_VIDEO_CAPTURE_SERVICE_H_
-#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_VIDEO_CAPTURE_SERVICE_H_
+#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_DEVICE_FACTORY_PROVIDER_H_
+#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_DEVICE_FACTORY_PROVIDER_H_
-#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace video_capture {
-class MockVideoCaptureService
- : public video_capture::mojom::VideoCaptureService {
+class MockDeviceFactoryProvider
+ : public video_capture::mojom::DeviceFactoryProvider {
public:
- MockVideoCaptureService();
- ~MockVideoCaptureService() override;
+ MockDeviceFactoryProvider();
+ ~MockDeviceFactoryProvider() override;
void ConnectToDeviceFactory(
video_capture::mojom::DeviceFactoryRequest request) override;
@@ -29,22 +29,17 @@ class MockVideoCaptureService
MOCK_METHOD1(
DoInjectGpuDependencies,
void(video_capture::mojom::AcceleratorFactoryPtr& accelerator_factory));
-
- void BindCrosImageCapture(
- mojo::PendingReceiver<cros::mojom::CrosImageCapture>) override {}
#endif // defined(OS_CHROMEOS
- void BindControlsForTesting(
- mojo::PendingReceiver<mojom::TestingControls>) override {}
-
MOCK_METHOD1(SetShutdownDelayInSeconds, void(float seconds));
MOCK_METHOD1(DoConnectToDeviceFactory,
void(video_capture::mojom::DeviceFactoryRequest& request));
MOCK_METHOD1(DoConnectToVideoSourceProvider,
void(video_capture::mojom::VideoSourceProviderRequest& request));
+ MOCK_METHOD0(ShutdownServiceAsap, void());
MOCK_METHOD1(SetRetryCount, void(int32_t));
};
} // namespace video_capture
-#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_VIDEO_CAPTURE_SERVICE_H_
+#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_DEVICE_FACTORY_PROVIDER_H_
diff --git a/chromium/services/video_capture/public/mojom/BUILD.gn b/chromium/services/video_capture/public/mojom/BUILD.gn
index 11b2e39afdd..908532aeb6f 100644
--- a/chromium/services/video_capture/public/mojom/BUILD.gn
+++ b/chromium/services/video_capture/public/mojom/BUILD.gn
@@ -8,12 +8,12 @@ mojom("mojom") {
sources = [
"device.mojom",
"device_factory.mojom",
+ "device_factory_provider.mojom",
"devices_changed_observer.mojom",
"producer.mojom",
"receiver.mojom",
"scoped_access_permission.mojom",
"testing_controls.mojom",
- "video_capture_service.mojom",
"video_source.mojom",
"video_source_provider.mojom",
"virtual_device.mojom",
@@ -27,10 +27,7 @@ mojom("mojom") {
]
if (is_chromeos) {
- deps += [
- "//components/chromeos_camera/common",
- "//media/capture/video/chromeos/mojo:cros_camera",
- ]
+ deps += [ "//components/chromeos_camera/common" ]
}
}
diff --git a/chromium/services/video_capture/public/mojom/constants.mojom b/chromium/services/video_capture/public/mojom/constants.mojom
index d13930e0a76..ee5cd3e3a05 100644
--- a/chromium/services/video_capture/public/mojom/constants.mojom
+++ b/chromium/services/video_capture/public/mojom/constants.mojom
@@ -4,4 +4,5 @@
module video_capture.mojom;
+const string kServiceName = "video_capture";
const int32 kInvalidBufferId = -1;
diff --git a/chromium/services/video_capture/public/mojom/video_capture_service.mojom b/chromium/services/video_capture/public/mojom/device_factory_provider.mojom
index 916e8efca19..4ec2285ddb0 100644
--- a/chromium/services/video_capture/public/mojom/video_capture_service.mojom
+++ b/chromium/services/video_capture/public/mojom/device_factory_provider.mojom
@@ -7,13 +7,9 @@ module video_capture.mojom;
[EnableIf=is_chromeos]
import "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom";
import "services/video_capture/public/mojom/device_factory.mojom";
-import "services/video_capture/public/mojom/testing_controls.mojom";
import "services/video_capture/public/mojom/video_source_provider.mojom";
[EnableIf=is_chromeos]
-import "media/capture/video/chromeos/mojo/cros_image_capture.mojom";
-
-[EnableIf=is_chromeos]
interface AcceleratorFactory {
// Creates a new JpegDecodeAccelerator and binds it to |jda|.
CreateJpegDecodeAccelerator(
@@ -29,24 +25,22 @@ interface AcceleratorFactory {
// to be called once before any call to ConnectToDeviceFactory() is made.
// Calling InjectGpuDependencies() is optional. If it is not called, MJPEG
// decoding will be performed without gpu acceleration.
-interface VideoCaptureService {
+// TODO(chfremer): Consider renaming this to VideoCaptureService.
+interface DeviceFactoryProvider {
[EnableIf=is_chromeos]
InjectGpuDependencies(AcceleratorFactory accelerator_factory);
- // Binds a Chrome OS camera capture interface.
- [EnableIf=is_chromeos]
- BindCrosImageCapture(pending_receiver<cros.mojom.CrosImageCapture> receiver);
-
// Legacy API. Supports one client per device.
ConnectToDeviceFactory(DeviceFactory& request);
// Current API. Supports multiple clients per source.
ConnectToVideoSourceProvider(VideoSourceProvider& request);
+ // Lets the service to close all connections and ask the service_manager to be
+ // shut down.
+ ShutdownServiceAsap();
+
// Sets a retry count that is used by the service for logging UMA events in
// the context of investigation for https://crbug.com/643068.
SetRetryCount(int32 count);
-
- // Binds a test-only interface for use by unit tests.
- BindControlsForTesting(pending_receiver<TestingControls> receiver);
};
diff --git a/chromium/services/video_capture/service_impl.cc b/chromium/services/video_capture/service_impl.cc
new file mode 100644
index 00000000000..5bf14321766
--- /dev/null
+++ b/chromium/services/video_capture/service_impl.cc
@@ -0,0 +1,192 @@
+// 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 "services/video_capture/service_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/video_capture/device_factory_provider_impl.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/public/uma/video_capture_service_event.h"
+#include "services/video_capture/testing_controls_impl.h"
+
+#if defined(OS_CHROMEOS)
+#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#endif // defined(OS_CHROMEOS)
+
+namespace video_capture {
+
+namespace {
+
+#if defined(OS_ANDROID)
+// On Android, we do not use automatic service shutdown, because when shutting
+// down the service, we lose caching of the supported formats, and re-querying
+// these can take several seconds on certain Android devices.
+constexpr base::Optional<base::TimeDelta> kDefaultIdleTimeout;
+#else
+constexpr base::Optional<base::TimeDelta> kDefaultIdleTimeout =
+ base::TimeDelta::FromSeconds(5);
+#endif
+
+} // namespace
+
+ServiceImpl::ServiceImpl(
+ service_manager::mojom::ServiceRequest request,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : ServiceImpl(std::move(request),
+ std::move(ui_task_runner),
+ kDefaultIdleTimeout) {}
+
+ServiceImpl::ServiceImpl(
+ service_manager::mojom::ServiceRequest request,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ base::Optional<base::TimeDelta> idle_timeout)
+ : binding_(this, std::move(request)),
+ keepalive_(&binding_, idle_timeout),
+ ui_task_runner_(std::move(ui_task_runner)) {
+ keepalive_.AddObserver(this);
+}
+
+ServiceImpl::~ServiceImpl() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ keepalive_.RemoveObserver(this);
+}
+
+void ServiceImpl::SetFactoryProviderClientConnectedObserver(
+ base::RepeatingClosure observer_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ factory_provider_client_connected_cb_ = std::move(observer_cb);
+}
+
+void ServiceImpl::SetFactoryProviderClientDisconnectedObserver(
+ base::RepeatingClosure observer_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ factory_provider_client_disconnected_cb_ = std::move(observer_cb);
+}
+
+void ServiceImpl::SetShutdownTimeoutCancelledObserver(
+ base::RepeatingClosure observer_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ shutdown_timeout_cancelled_cb_ = std::move(observer_cb);
+}
+
+bool ServiceImpl::HasNoContextRefs() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return keepalive_.HasNoRefs();
+}
+
+void ServiceImpl::ShutdownServiceAsap() {
+ binding_.RequestClose();
+}
+
+void ServiceImpl::OnStart() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ video_capture::uma::LogVideoCaptureServiceEvent(
+ video_capture::uma::SERVICE_STARTED);
+
+ registry_.AddInterface<mojom::DeviceFactoryProvider>(
+ // Unretained |this| is safe because |registry_| is owned by |this|.
+ base::BindRepeating(&ServiceImpl::OnDeviceFactoryProviderRequest,
+ base::Unretained(this)));
+ registry_.AddInterface<mojom::TestingControls>(
+ // Unretained |this| is safe because |registry_| is owned by |this|.
+ base::BindRepeating(&ServiceImpl::OnTestingControlsRequest,
+ base::Unretained(this)));
+
+#if defined(OS_CHROMEOS)
+ registry_.AddInterface<cros::mojom::CrosImageCapture>(base::BindRepeating(
+ &ServiceImpl::OnCrosImageCaptureRequest, base::Unretained(this)));
+#endif // defined(OS_CHROMEOS)
+
+ // Unretained |this| is safe because |factory_provider_bindings_| is owned by
+ // |this|.
+ factory_provider_bindings_.set_connection_error_handler(base::BindRepeating(
+ &ServiceImpl::OnProviderClientDisconnected, base::Unretained(this)));
+}
+
+void ServiceImpl::OnBindInterface(
+ const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
+}
+
+bool ServiceImpl::OnServiceManagerConnectionLost() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return true;
+}
+
+void ServiceImpl::OnIdleTimeout() {
+ video_capture::uma::LogVideoCaptureServiceEvent(
+ video_capture::uma::SERVICE_SHUTTING_DOWN_BECAUSE_NO_CLIENT);
+}
+
+void ServiceImpl::OnIdleTimeoutCancelled() {
+ video_capture::uma::LogVideoCaptureServiceEvent(
+ video_capture::uma::SERVICE_SHUTDOWN_TIMEOUT_CANCELED);
+ if (shutdown_timeout_cancelled_cb_)
+ shutdown_timeout_cancelled_cb_.Run();
+}
+
+void ServiceImpl::OnDeviceFactoryProviderRequest(
+ mojom::DeviceFactoryProviderRequest request) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ LazyInitializeDeviceFactoryProvider();
+ if (factory_provider_bindings_.empty())
+ device_factory_provider_->SetServiceRef(keepalive_.CreateRef());
+ factory_provider_bindings_.AddBinding(device_factory_provider_.get(),
+ std::move(request));
+
+ if (!factory_provider_client_connected_cb_.is_null()) {
+ factory_provider_client_connected_cb_.Run();
+ }
+}
+
+void ServiceImpl::OnTestingControlsRequest(
+ mojom::TestingControlsRequest request) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ mojo::MakeStrongBinding(
+ std::make_unique<TestingControlsImpl>(keepalive_.CreateRef()),
+ std::move(request));
+}
+
+#if defined(OS_CHROMEOS)
+void ServiceImpl::OnCrosImageCaptureRequest(
+ cros::mojom::CrosImageCaptureRequest request) {
+ LazyInitializeDeviceFactoryProvider();
+ device_factory_provider_->BindCrosImageCaptureRequest(std::move(request));
+}
+#endif // defined(OS_CHROMEOS)
+
+void ServiceImpl::LazyInitializeDeviceFactoryProvider() {
+ if (device_factory_provider_)
+ return;
+
+ // Use of base::Unretained() is safe because |this| owns, and therefore
+ // outlives |device_factory_provider_|
+ device_factory_provider_ = std::make_unique<DeviceFactoryProviderImpl>(
+ ui_task_runner_, base::BindOnce(&ServiceImpl::ShutdownServiceAsap,
+ base::Unretained(this)));
+}
+
+void ServiceImpl::OnProviderClientDisconnected() {
+ // If last client has disconnected, release service ref so that service
+ // shutdown timeout starts if no other references are still alive.
+ // We keep the |device_factory_provider_| instance alive in order to avoid
+ // losing state that would be expensive to reinitialize, e.g. having
+ // already enumerated the available devices.
+ if (factory_provider_bindings_.empty())
+ device_factory_provider_->SetServiceRef(nullptr);
+
+ if (!factory_provider_client_disconnected_cb_.is_null()) {
+ factory_provider_client_disconnected_cb_.Run();
+ }
+}
+
+} // namespace video_capture
diff --git a/chromium/services/video_capture/service_impl.h b/chromium/services/video_capture/service_impl.h
new file mode 100644
index 00000000000..65b2a12aba3
--- /dev/null
+++ b/chromium/services/video_capture/service_impl.h
@@ -0,0 +1,107 @@
+// 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 SERVICES_VIDEO_CAPTURE_SERVICE_IMPL_H_
+#define SERVICES_VIDEO_CAPTURE_SERVICE_IMPL_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_binding.h"
+#include "services/service_manager/public/cpp/service_keepalive.h"
+#include "services/video_capture/device_factory_provider_impl.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
+#include "services/video_capture/public/mojom/testing_controls.mojom.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#endif // defined(OS_CHROMEOS)
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace video_capture {
+
+class ServiceImpl : public service_manager::Service,
+ public service_manager::ServiceKeepalive::Observer {
+ public:
+ ServiceImpl(service_manager::mojom::ServiceRequest request,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+
+ // Constructs a service instance which overrides the default idle timeout
+ // behavior.
+ ServiceImpl(service_manager::mojom::ServiceRequest request,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ base::Optional<base::TimeDelta> idle_timeout);
+
+ ~ServiceImpl() override;
+
+ void SetFactoryProviderClientConnectedObserver(
+ base::RepeatingClosure observer_cb);
+ void SetFactoryProviderClientDisconnectedObserver(
+ base::RepeatingClosure observer_cb);
+ void SetShutdownTimeoutCancelledObserver(base::RepeatingClosure observer_cb);
+ bool HasNoContextRefs();
+
+ void ShutdownServiceAsap();
+
+ // service_manager::Service implementation.
+ void OnStart() override;
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+ bool OnServiceManagerConnectionLost() override;
+
+ // service_manager::ServiceKeepalive::Observer implementation.
+ void OnIdleTimeout() override;
+ void OnIdleTimeoutCancelled() override;
+
+ private:
+ void OnDeviceFactoryProviderRequest(
+ mojom::DeviceFactoryProviderRequest request);
+ void OnTestingControlsRequest(mojom::TestingControlsRequest request);
+#if defined(OS_CHROMEOS)
+ void OnCrosImageCaptureRequest(cros::mojom::CrosImageCaptureRequest request);
+#endif // defined(OS_CHROMEOS)
+ void MaybeRequestQuitDelayed();
+ void MaybeRequestQuit();
+ void LazyInitializeDeviceFactoryProvider();
+ void OnProviderClientDisconnected();
+
+ service_manager::ServiceBinding binding_;
+ service_manager::ServiceKeepalive keepalive_;
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+
+#if defined(OS_WIN)
+ // COM must be initialized in order to access the video capture devices.
+ base::win::ScopedCOMInitializer com_initializer_;
+#endif
+ service_manager::BinderRegistry registry_;
+ mojo::BindingSet<mojom::DeviceFactoryProvider> factory_provider_bindings_;
+ std::unique_ptr<DeviceFactoryProviderImpl> device_factory_provider_;
+
+ // Callbacks that can optionally be set by clients.
+ base::RepeatingClosure factory_provider_client_connected_cb_;
+ base::RepeatingClosure factory_provider_client_disconnected_cb_;
+ base::RepeatingClosure shutdown_timeout_cancelled_cb_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
+};
+
+} // namespace video_capture
+
+#endif // SERVICES_VIDEO_CAPTURE_SERVICE_IMPL_H_
diff --git a/chromium/services/video_capture/service_main.cc b/chromium/services/video_capture/service_main.cc
new file mode 100644
index 00000000000..77f46359fd9
--- /dev/null
+++ b/chromium/services/video_capture/service_main.cc
@@ -0,0 +1,14 @@
+// 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 "services/service_manager/public/cpp/service_executable/service_main.h"
+#include "base/task/single_thread_task_executor.h"
+#include "services/video_capture/service_impl.h"
+
+void ServiceMain(service_manager::mojom::ServiceRequest request) {
+ base::SingleThreadTaskExecutor main_thread_task_executor;
+ video_capture::ServiceImpl(std::move(request),
+ main_thread_task_executor.task_runner())
+ .RunUntilTermination();
+}
diff --git a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
index 265ed010d9b..2cecb0fef8c 100644
--- a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
@@ -29,9 +29,11 @@ void OnNewBufferAcknowleged(
namespace video_capture {
SharedMemoryVirtualDeviceMojoAdapter::SharedMemoryVirtualDeviceMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
mojom::ProducerPtr producer,
bool send_buffer_handles_to_producer_as_raw_file_descriptors)
- : producer_(std::move(producer)),
+ : service_ref_(std::move(service_ref)),
+ producer_(std::move(producer)),
send_buffer_handles_to_producer_as_raw_file_descriptors_(
send_buffer_handles_to_producer_as_raw_file_descriptors),
buffer_pool_(new media::VideoCaptureBufferPoolImpl(
diff --git a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
index 4f35010d9bb..45c4a2d44d1 100644
--- a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
@@ -8,6 +8,7 @@
#include "base/sequence_checker.h"
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video_capture_types.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "services/video_capture/public/mojom/receiver.mojom.h"
@@ -20,6 +21,7 @@ class SharedMemoryVirtualDeviceMojoAdapter
public mojom::Device {
public:
SharedMemoryVirtualDeviceMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
mojom::ProducerPtr producer,
bool send_buffer_handles_to_producer_as_raw_file_descriptors = false);
~SharedMemoryVirtualDeviceMojoAdapter() override;
@@ -52,6 +54,7 @@ class SharedMemoryVirtualDeviceMojoAdapter
private:
void OnReceiverConnectionErrorOrClose();
+ const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
mojom::ReceiverPtr receiver_;
mojom::ProducerPtr producer_;
const bool send_buffer_handles_to_producer_as_raw_file_descriptors_;
diff --git a/chromium/services/video_capture/testing_controls_impl.cc b/chromium/services/video_capture/testing_controls_impl.cc
index 3dc4e69af3a..e89eb86ec3a 100644
--- a/chromium/services/video_capture/testing_controls_impl.cc
+++ b/chromium/services/video_capture/testing_controls_impl.cc
@@ -4,11 +4,11 @@
#include "services/video_capture/testing_controls_impl.h"
-#include "base/logging.h"
-
namespace video_capture {
-TestingControlsImpl::TestingControlsImpl() = default;
+TestingControlsImpl::TestingControlsImpl(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+ : service_ref_(std::move(service_ref)) {}
TestingControlsImpl::~TestingControlsImpl() = default;
diff --git a/chromium/services/video_capture/testing_controls_impl.h b/chromium/services/video_capture/testing_controls_impl.h
index eb051d14b6e..860820be50d 100644
--- a/chromium/services/video_capture/testing_controls_impl.h
+++ b/chromium/services/video_capture/testing_controls_impl.h
@@ -5,19 +5,23 @@
#ifndef SERVICES_VIDEO_CAPTURE_TESTING_CONTROLS_IMPL_H_
#define SERVICES_VIDEO_CAPTURE_TESTING_CONTROLS_IMPL_H_
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/testing_controls.mojom.h"
namespace video_capture {
class TestingControlsImpl : public mojom::TestingControls {
public:
- TestingControlsImpl();
+ TestingControlsImpl(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref);
~TestingControlsImpl() override;
// mojom::TestingControls implementation.
void Crash() override;
private:
+ const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+
DISALLOW_COPY_AND_ASSIGN(TestingControlsImpl);
};
diff --git a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
index 3239a4d74a6..42c604debfd 100644
--- a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
@@ -15,7 +15,9 @@
namespace video_capture {
-TextureVirtualDeviceMojoAdapter::TextureVirtualDeviceMojoAdapter() = default;
+TextureVirtualDeviceMojoAdapter::TextureVirtualDeviceMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+ : service_ref_(std::move(service_ref)) {}
TextureVirtualDeviceMojoAdapter::~TextureVirtualDeviceMojoAdapter() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
index 2293ae05135..8f1749e5b46 100644
--- a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
@@ -8,6 +8,7 @@
#include "base/sequence_checker.h"
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video_capture_types.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/producer.mojom.h"
#include "services/video_capture/public/mojom/receiver.mojom.h"
@@ -18,7 +19,8 @@ namespace video_capture {
class TextureVirtualDeviceMojoAdapter : public mojom::TextureVirtualDevice,
public mojom::Device {
public:
- TextureVirtualDeviceMojoAdapter();
+ explicit TextureVirtualDeviceMojoAdapter(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref);
~TextureVirtualDeviceMojoAdapter() override;
void SetReceiverDisconnectedCallback(base::OnceClosure callback);
@@ -48,6 +50,7 @@ class TextureVirtualDeviceMojoAdapter : public mojom::TextureVirtualDevice,
private:
void OnReceiverConnectionErrorOrClose();
+ const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
base::OnceClosure optional_receiver_disconnected_callback_;
mojom::ReceiverPtr receiver_;
std::unordered_map<int32_t, media::mojom::MailboxBufferHandleSetPtr>
diff --git a/chromium/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc b/chromium/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
index f0774b7e5cd..4ec7f3bced3 100644
--- a/chromium/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
+++ b/chromium/services/video_capture/texture_virtual_device_mojo_adapter_unittest.cc
@@ -17,14 +17,16 @@ namespace video_capture {
class TextureVirtualDeviceMojoAdapterTest : public ::testing::Test {
public:
- TextureVirtualDeviceMojoAdapterTest() = default;
+ TextureVirtualDeviceMojoAdapterTest()
+ : service_keepalive_(nullptr, base::nullopt) {}
void SetUp() override {
mock_receiver_1_ =
std::make_unique<MockReceiver>(mojo::MakeRequest(&receiver_1_));
mock_receiver_2_ =
std::make_unique<MockReceiver>(mojo::MakeRequest(&receiver_2_));
- adapter_ = std::make_unique<TextureVirtualDeviceMojoAdapter>();
+ adapter_ = std::make_unique<TextureVirtualDeviceMojoAdapter>(
+ service_keepalive_.CreateRef());
}
protected:
@@ -61,6 +63,7 @@ class TextureVirtualDeviceMojoAdapterTest : public ::testing::Test {
private:
base::test::ScopedTaskEnvironment task_environment_;
+ service_manager::ServiceKeepalive service_keepalive_;
std::unique_ptr<TextureVirtualDeviceMojoAdapter> adapter_;
mojom::ReceiverPtr receiver_1_;
mojom::ReceiverPtr receiver_2_;
diff --git a/chromium/services/video_capture/video_source_provider_impl.h b/chromium/services/video_capture/video_source_provider_impl.h
index f7d0ecddbc9..468ae6d9ed0 100644
--- a/chromium/services/video_capture/video_source_provider_impl.h
+++ b/chromium/services/video_capture/video_source_provider_impl.h
@@ -51,6 +51,7 @@ class VideoSourceProviderImpl : public mojom::VideoSourceProvider {
int client_count_ = 0;
int closed_but_not_yet_disconnected_client_count_ = 0;
mojo::BindingSet<mojom::VideoSourceProvider> bindings_;
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
std::map<std::string, std::unique_ptr<VideoSourceImpl>> sources_;
DISALLOW_COPY_AND_ASSIGN(VideoSourceProviderImpl);
};
diff --git a/chromium/services/video_capture/virtual_device_enabled_device_factory.cc b/chromium/services/video_capture/virtual_device_enabled_device_factory.cc
index cd413613cd2..6db39c737aa 100644
--- a/chromium/services/video_capture/virtual_device_enabled_device_factory.cc
+++ b/chromium/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -92,6 +92,15 @@ VirtualDeviceEnabledDeviceFactory::VirtualDeviceEnabledDeviceFactory(
VirtualDeviceEnabledDeviceFactory::~VirtualDeviceEnabledDeviceFactory() =
default;
+void VirtualDeviceEnabledDeviceFactory::SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+ if (service_ref)
+ device_factory_->SetServiceRef(service_ref->Clone());
+ else
+ device_factory_->SetServiceRef(nullptr);
+ service_ref_ = std::move(service_ref);
+}
+
void VirtualDeviceEnabledDeviceFactory::GetDeviceInfos(
GetDeviceInfosCallback callback) {
device_factory_->GetDeviceInfos(
@@ -143,7 +152,7 @@ void VirtualDeviceEnabledDeviceFactory::AddSharedMemoryVirtualDevice(
OnVirtualDeviceProducerConnectionErrorOrClose,
base::Unretained(this), device_id));
auto device = std::make_unique<SharedMemoryVirtualDeviceMojoAdapter>(
- std::move(producer),
+ service_ref_->Clone(), std::move(producer),
send_buffer_handles_to_producer_as_raw_file_descriptors);
auto producer_binding =
std::make_unique<mojo::Binding<mojom::SharedMemoryVirtualDevice>>(
@@ -170,7 +179,8 @@ void VirtualDeviceEnabledDeviceFactory::AddTextureVirtualDevice(
virtual_devices_by_id_.erase(virtual_device_iter);
}
- auto device = std::make_unique<TextureVirtualDeviceMojoAdapter>();
+ auto device =
+ std::make_unique<TextureVirtualDeviceMojoAdapter>(service_ref_->Clone());
auto producer_binding =
std::make_unique<mojo::Binding<mojom::TextureVirtualDevice>>(
device.get(), std::move(virtual_device_request));
diff --git a/chromium/services/video_capture/virtual_device_enabled_device_factory.h b/chromium/services/video_capture/virtual_device_enabled_device_factory.h
index 8c812c28f28..0d74f647055 100644
--- a/chromium/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/chromium/services/video_capture/virtual_device_enabled_device_factory.h
@@ -9,6 +9,7 @@
#include <utility>
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/device_factory.h"
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
@@ -28,6 +29,8 @@ class VirtualDeviceEnabledDeviceFactory : public DeviceFactory {
~VirtualDeviceEnabledDeviceFactory() override;
// DeviceFactory implementation.
+ void SetServiceRef(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref) override;
void GetDeviceInfos(GetDeviceInfosCallback callback) override;
void CreateDevice(const std::string& device_id,
mojom::DeviceRequest device_request,
@@ -66,6 +69,7 @@ class VirtualDeviceEnabledDeviceFactory : public DeviceFactory {
std::map<std::string, VirtualDeviceEntry> virtual_devices_by_id_;
const std::unique_ptr<DeviceFactory> device_factory_;
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
std::vector<mojom::DevicesChangedObserverPtr> devices_changed_observers_;
base::WeakPtrFactory<VirtualDeviceEnabledDeviceFactory> weak_factory_;
diff --git a/chromium/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h b/chromium/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
index 0d59e15f75d..fe9ba92c44f 100644
--- a/chromium/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
@@ -63,10 +63,6 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, OptSharedQuadState> {
static int32_t sorting_context_id(const OptSharedQuadState& input) {
return input.sqs->sorting_context_id;
}
-
- static bool is_fast_rounded_corner(const OptSharedQuadState& input) {
- return input.sqs->is_fast_rounded_corner;
- }
};
template <>
@@ -112,10 +108,6 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> {
return sqs.sorting_context_id;
}
- static bool is_fast_rounded_corner(const viz::SharedQuadState& sqs) {
- return sqs.is_fast_rounded_corner;
- }
-
static bool Read(viz::mojom::SharedQuadStateDataView data,
viz::SharedQuadState* out) {
if (!data.ReadQuadToTargetTransform(&out->quad_to_target_transform) ||
@@ -133,7 +125,6 @@ struct StructTraits<viz::mojom::SharedQuadStateDataView, viz::SharedQuadState> {
return false;
out->blend_mode = static_cast<SkBlendMode>(data.blend_mode());
out->sorting_context_id = data.sorting_context_id();
- out->is_fast_rounded_corner = data.is_fast_rounded_corner();
return true;
}
};
diff --git a/chromium/services/viz/public/interfaces/compositing/shared_quad_state.mojom b/chromium/services/viz/public/interfaces/compositing/shared_quad_state.mojom
index 1ca6de822df..6ca90c7e47c 100644
--- a/chromium/services/viz/public/interfaces/compositing/shared_quad_state.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/shared_quad_state.mojom
@@ -8,7 +8,6 @@ import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/rrect_f.mojom";
import "ui/gfx/mojo/transform.mojom";
-// See viz::SharedQuadState.
struct SharedQuadState {
// gfx.mojom.Transforms quad rects into the target content space.
gfx.mojom.Transform quad_to_target_transform;
@@ -37,6 +36,4 @@ struct SharedQuadState {
// supported.
uint32 blend_mode;
int32 sorting_context_id;
-
- bool is_fast_rounded_corner;
};
diff --git a/chromium/skia/ext/skia_commit_hash.h b/chromium/skia/ext/skia_commit_hash.h
index 50656e0369f..57779c35afb 100644
--- a/chromium/skia/ext/skia_commit_hash.h
+++ b/chromium/skia/ext/skia_commit_hash.h
@@ -3,6 +3,6 @@
#ifndef SKIA_EXT_SKIA_COMMIT_HASH_H_
#define SKIA_EXT_SKIA_COMMIT_HASH_H_
-#define SKIA_COMMIT_HASH "2417cee95d9097a19d759a2267d4c3e51786e873"
+#define SKIA_COMMIT_HASH "a10014304cba4f24b7af17191f59490faa8aee77"
#endif // SKIA_EXT_SKIA_COMMIT_HASH_H_
diff --git a/chromium/third_party/blink/common/features.cc b/chromium/third_party/blink/common/features.cc
index 6f58e10523e..91eec38eb8e 100644
--- a/chromium/third_party/blink/common/features.cc
+++ b/chromium/third_party/blink/common/features.cc
@@ -67,8 +67,18 @@ const base::Feature kBlinkGenPropertyTrees{"BlinkGenPropertyTrees",
base::FEATURE_ENABLED_BY_DEFAULT};
// Enable a new CSS property called backdrop-filter.
-const base::Feature kCSSBackdropFilter{"CSSBackdropFilter",
- base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kCSSBackdropFilter {
+ "CSSBackdropFilter",
+#if defined(OS_ANDROID)
+ // There are two bugs in the backdrop-filter feature for Android Webview
+ // only (crbug.com/990535 and crbug.com/991869). Because there is no
+ // compile-time flag for Webview, this disables all of Android, and the
+ // feature will be re-enabled for non-Webview Android by Finch.
+ base::FEATURE_DISABLED_BY_DEFAULT
+#else
+ base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
// Enable Display Locking JavaScript APIs.
const base::Feature kDisplayLocking{"DisplayLocking",
diff --git a/chromium/third_party/blink/renderer/controller/blink_initializer.cc b/chromium/third_party/blink/renderer/controller/blink_initializer.cc
index 471f3623f74..e8558840bba 100644
--- a/chromium/third_party/blink/renderer/controller/blink_initializer.cc
+++ b/chromium/third_party/blink/renderer/controller/blink_initializer.cc
@@ -42,6 +42,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h"
#include "third_party/blink/renderer/controller/blink_leak_detector.h"
#include "third_party/blink/renderer/controller/dev_tools_frontend_impl.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/frame/display_cutout_client_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -67,7 +68,9 @@ namespace {
class EndOfTaskRunner : public Thread::TaskObserver {
public:
- void WillProcessTask(const base::PendingTask&) override {}
+ void WillProcessTask(const base::PendingTask&) override {
+ AnimationClock::NotifyTaskStart();
+ }
void DidProcessTask(const base::PendingTask&) override {
// TODO(tzik): Move rejected promise handling to EventLoop.
diff --git a/chromium/third_party/blink/renderer/core/BUILD.gn b/chromium/third_party/blink/renderer/core/BUILD.gn
index 79a7f1d5010..6b856daa7e2 100644
--- a/chromium/third_party/blink/renderer/core/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/BUILD.gn
@@ -1452,6 +1452,7 @@ jumbo_source_set("unit_tests") {
"page/slot_scoped_traversal_test.cc",
"page/spatial_navigation_test.cc",
"page/touch_adjustment_test.cc",
+ "page/validation_message_overlay_delegate_test.cc",
"page/viewport_test.cc",
"page/window_features_test.cc",
"page/zoom_test.cc",
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_clock.cc b/chromium/third_party/blink/renderer/core/animation/animation_clock.cc
index 1c8ae77d3e0..19ba57ea1e9 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_clock.cc
+++ b/chromium/third_party/blink/renderer/core/animation/animation_clock.cc
@@ -35,7 +35,18 @@
namespace blink {
+namespace {
+// This is an approximation of time between frames, used when ticking the
+// animation clock outside of animation frame callbacks.
+constexpr base::TimeDelta kApproximateFrameTime =
+ base::TimeDelta::FromSecondsD(1 / 60.0);
+} // namespace
+
+unsigned AnimationClock::currently_running_task_ = 0;
+
void AnimationClock::UpdateTime(base::TimeTicks time) {
+ task_for_which_time_was_calculated_ = currently_running_task_;
+
// TODO(crbug.com/985770): Change this to a DCHECK_GE(time, time_) when
// VR no longer sends historical timestamps.
if (time < time_)
@@ -43,7 +54,35 @@ void AnimationClock::UpdateTime(base::TimeTicks time) {
time_ = time;
}
-base::TimeTicks AnimationClock::CurrentTime() const {
+base::TimeTicks AnimationClock::CurrentTime() {
+ // By spec, within a single rendering lifecycle the AnimationClock time should
+ // not change (as it is set from the frame time).
+ if (!can_dynamically_update_time_)
+ return time_;
+
+ // Outside of the rendering lifecycle, we may have to dynamically advance our
+ // own time (see comments on |SetAllowedToDynamicallyUpdateTime|). However we
+ // should never dynamically advance time inside a single task, as otherwise a
+ // single long-running JavaScript function could see multiple different times
+ // from document.timeline.currentTime.
+ if (task_for_which_time_was_calculated_ == currently_running_task_)
+ return time_;
+
+ // Otherwise, we may need to dynamically update our own time. Again see the
+ // comments on |SetAllowedToDynamicallyUpdateTime|.
+ const base::TimeTicks current_time = clock_->NowTicks();
+ base::TimeTicks new_time = time_;
+ if (time_ < current_time) {
+ // Attempt to predict what the most recent timestamp would have been. This
+ // may not produce a result greater than |time_|, but it greatly reduces the
+ // chance of conflicting with any future frame timestamp that does come in.
+ const base::TimeDelta frame_shift =
+ (current_time - time_) % kApproximateFrameTime;
+ new_time = current_time - frame_shift;
+ DCHECK_GE(new_time, time_);
+ }
+ UpdateTime(new_time);
+
return time_;
}
@@ -51,4 +90,11 @@ void AnimationClock::ResetTimeForTesting() {
time_ = base::TimeTicks();
}
+void AnimationClock::OverrideDynamicClockForTesting(
+ const base::TickClock* clock) {
+ clock_ = clock;
+ ResetTimeForTesting();
+ UpdateTime(clock_->NowTicks());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/animation/animation_clock.h b/chromium/third_party/blink/renderer/core/animation/animation_clock.h
index b780210abdb..8f10d8b6852 100644
--- a/chromium/third_party/blink/renderer/core/animation/animation_clock.h
+++ b/chromium/third_party/blink/renderer/core/animation/animation_clock.h
@@ -34,6 +34,7 @@
#include <limits>
#include "base/macros.h"
+#include "base/time/default_tick_clock.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -46,14 +47,57 @@ class CORE_EXPORT AnimationClock {
DISALLOW_NEW();
public:
- AnimationClock() : time_() {}
+ AnimationClock()
+ : time_(),
+ can_dynamically_update_time_(false),
+ clock_(base::DefaultTickClock::GetInstance()),
+ task_for_which_time_was_calculated_(
+ std::numeric_limits<unsigned>::max()) {}
void UpdateTime(base::TimeTicks time);
- base::TimeTicks CurrentTime() const;
+ base::TimeTicks CurrentTime();
+
+ // The HTML spec says that the clock for animations is only updated once per
+ // rendering lifecycle, at the start. However the spec also assumes that the
+ // user agent runs rendering lifecycles constantly, back-to-back. In Blink we
+ // attempt to *not* run rendering lifecycles as much as possible, to avoid
+ // unnecessary CPU usage.
+ //
+ // As such, when outside a rendering lifecycle (for example, if a setInterval
+ // triggers) we allow the AnimationClock to dynamically adjust its time to
+ // look like it is being updated by the rendering lifecycles that never
+ // happened.
+ //
+ // TODO(crbug.com/995806): Allowing the AnimationClock to update itself is
+ // error prone. We should instead get the latest impl-frame time from the
+ // compositor when outside of a Blink rendering lifecycle (whilst still
+ // not changing within the same task).
+ void SetAllowedToDynamicallyUpdateTime(bool can_dynamically_update_time) {
+ can_dynamically_update_time_ = can_dynamically_update_time;
+ }
+
+ // When using our dynamically update behavior outside rendering lifecycles, we
+ // still do not want the time to move forward within the same task (e.g.
+ // within a single setInterval callback). To achieve this we track the task in
+ // which the time was last updated, and don't update it again until we are in
+ // a new task.
+ static void NotifyTaskStart() { ++currently_running_task_; }
+
void ResetTimeForTesting();
+ // The caller owns the passed in clock, which must outlive the AnimationClock.
+ void OverrideDynamicClockForTesting(const base::TickClock*);
private:
base::TimeTicks time_;
+
+ // See |SetAllowedToDynamicallyUpdateTime| documentation for these members.
+ bool can_dynamically_update_time_;
+ const base::TickClock* clock_;
+
+ // See |NotifyTaskStart| documentation for these members.
+ unsigned task_for_which_time_was_calculated_;
+ static unsigned currently_running_task_;
+
DISALLOW_COPY_AND_ASSIGN(AnimationClock);
};
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 be4f5e1fa50..a467082f74f 100644
--- a/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/chromium/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -43,6 +43,7 @@
#include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
@@ -343,8 +344,15 @@ CompositorAnimations::CheckCanStartElementOnCompositor(
const Element& target_element) {
FailureReasons reasons = kNoFailure;
- if (!Platform::Current()->IsThreadedAnimationEnabled())
+ // Both of these checks are required. It is legal to enable the compositor
+ // thread but disable threaded animations, and there are situations where
+ // threaded animations are enabled globally but this particular LocalFrame
+ // does not have a compositor (e.g. for overlays).
+ const Settings* settings = target_element.GetDocument().GetSettings();
+ if ((settings && !settings->GetAcceleratedCompositingEnabled()) ||
+ !Platform::Current()->IsThreadedAnimationEnabled()) {
reasons |= kAcceleratedAnimationsDisabled;
+ }
if (const auto* layout_object = target_element.GetLayoutObject()) {
// We query paint property tree state below to determine whether the
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 358dfd06f0b..bfaae4f10db 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
@@ -1998,4 +1998,25 @@ TEST_P(AnimationCompositorAnimationsTest,
EXPECT_EQ(host->CompositedAnimationsCount(), 0u);
}
+// Regression test for https://crbug.com/999333. We were relying on the Document
+// always having Settings, which will not be the case if it is not attached to a
+// Frame.
+TEST_P(AnimationCompositorAnimationsTest,
+ DocumentWithoutSettingShouldNotCauseCrash) {
+ SetBodyInnerHTML("<div id='target'></div>");
+ Element* target = GetElementById("target");
+ ASSERT_TRUE(target);
+
+ // Move the target element to another Document, that does not have a frame
+ // (and thus no Settings).
+ Document* another_document = MakeGarbageCollected<Document>();
+ ASSERT_FALSE(another_document->GetSettings());
+
+ another_document->adoptNode(target, ASSERT_NO_EXCEPTION);
+
+ // This should not crash.
+ EXPECT_NE(CheckCanStartElementOnCompositor(*target),
+ CompositorAnimations::kNoFailure);
+}
+
} // namespace blink
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 7c19e649a3b..b6b0268ecd9 100644
--- a/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -56,7 +56,7 @@ bool CompareAnimations(const Member<Animation>& left,
// 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.
-base::TimeTicks CurrentAnimationTime(const Document* document) {
+base::TimeTicks CurrentAnimationTime(Document* document) {
base::TimeTicks animation_time = document->GetAnimationClock().CurrentTime();
base::TimeTicks document_zero_time = document->Timeline().ZeroTime();
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 d32736e9008..801ba257b80 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
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/animation/document_timeline.h"
+#include "base/test/simple_test_tick_clock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/animation/animation_clock.h"
@@ -68,6 +69,7 @@ class AnimationDocumentTimelineTest : public PageTestBase {
PageTestBase::SetUp(IntSize());
document = &GetDocument();
GetAnimationClock().ResetTimeForTesting();
+ GetAnimationClock().SetAllowedToDynamicallyUpdateTime(false);
element = Element::Create(QualifiedName::Null(), document.Get());
platform_timing = MakeGarbageCollected<MockPlatformTiming>();
timeline = document->Timeline();
@@ -113,6 +115,7 @@ class AnimationDocumentTimelineRealTimeTest : public PageTestBase {
PageTestBase::SetUp(IntSize());
document = &GetDocument();
timeline = document->Timeline();
+ GetAnimationClock().SetAllowedToDynamicallyUpdateTime(false);
}
void TearDown() override {
@@ -454,6 +457,39 @@ TEST_F(AnimationDocumentTimelineTest, PlayAfterDocumentDeref) {
timeline->Play(keyframe_effect);
}
+// Regression test for https://crbug.com/995806, ensuring that we do dynamically
+// progress the time when outside a rendering loop (so that we can serve e.g.
+// setInterval), but also that we *only* dynamically progress the time when
+// outside a rendering loop (so that we are mostly spec compliant).
+TEST_F(AnimationDocumentTimelineTest,
+ PredictionBehaviorOnlyAppliesOutsideRenderingLoop) {
+ base::SimpleTestTickClock test_clock;
+ GetAnimationClock().OverrideDynamicClockForTesting(&test_clock);
+ ASSERT_EQ(GetAnimationClock().CurrentTime(), test_clock.NowTicks());
+
+ // As long as we are inside the rendering loop, we shouldn't update even
+ // across tasks.
+ base::TimeTicks before_time = GetAnimationClock().CurrentTime();
+ test_clock.Advance(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(GetAnimationClock().CurrentTime(), before_time);
+
+ AnimationClock::NotifyTaskStart();
+ test_clock.Advance(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(GetAnimationClock().CurrentTime(), before_time);
+
+ // Once we leave the rendering loop, however, it is valid for the time to
+ // increase *once* per task.
+ GetAnimationClock().SetAllowedToDynamicallyUpdateTime(true);
+ EXPECT_GT(GetAnimationClock().CurrentTime(), before_time);
+
+ // The clock shouldn't tick again until we change task, however.
+ base::TimeTicks current_time = GetAnimationClock().CurrentTime();
+ test_clock.Advance(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(GetAnimationClock().CurrentTime(), current_time);
+ AnimationClock::NotifyTaskStart();
+ EXPECT_GT(GetAnimationClock().CurrentTime(), current_time);
+}
+
// Ensure that origin time is correctly calculated even when the animation
// clock has not yet been initialized.
TEST_F(AnimationDocumentTimelineRealTimeTest,
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 c63a32f28bb..27824b365c4 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
@@ -148,10 +148,12 @@ DOMArrayBuffer* FileReaderLoader::ArrayBufferResult() {
if (!finished_loading_) {
return DOMArrayBuffer::Create(ArrayBuffer::Create(
- raw_data_->Data(), static_cast<unsigned>(bytes_loaded_)));
+ raw_data_.Data(), static_cast<unsigned>(bytes_loaded_)));
}
- array_buffer_result_ = DOMArrayBuffer::Create(std::move(raw_data_));
+ WTF::ArrayBufferContents contents(std::move(raw_data_),
+ WTF::ArrayBufferContents::kNotShared);
+ array_buffer_result_ = DOMArrayBuffer::Create(contents);
AdjustReportedMemoryUsageToV8(-1 * static_cast<int64_t>(bytes_loaded_));
raw_data_.reset();
return array_buffer_result_;
@@ -171,7 +173,7 @@ String FileReaderLoader::StringResult() {
// No conversion is needed.
return string_result_;
case kReadAsBinaryString:
- SetStringResult(String(static_cast<const char*>(raw_data_->Data()),
+ SetStringResult(String(static_cast<const char*>(raw_data_.Data()),
static_cast<size_t>(bytes_loaded_)));
break;
case kReadAsText:
@@ -194,6 +196,17 @@ String FileReaderLoader::StringResult() {
return string_result_;
}
+WTF::ArrayBufferContents::DataHandle FileReaderLoader::TakeDataHandle() {
+ if (!raw_data_ || error_code_ != FileErrorCode::kOK)
+ return WTF::ArrayBufferContents::DataHandle();
+
+ DCHECK(finished_loading_);
+ WTF::ArrayBufferContents::DataHandle handle = std::move(raw_data_);
+ AdjustReportedMemoryUsageToV8(-1 * static_cast<int64_t>(bytes_loaded_));
+ raw_data_.reset();
+ return handle;
+}
+
void FileReaderLoader::SetEncoding(const String& encoding) {
if (!encoding.IsEmpty())
encoding_ = WTF::TextEncoding(encoding);
@@ -242,7 +255,9 @@ void FileReaderLoader::OnStartLoading(uint64_t total_bytes) {
return;
}
- raw_data_ = ArrayBuffer::Create(static_cast<unsigned>(total_bytes), 1);
+ raw_data_ = WTF::ArrayBufferContents::CreateDataHandle(
+ static_cast<unsigned>(total_bytes),
+ WTF::ArrayBufferContents::kDontInitialize);
if (!raw_data_) {
Failed(FileErrorCode::kNotReadableErr,
FailureType::kArrayBufferBuilderCreation);
@@ -274,14 +289,14 @@ void FileReaderLoader::OnReceivedData(const char* data, unsigned data_length) {
// that the BlobPtr is actually backed by a "real" blob, so to defend against
// compromised renderer processes we still need to carefully validate anything
// received. So return an error if we received too much data.
- if (bytes_loaded_ + data_length > raw_data_->ByteLength()) {
+ if (bytes_loaded_ + data_length > raw_data_.DataLength()) {
raw_data_.reset();
bytes_loaded_ = 0;
Failed(FileErrorCode::kNotReadableErr,
FailureType::kArrayBufferBuilderAppend);
return;
}
- memcpy(static_cast<char*>(raw_data_->Data()) + bytes_loaded_, data,
+ memcpy(static_cast<char*>(raw_data_.Data()) + bytes_loaded_, data,
data_length);
bytes_loaded_ += data_length;
is_raw_data_converted_ = false;
@@ -293,7 +308,7 @@ void FileReaderLoader::OnReceivedData(const char* data, unsigned data_length) {
void FileReaderLoader::OnFinishLoading() {
if (read_type_ != kReadByClient && raw_data_) {
- DCHECK_EQ(bytes_loaded_, raw_data_->ByteLength());
+ DCHECK_EQ(bytes_loaded_, raw_data_.DataLength());
is_raw_data_converted_ = false;
}
@@ -436,7 +451,7 @@ String FileReaderLoader::ConvertToText() {
TextResourceDecoderOptions::kPlainTextContent,
encoding_.IsValid() ? encoding_ : UTF8Encoding()));
}
- builder.Append(decoder_->Decode(static_cast<const char*>(raw_data_->Data()),
+ builder.Append(decoder_->Decode(static_cast<const char*>(raw_data_.Data()),
static_cast<size_t>(bytes_loaded_)));
if (finished_loading_)
@@ -462,7 +477,7 @@ String FileReaderLoader::ConvertToDataURL() {
builder.Append(";base64,");
Vector<char> out;
- Base64Encode(base::make_span(static_cast<const uint8_t*>(raw_data_->Data()),
+ Base64Encode(base::make_span(static_cast<const uint8_t*>(raw_data_.Data()),
SafeCast<unsigned>(bytes_loaded_)),
out);
builder.Append(out.data(), out.size());
diff --git a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.h
index d460a3f50c9..5bf738e4b2b 100644
--- a/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.h
+++ b/chromium/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h"
+#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h"
namespace blink {
@@ -85,6 +86,7 @@ class CORE_EXPORT FileReaderLoader : public mojom::blink::BlobReaderClient {
DOMArrayBuffer* ArrayBufferResult();
String StringResult();
+ WTF::ArrayBufferContents::DataHandle TakeDataHandle();
// Returns the total bytes received. Bytes ignored by m_rawData won't be
// counted.
@@ -154,7 +156,7 @@ class CORE_EXPORT FileReaderLoader : public mojom::blink::BlobReaderClient {
WTF::TextEncoding encoding_;
String data_type_;
- scoped_refptr<ArrayBuffer> raw_data_;
+ WTF::ArrayBufferContents::DataHandle raw_data_;
bool is_raw_data_converted_ = false;
Persistent<DOMArrayBuffer> array_buffer_result_;
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 775930a98f0..f39011767f9 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.cc
@@ -119,6 +119,11 @@ void FrameOverlay::PaintContents(const GraphicsLayer* graphics_layer,
Paint(context);
}
+void FrameOverlay::ServiceScriptedAnimations(
+ base::TimeTicks monotonic_frame_begin_time) {
+ delegate_->ServiceScriptedAnimations(monotonic_frame_begin_time);
+}
+
String FrameOverlay::DebugName(const GraphicsLayer*) const {
DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
return "Frame Overlay Content Layer";
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 267312c66de..ae0df9d1353 100644
--- a/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
+++ b/chromium/third_party/blink/renderer/core/frame/frame_overlay.h
@@ -56,6 +56,10 @@ class CORE_EXPORT FrameOverlay : public GraphicsLayerClient,
// For CompositeAfterPaint. Invalidates composited layers managed by the
// delegate if any.
virtual void Invalidate() {}
+
+ // Service any animations managed by the delegate.
+ virtual void ServiceScriptedAnimations(
+ base::TimeTicks monotonic_frame_begin_time) {}
};
FrameOverlay(LocalFrame*, std::unique_ptr<FrameOverlay::Delegate>);
@@ -76,6 +80,9 @@ class CORE_EXPORT FrameOverlay : public GraphicsLayerClient,
const Delegate* GetDelegate() const { return delegate_.get(); }
const LocalFrame& Frame() const { return *frame_; }
+ // Services any animations that the overlay may be managing.
+ void ServiceScriptedAnimations(base::TimeTicks monotonic_frame_begin_time);
+
// DisplayItemClient methods.
String DebugName() const final { return "FrameOverlay"; }
IntRect VisualRect() const override;
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 1f5407c50ed..bcc0869cc2f 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1661,6 +1661,10 @@ void LocalFrame::UnpauseContext() {
}
void LocalFrame::SetLifecycleState(mojom::FrameLifecycleState state) {
+ // Don't allow lifecycle state changes for detached frames.
+ if (!IsAttached())
+ return;
+
// If we have asked to be frozen we will only do this once the
// load event has fired.
if ((state == mojom::FrameLifecycleState::kFrozen ||
@@ -1688,13 +1692,21 @@ void LocalFrame::SetLifecycleState(mojom::FrameLifecycleState state) {
lifecycle_state_ = state;
if (freeze) {
- if (lifecycle_state_ != mojom::FrameLifecycleState::kPaused)
+ if (lifecycle_state_ != mojom::FrameLifecycleState::kPaused) {
DidFreeze();
+ // DidFreeze can dispatch JS events, causing |this| to be detached.
+ if (!IsAttached())
+ return;
+ }
PauseContext();
} else {
UnpauseContext();
- if (old_state != mojom::FrameLifecycleState::kPaused)
+ if (old_state != mojom::FrameLifecycleState::kPaused) {
DidResume();
+ // DidResume can dispatch JS events, causing |this| to be detached.
+ if (!IsAttached())
+ return;
+ }
}
if (Client())
Client()->LifecycleStateChanged(state);
diff --git a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
index 096a501994e..00fa7e0abcb 100644
--- a/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
+++ b/chromium/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -907,6 +907,7 @@ class LazyLoadAutomaticImagesTest : public SimTest {
ScrollOffset(0, kLoadingDistanceThreshold + kViewportHeight),
kProgrammaticScroll);
Compositor().BeginFrame();
+ test::RunPendingTasks();
full_resource.Complete(ReadTestImage());
ExpectResourceIsFullImage(GetDocument().Fetcher()->CachedResource(
KURL("https://example.com/image.png")));
@@ -1349,6 +1350,7 @@ TEST_F(LazyLoadAutomaticImagesTest, LazyLoadDisabledOnReload) {
LazyLoadAutomaticImagesTest::kViewportHeight),
kProgrammaticScroll);
Compositor().BeginFrame();
+ test::RunPendingTasks();
auto_image.Complete(ReadTestImage());
lazy_image.Complete(ReadTestImage());
test::RunPendingTasks();
@@ -1376,6 +1378,7 @@ TEST_F(LazyLoadAutomaticImagesTest, LazyLoadDisabledOnReload) {
SimSubresourceRequest lazy_image("https://example.com/image_lazy.png",
"image/png");
Compositor().BeginFrame();
+ test::RunPendingTasks();
lazy_image.Complete(ReadTestImage());
test::RunPendingTasks();
histogram_tester.ExpectTotalCount(
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
index 338eabd4ad2..0f73d79e946 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
@@ -49,7 +49,6 @@
#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/image-decoders/image_decoder.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"
@@ -298,64 +297,67 @@ void ImageBitmapFactories::ImageBitmapLoader::ContextDestroyed(
}
void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() {
- DOMArrayBuffer* array_buffer = loader_->ArrayBufferResult();
+ auto data_handle = loader_->TakeDataHandle();
loader_.reset();
- if (!array_buffer) {
+ if (!data_handle) {
RejectPromise(kAllocationFailureImageBitmapRejectionReason);
return;
}
- ScheduleAsyncImageBitmapDecoding(array_buffer);
+ ScheduleAsyncImageBitmapDecoding(std::move(data_handle));
}
void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) {
RejectPromise(kUndecodableImageBitmapRejectionReason);
}
-void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding(
- DOMArrayBuffer* array_buffer) {
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- Thread::Current()->GetTaskRunner();
- worker_pool::PostTask(
- FROM_HERE,
- CrossThreadBindOnce(
- &ImageBitmapFactories::ImageBitmapLoader::DecodeImageOnDecoderThread,
- WrapCrossThreadPersistent(this), std::move(task_runner),
- WrapCrossThreadPersistent(array_buffer), options_->premultiplyAlpha(),
- options_->colorSpaceConversion()));
-}
-
-void ImageBitmapFactories::ImageBitmapLoader::DecodeImageOnDecoderThread(
+namespace {
+void DecodeImageOnDecoderThread(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- DOMArrayBuffer* array_buffer,
- const String& premultiply_alpha_option,
- const String& color_space_conversion_option) {
- DCHECK(!IsMainThread());
-
- ImageDecoder::AlphaOption alpha_op = ImageDecoder::kAlphaPremultiplied;
- if (premultiply_alpha_option == "none")
- alpha_op = ImageDecoder::kAlphaNotPremultiplied;
- bool ignore_color_space = false;
- if (color_space_conversion_option == "none")
- ignore_color_space = true;
+ WTF::ArrayBufferContents::DataHandle data_handle,
+ ImageDecoder::AlphaOption alpha_option,
+ ColorBehavior color_behavior,
+ WTF::CrossThreadOnceFunction<void(sk_sp<SkImage>)> result_callback) {
const bool data_complete = true;
std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
SegmentReader::CreateFromSkData(SkData::MakeWithoutCopy(
- array_buffer->Data(), array_buffer->ByteLength())),
- data_complete, alpha_op, ImageDecoder::kDefaultBitDepth,
- ignore_color_space ? ColorBehavior::Ignore() : ColorBehavior::Tag());
+ data_handle.Data(), data_handle.DataLength())),
+ data_complete, alpha_option, ImageDecoder::kDefaultBitDepth,
+ color_behavior);
sk_sp<SkImage> frame;
if (decoder) {
frame = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
}
PostCrossThreadTask(
*task_runner, FROM_HERE,
- CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader::
- ResolvePromiseOnOriginalThread,
- WrapCrossThreadPersistent(this), std::move(frame)));
+ CrossThreadBindOnce(std::move(result_callback), std::move(frame)));
+}
+} // namespace
+
+void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding(
+ WTF::ArrayBufferContents::DataHandle data_handle) {
+ 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(data_handle), alpha_option, color_behavior,
+ CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader::
+ ResolvePromiseOnOriginalThread,
+ WrapCrossThreadWeakPersistent(this))));
}
void ImageBitmapFactories::ImageBitmapLoader::ResolvePromiseOnOriginalThread(
sk_sp<SkImage> frame) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!frame) {
RejectPromise(kUndecodableImageBitmapRejectionReason);
return;
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
index 503364df46b..465ccbfa787 100644
--- a/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
+++ b/chromium/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
@@ -47,6 +47,7 @@
#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"
@@ -129,6 +130,8 @@ class ImageBitmapFactories final
~ImageBitmapLoader() override;
private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
enum ImageBitmapRejectionReason {
kUndecodableImageBitmapRejectionReason,
kAllocationFailureImageBitmapRejectionReason,
@@ -136,12 +139,7 @@ class ImageBitmapFactories final
void RejectPromise(ImageBitmapRejectionReason);
- void ScheduleAsyncImageBitmapDecoding(DOMArrayBuffer*);
- void DecodeImageOnDecoderThread(
- scoped_refptr<base::SingleThreadTaskRunner>,
- DOMArrayBuffer*,
- const String& premultiply_alpha_option,
- const String& color_space_conversion_option);
+ void ScheduleAsyncImageBitmapDecoding(WTF::ArrayBufferContents::DataHandle);
void ResolvePromiseOnOriginalThread(sk_sp<SkImage>);
// ContextLifecycleObserver
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 4fcefb3de1d..160d6e2a19b 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
@@ -499,12 +499,6 @@ LayoutUnit LayoutFlexibleBox::ChildUnstretchedLogicalHeight(
// This should only be called if the logical height is the cross size
DCHECK(MainAxisIsInlineAxis(child));
if (NeedToStretchChildLogicalHeight(child)) {
- LayoutUnit old_override_height = LayoutUnit(-1);
- if (child.HasOverrideLogicalHeight()) {
- old_override_height = child.OverrideLogicalHeight();
- const_cast<LayoutBox&>(child).ClearOverrideLogicalHeight();
- }
-
LayoutUnit child_intrinsic_content_logical_height;
if (!child.ShouldApplySizeContainment()) {
if (child.DisplayLockInducesSizeContainment()) {
@@ -522,10 +516,6 @@ LayoutUnit LayoutFlexibleBox::ChildUnstretchedLogicalHeight(
LogicalExtentComputedValues values;
child.ComputeLogicalHeight(child_intrinsic_logical_height, LayoutUnit(),
values);
- if (old_override_height != LayoutUnit(-1)) {
- const_cast<LayoutBox&>(child).SetOverrideLogicalHeight(
- old_override_height);
- }
return values.extent_;
}
return child.LogicalHeight();
@@ -536,23 +526,14 @@ LayoutUnit LayoutFlexibleBox::ChildUnstretchedLogicalWidth(
const LayoutBox& child) const {
// This should only be called if the logical width is the cross size
DCHECK(!MainAxisIsInlineAxis(child));
-
+ DCHECK(!child.HasOverrideLogicalWidth());
// We compute the width as if we were unstretched. Only the main axis
// override size is set at this point.
// However, if our cross axis length is definite we don't need to recompute
// and can just return the already-set logical width.
if (!CrossAxisLengthIsDefinite(child, child.StyleRef().LogicalWidth())) {
- LayoutUnit old_override_width = LayoutUnit(-1);
- if (child.HasOverrideLogicalWidth()) {
- old_override_width = child.OverrideLogicalWidth();
- const_cast<LayoutBox&>(child).ClearOverrideLogicalWidth();
- }
-
LogicalExtentComputedValues values;
child.ComputeLogicalWidth(values);
-
- if (old_override_width != LayoutUnit(-1))
- const_cast<LayoutBox&>(child).SetOverrideLogicalWidth(old_override_width);
return values.extent_;
}
@@ -1223,6 +1204,8 @@ void LayoutFlexibleBox::ConstructAndAppendFlexItem(
FlexLayoutAlgorithm* algorithm,
LayoutBox& child,
ChildLayoutType layout_type) {
+ if (layout_type != kNeverLayout)
+ child.ClearOverrideSize();
if (layout_type != kNeverLayout &&
ChildHasIntrinsicMainAxisSize(*algorithm, child)) {
// If this condition is true, then ComputeMainAxisExtentForChild will call
@@ -1237,7 +1220,6 @@ void LayoutFlexibleBox::ConstructAndAppendFlexItem(
UpdateBlockChildDirtyBitsBeforeLayout(layout_type == kForceLayout, child);
if (child.NeedsLayout() || layout_type == kForceLayout ||
!intrinsic_size_along_main_axis_.Contains(&child)) {
- child.ClearOverrideSize();
child.ForceLayout();
CacheChildMainSize(child);
}
@@ -1504,19 +1486,8 @@ void LayoutFlexibleBox::LayoutLineItems(FlexLine* current_line,
UpdateBlockChildDirtyBitsBeforeLayout(force_child_relayout, *child);
if (!child->NeedsLayout())
MarkChildForPaginationRelayoutIfNeeded(*child, layout_scope);
- if (child->NeedsLayout()) {
+ if (child->NeedsLayout())
relaid_out_children_.insert(child);
- // It is very important that we only clear the cross axis override size
- // if we are in fact going to lay out the child. Otherwise, the cross
- // axis size and the actual laid out size get out of sync, which will
- // cause problems if we later lay out the child in simplified layout,
- // which does not go through regular flex layout and therefore would
- // not reset the cross axis size.
- if (MainAxisIsInlineAxis(*child))
- child->ClearOverrideLogicalHeight();
- else
- child->ClearOverrideLogicalWidth();
- }
child->LayoutIfNeeded();
// This shouldn't be necessary, because we set the override size to be
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 a3d84fb4390..e73dbce4bd4 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
@@ -456,6 +456,8 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendText(
// If not create a new item as needed.
if (UNLIKELY(layout_text->IsWordBreak())) {
+ typename OffsetMappingBuilder::SourceNodeScope scope(&mapping_builder_,
+ layout_text);
AppendBreakOpportunity(layout_text);
return;
}
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 39d7c563bf0..e3dfe0194be 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
@@ -1485,16 +1485,19 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
MoveToNextOf(item);
// If the line can break after the previous item, prohibit it and allow break
- // after this close tag instead.
- if (was_auto_wrap) {
- const NGInlineItemResults& item_results = line_info->Results();
- if (item_results.size() >= 2) {
- NGInlineItemResult* last = std::prev(item_result);
+ // after this close tag instead. Even when the close tag has "nowrap", break
+ // after it is allowed if the line is breakable after the previous item.
+ const NGInlineItemResults& item_results = line_info->Results();
+ if (item_results.size() >= 2) {
+ NGInlineItemResult* last = std::prev(item_result);
+ if (was_auto_wrap || last->can_break_after) {
item_result->can_break_after = last->can_break_after;
last->can_break_after = false;
+ return;
}
- return;
}
+ if (was_auto_wrap)
+ return;
DCHECK(!item_result->can_break_after);
if (!auto_wrap_)
@@ -1513,13 +1516,14 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
}
+// Returns whether this item contains only spaces that can hang.
bool NGLineBreaker::ShouldHangTraillingSpaces(const NGInlineItem& item) {
if (!item.Length())
return false;
const ComputedStyle& style = *item.Style();
- if (!auto_wrap_ || (!style.CollapseWhiteSpace() &&
- style.WhiteSpace() == EWhiteSpace::kBreakSpaces))
+ if (!style.AutoWrap() || (!style.CollapseWhiteSpace() &&
+ style.WhiteSpace() == EWhiteSpace::kBreakSpaces))
return false;
const String& text = Text();
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 f8895564880..9e5ef9dc4aa 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
@@ -107,7 +107,8 @@ void NGOffsetMappingUnit::AssertValid() const {
SECURITY_DCHECK(dom_start_ <= dom_end_) << dom_start_ << " vs. " << dom_end_;
SECURITY_DCHECK(text_content_start_ <= text_content_end_)
<< text_content_start_ << " vs. " << text_content_end_;
- if (layout_object_->IsText()) {
+ if (layout_object_->IsText() &&
+ !ToLayoutText(*layout_object_).IsWordBreak()) {
const LayoutText& layout_text = ToLayoutText(*layout_object_);
const unsigned text_start =
AssociatedNode() ? layout_text.TextStartOffset() : 0;
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 533fb646428..206226f2b87 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
@@ -1452,6 +1452,26 @@ TEST_F(NGOffsetMappingTest, EndOfLastNonCollapsedContentWithPseudo) {
EXPECT_EQ(Position(),
GetOffsetMapping().EndOfLastNonCollapsedContent(position));
}
+
+TEST_F(NGOffsetMappingTest, WordBreak) {
+ SetupHtml("t", "<div id=t>a<wbr>b</div>");
+
+ const LayoutObject& text_a = *layout_object_;
+ const LayoutObject& wbr = *text_a.NextSibling();
+ const LayoutObject& text_b = *wbr.NextSibling();
+ const NGOffsetMapping& result = GetOffsetMapping();
+
+ EXPECT_EQ((Vector<NGOffsetMappingUnit>{
+ NGOffsetMappingUnit(kIdentity, text_a, 0u, 1u, 0u, 1u),
+ NGOffsetMappingUnit(kIdentity, wbr, 0u, 1u, 1u, 2u),
+ NGOffsetMappingUnit(kIdentity, text_b, 0u, 1u, 2u, 3u)}),
+ result.GetUnits());
+
+ EXPECT_EQ((Vector<NGOffsetMappingUnit>{
+ NGOffsetMappingUnit(kIdentity, wbr, 0u, 1u, 1u, 2u)}),
+ result.GetMappingUnitsForLayoutObject(wbr));
+}
+
// Test |GetOffsetMapping| which is available both for LayoutNG and for legacy.
class NGOffsetMappingGetterTest : public RenderingTest,
public testing::WithParamInterface<bool>,
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 2c37e28cbdd..aeaa0c8ba9a 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
@@ -84,7 +84,7 @@ PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflow(
PhysicalSize container_physical_size) const {
WritingMode container_writing_mode = container_style->GetWritingMode();
TextDirection container_direction = container_style->Direction();
- PhysicalRect overflow({}, Size());
+ PhysicalRect overflow;
for (const auto& child : Children()) {
PhysicalRect child_scroll_overflow =
child->ScrollableOverflowForPropagation(container);
@@ -116,6 +116,15 @@ PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflow(
}
overflow.Unite(child_scroll_overflow);
}
+
+ // Make sure we include the inline-size of the line-box in the overflow.
+ PhysicalRect rect;
+ if (IsHorizontalWritingMode(container_writing_mode))
+ rect.size.width = Size().width;
+ else
+ rect.size.height = Size().height;
+ overflow.UniteEvenIfEmpty(rect);
+
return overflow;
}
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 15980a27bae..b2e4a86c335 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
@@ -729,7 +729,12 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
if (LIKELY(IsLastFragment(physical_fragment)))
intrinsic_content_logical_height -= border_scrollbar_padding.BlockSum();
- box_->SetIntrinsicContentLogicalHeight(intrinsic_content_logical_height);
+ if (!constraint_space.IsFixedSizeBlock()) {
+ // If we had a fixed block size, our children will have sized themselves
+ // relative to the fixed size, which would make our intrinsic size
+ // incorrect (too big).
+ box_->SetIntrinsicContentLogicalHeight(intrinsic_content_logical_height);
+ }
// TODO(mstensho): This should always be done by the parent algorithm, since
// we may have auto margins, which only the parent is able to resolve. Remove
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 2f53751c117..ac5b8fee680 100644
--- a/chromium/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/chromium/third_party/blink/renderer/core/loader/image_loader.cc
@@ -668,7 +668,18 @@ void ImageLoader::DoUpdateFromElement(
params.SetLazyImageAutoReload();
}
- new_image_content = ImageResourceContent::Fetch(params, document.Fetcher());
+ if (lazy_image_load_state_ == LazyImageLoadState::kDeferred &&
+ was_fully_deferred_) {
+ // TODO(rajendrant): Remove this temporary workaround of creating a 1x1
+ // placeholder to fix an intersection observer issue not firing with
+ // certain styles (https://crbug.com/992765). Instead
+ // NoImageResourceToLoad() should be skipped when the image is deferred.
+ // https://crbug.com/999209
+ new_image_content = ImageResourceContent::CreateLazyImagePlaceholder();
+ } else {
+ new_image_content =
+ ImageResourceContent::Fetch(params, document.Fetcher());
+ }
// If this load is starting while navigating away, treat it as an auditing
// keepalive request, and don't report its results back to the element.
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 04b8d7dfc2f..b277d667a12 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
@@ -119,6 +119,14 @@ ImageResourceContent* ImageResourceContent::CreateLoaded(
return content;
}
+ImageResourceContent* ImageResourceContent::CreateLazyImagePlaceholder() {
+ ImageResourceContent* content = MakeGarbageCollected<ImageResourceContent>();
+ content->content_status_ = ResourceStatus::kCached;
+ content->image_ =
+ PlaceholderImage::CreateForLazyImages(content, IntSize(1, 1));
+ return content;
+}
+
ImageResourceContent* ImageResourceContent::Fetch(FetchParameters& params,
ResourceFetcher* fetcher) {
// TODO(hiroshige): Remove direct references to ImageResource by making
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 7c91be4f723..c022783bd1a 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
@@ -56,6 +56,8 @@ class CORE_EXPORT ImageResourceContent final
// Creates ImageResourceContent from an already loaded image.
static ImageResourceContent* CreateLoaded(scoped_refptr<blink::Image>);
+ static ImageResourceContent* CreateLazyImagePlaceholder();
+
static ImageResourceContent* Fetch(FetchParameters&, ResourceFetcher*);
explicit ImageResourceContent(scoped_refptr<blink::Image> = nullptr);
diff --git a/chromium/third_party/blink/renderer/core/page/DEPS b/chromium/third_party/blink/renderer/core/page/DEPS
new file mode 100644
index 00000000000..a45c5f7cb81
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ # For validation_message_overlay_delegate_test.cc
+ "+base/strings/utf_string_conversions.h",
+]
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 42ea986e571..4a16ce2d429 100644
--- a/chromium/third_party/blink/renderer/core/page/page_animator.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_animator.cc
@@ -30,6 +30,10 @@ void PageAnimator::Trace(blink::Visitor* visitor) {
void PageAnimator::ServiceScriptedAnimations(
base::TimeTicks monotonic_animation_start_time) {
base::AutoReset<bool> servicing(&servicing_animations_, true);
+
+ // Once we are inside a frame's lifecycle, the AnimationClock should hold its
+ // time value until the end of the frame.
+ Clock().SetAllowedToDynamicallyUpdateTime(false);
Clock().UpdateTime(monotonic_animation_start_time);
HeapVector<Member<Document>, 32> documents;
@@ -84,7 +88,7 @@ void PageAnimator::ServiceScriptedAnimations(
page_->GetValidationMessageClient().LayoutOverlay();
}
-void PageAnimator::RunPostAnimationFrameCallbacks() {
+void PageAnimator::PostAnimate() {
HeapVector<Member<Document>, 32> documents;
for (Frame* frame = page_->MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
@@ -92,8 +96,21 @@ void PageAnimator::RunPostAnimationFrameCallbacks() {
documents.push_back(To<LocalFrame>(frame)->GetDocument());
}
+ // Run the post-animation frame callbacks. See
+ // https://github.com/WICG/requestPostAnimationFrame
for (auto& document : documents)
document->RunPostAnimationFrameCallbacks();
+
+ // If we don't have an imminently incoming frame, we need to let the
+ // AnimationClock update its own time to properly service out-of-lifecycle
+ // events such as setInterval (see https://crbug.com/995806). This isn't a
+ // perfect heuristic, but at the very least we know that if there is a pending
+ // RAF we will be getting a new frame and thus don't need to unlock the clock.
+ bool next_frame_has_raf = false;
+ for (auto& document : documents)
+ next_frame_has_raf |= document->NextFrameHasPendingRAF();
+ if (!next_frame_has_raf)
+ Clock().SetAllowedToDynamicallyUpdateTime(true);
}
void PageAnimator::SetSuppressFrameRequestsWorkaroundFor704763Only(
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 0e2616f8385..84701414048 100644
--- a/chromium/third_party/blink/renderer/core/page/page_animator.h
+++ b/chromium/third_party/blink/renderer/core/page/page_animator.h
@@ -23,7 +23,7 @@ class CORE_EXPORT PageAnimator final : public GarbageCollected<PageAnimator> {
void ScheduleVisualUpdate(LocalFrame*);
void ServiceScriptedAnimations(
base::TimeTicks monotonic_animation_start_time);
- void RunPostAnimationFrameCallbacks();
+ void PostAnimate();
bool IsServicingAnimations() const { return servicing_animations_; }
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 d0777576a07..37f1a9d0cab 100644
--- a/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
+++ b/chromium/third_party/blink/renderer/core/page/page_widget_delegate.cc
@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/core/layout/layout_view.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/page/validation_message_client.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
@@ -49,10 +50,15 @@ void PageWidgetDelegate::Animate(Page& page,
base::TimeTicks monotonic_frame_begin_time) {
page.GetAutoscrollController().Animate();
page.Animator().ServiceScriptedAnimations(monotonic_frame_begin_time);
+ // The ValidationMessage overlay manages its own internal Page that isn't
+ // hooked up the normal BeginMainFrame flow, so we manually tick its
+ // animations here.
+ page.GetValidationMessageClient().ServiceScriptedAnimations(
+ monotonic_frame_begin_time);
}
void PageWidgetDelegate::PostAnimate(Page& page) {
- page.Animator().RunPostAnimationFrameCallbacks();
+ page.Animator().PostAnimate();
}
void PageWidgetDelegate::UpdateLifecycle(
diff --git a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
index caf3e53f6a5..a0489a1906b 100644
--- a/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
@@ -32,14 +32,15 @@ FragmentAnchor* FragmentAnchor::TryCreate(const KURL& url,
}
// Count how often we see a # in the fragment (i.e. after the # delimiting
- // the hash). We do this after trying to find a ##targetText so that we don't
- // pollute this metric with our own feature since we're trying to determine
- // how prevalent ## is. If a ##targetText is found, it'll strip off the ##
- // and any text following it.
+ // the hash). We avoid counting cases with ##targetText since we're trying to
+ // determine how often this happens outside our feature so we don't want to
+ // pollute it with our own usage.
if (url.HasFragmentIdentifier()) {
size_t hash_pos = url.FragmentIdentifier().Find("#");
- if (hash_pos != kNotFound)
- UseCounter::Count(frame.GetDocument(), WebFeature::kFragmentDoubleHash);
+ if (hash_pos != kNotFound) {
+ if (url.FragmentIdentifier().Find("#targetText=") == kNotFound)
+ UseCounter::Count(frame.GetDocument(), WebFeature::kFragmentDoubleHash);
+ }
}
bool element_id_anchor_found = false;
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 03cfaf8333a..a378d56b09f 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
@@ -356,11 +356,6 @@ TEST_P(TextFragmentRelatedMetricTest, DoubleHashUseCounter) {
const int kUncounted = 0;
const int kCounted = 1;
- // When the TextFragmentAnchors feature is on, we should avoid counting a
- // ##targetText directive as a use of double-hash in this case. When it's
- // off, we expect to count it.
- const int kCountedOnlyIfDisabled = !GetParam() ? kCounted : kUncounted;
-
Vector<std::pair<String, int>> test_cases = {
{"", kUncounted},
{"#element", kUncounted},
@@ -371,10 +366,14 @@ TEST_P(TextFragmentRelatedMetricTest, DoubleHashUseCounter) {
{"#element#", kCounted},
{"#foo#bar#", kCounted},
{"#foo%23", kUncounted},
- {"#element##targetText=doesntexist", kCountedOnlyIfDisabled},
- {"#element##targetText=doesntexist#", kCountedOnlyIfDisabled},
- {"#element##targetText=page", kCountedOnlyIfDisabled},
- {"#element##targetText=page#", kCountedOnlyIfDisabled},
+ {"#element##targetText=doesntexist", kUncounted},
+ {"#element##targetText=doesntexist#", kUncounted},
+ {"#element##targetText=page", kUncounted},
+ {"#element##targetText=page#", kUncounted},
+ {"##targetText=doesntexist", kUncounted},
+ {"##targetText=doesntexist#", kUncounted},
+ {"##targetText=page", kUncounted},
+ {"##targetText=page#", kUncounted},
{"#targetText=doesntexist", kUncounted},
{"#targetText=page", kUncounted}};
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_client.h b/chromium/third_party/blink/renderer/core/page/validation_message_client.h
index 09425262da3..8e9e1a248b4 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_client.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_client.h
@@ -62,6 +62,7 @@ class ValidationMessageClient : public GarbageCollectedMixin {
virtual void WillBeDestroyed() = 0;
+ virtual void ServiceScriptedAnimations(base::TimeTicks) {}
virtual void LayoutOverlay() {}
virtual void UpdatePrePaint() {}
// For CompositeAfterPaint.
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 7ab6b3b84f1..b9142462dd6 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
@@ -195,6 +195,12 @@ void ValidationMessageClientImpl::WillOpenPopup() {
HideValidationMessage(*current_anchor_);
}
+void ValidationMessageClientImpl::ServiceScriptedAnimations(
+ base::TimeTicks monotonic_frame_begin_time) {
+ if (overlay_)
+ overlay_->ServiceScriptedAnimations(monotonic_frame_begin_time);
+}
+
void ValidationMessageClientImpl::LayoutOverlay() {
if (overlay_)
CheckAnchorStatus(nullptr);
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 ead9a0db738..4e9cac17e36 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
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_CLIENT_IMPL_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_CLIENT_IMPL_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/popup_opening_observer.h"
#include "third_party/blink/renderer/core/page/validation_message_client.h"
@@ -40,7 +41,7 @@ class LocalFrameView;
class FrameOverlay;
class ValidationMessageOverlayDelegate;
-class ValidationMessageClientImpl final
+class CORE_EXPORT ValidationMessageClientImpl final
: public GarbageCollectedFinalized<ValidationMessageClientImpl>,
public ValidationMessageClient,
private PopupOpeningObserver {
@@ -50,8 +51,18 @@ class ValidationMessageClientImpl final
explicit ValidationMessageClientImpl(Page&);
~ValidationMessageClientImpl() override;
+ void ShowValidationMessage(const Element& anchor,
+ const String& message,
+ TextDirection message_dir,
+ const String& sub_message,
+ TextDirection sub_message_dir) override;
+
void Trace(blink::Visitor*) override;
+ ValidationMessageOverlayDelegate* GetDelegateForTesting() const {
+ return overlay_delegate_;
+ }
+
private:
void CheckAnchorStatus(TimerBase*);
LocalFrameView* CurrentView();
@@ -59,16 +70,12 @@ class ValidationMessageClientImpl final
void Reset(TimerBase*);
void ValidationMessageVisibilityChanged(const Element& anchor);
- void ShowValidationMessage(const Element& anchor,
- const String& message,
- TextDirection message_dir,
- const String& sub_message,
- TextDirection sub_message_dir) override;
void HideValidationMessage(const Element& anchor) override;
bool IsValidationMessageVisible(const Element& anchor) override;
void DocumentDetached(const Document&) override;
void DidChangeFocusTo(const Element* new_element) override;
void WillBeDestroyed() override;
+ void ServiceScriptedAnimations(base::TimeTicks) override;
void LayoutOverlay() override;
void UpdatePrePaint() override;
void PaintOverlay(GraphicsContext&) override;
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 8f738806995..604c73873d7 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
@@ -112,6 +112,11 @@ void ValidationMessageOverlayDelegate::PaintFrameOverlay(
}
}
+void ValidationMessageOverlayDelegate::ServiceScriptedAnimations(
+ base::TimeTicks monotonic_frame_begin_time) {
+ page_->Animator().ServiceScriptedAnimations(monotonic_frame_begin_time);
+}
+
void ValidationMessageOverlayDelegate::UpdateFrameViewState(
const FrameOverlay& overlay,
const IntSize& view_size) {
diff --git a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
index c48cfc16dd6..e3dfbb49c89 100644
--- a/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_OVERLAY_DELEGATE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_VALIDATION_MESSAGE_OVERLAY_DELEGATE_H_
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/frame_overlay.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -23,7 +24,8 @@ class Page;
// bubble is shown, and deleted when the bubble is closed.
//
// Ownership: A FrameOverlay instance owns a ValidationMessageOverlayDelegate.
-class ValidationMessageOverlayDelegate : public FrameOverlay::Delegate {
+class CORE_EXPORT ValidationMessageOverlayDelegate
+ : public FrameOverlay::Delegate {
public:
ValidationMessageOverlayDelegate(Page& main_page,
const Element& anchor,
@@ -34,12 +36,18 @@ class ValidationMessageOverlayDelegate : public FrameOverlay::Delegate {
~ValidationMessageOverlayDelegate() override;
void CreatePage(const FrameOverlay&);
+
+ // FrameOverlay::Delegate implementation.
void PaintFrameOverlay(const FrameOverlay&,
GraphicsContext&,
const IntSize& view_size) const override;
+ void ServiceScriptedAnimations(base::TimeTicks) override;
+
void StartToHide();
bool IsHiding() const;
+ Page* GetPageForTesting() const { return page_; }
+
private:
LocalFrameView& FrameView() const;
void UpdateFrameViewState(const FrameOverlay&, const IntSize& view_size);
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
new file mode 100644
index 00000000000..0a4a5a3b699
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc
@@ -0,0 +1,139 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/page/validation_message_overlay_delegate.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#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/page/page_widget_delegate.h"
+#include "third_party/blink/renderer/core/page/validation_message_client.h"
+#include "third_party/blink/renderer/core/page/validation_message_client_impl.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/web_test_support.h"
+
+#if defined(OS_WIN)
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/blink/public/web/win/web_font_rendering.h"
+#endif
+
+namespace blink {
+
+class ValidationMessageOverlayDelegateTest : public PaintTestConfigurations,
+ public RenderingTest {
+#if defined(OS_WIN)
+ public:
+ void SetUp() override {
+ RenderingTest::SetUp();
+
+ // These tests appear to trigger a requirement for system fonts. On windows,
+ // 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);
+ }
+#endif
+};
+
+INSTANTIATE_PAINT_TEST_SUITE_P(ValidationMessageOverlayDelegateTest);
+
+// Regression test for https://crbug.com/990680, where we accidentally
+// composited the animations created by ValidationMessageOverlayDelegate. Since
+// overlays operate in a Page that has no compositor, the animations broke.
+TEST_P(ValidationMessageOverlayDelegateTest,
+ OverlayAnimationsShouldNotBeComposited) {
+ // When WebTestSupport::IsRunningWebTest is set, the animations in
+ // ValidationMessageOverlayDelegate are disabled. We are specifically testing
+ // animations, so make sure that doesn't happen.
+ bool was_running_web_test = WebTestSupport::IsRunningWebTest();
+ WebTestSupport::SetIsRunningWebTest(false);
+
+ SetBodyInnerHTML("<div id='anchor'></div>");
+ Element* anchor = GetElementById("anchor");
+ ASSERT_TRUE(anchor);
+
+ auto delegate = std::make_unique<ValidationMessageOverlayDelegate>(
+ GetPage(), *anchor, "Test message", TextDirection::kLtr, "Sub-message",
+ TextDirection::kLtr);
+ ValidationMessageOverlayDelegate* delegate_ptr = delegate.get();
+
+ auto overlay =
+ std::make_unique<FrameOverlay>(&GetFrame(), std::move(delegate));
+ delegate_ptr->CreatePage(*overlay);
+ ASSERT_TRUE(
+ GetFrame().View()->UpdateLifecycleToCompositingCleanPlusScrolling());
+
+ // Trigger the overlay animations.
+ auto paint_controller =
+ std::make_unique<PaintController>(PaintController::kTransient);
+ GraphicsContext context(*paint_controller);
+ overlay->Paint(context);
+
+ // Now find the related animations, and make sure they weren't composited.
+ Document* internal_document =
+ To<LocalFrame>(delegate_ptr->GetPageForTesting()->MainFrame())
+ ->GetDocument();
+ HeapVector<Member<Animation>> animations =
+ internal_document->Timeline().getAnimations();
+ ASSERT_FALSE(animations.IsEmpty());
+
+ for (const auto& animation : animations) {
+ EXPECT_FALSE(animation->HasActiveAnimationsOnCompositor());
+ }
+
+ WebTestSupport::SetIsRunningWebTest(was_running_web_test);
+}
+
+// Regression test for https://crbug.com/990680, where we found we were not
+// properly advancing the AnimationClock in the internal Page created by
+// ValidationMessageOverlayDelegate. When combined with the fix for
+// https://crbug.com/785940, this caused Animations to never be updated.
+TEST_P(ValidationMessageOverlayDelegateTest,
+ DelegatesInternalPageShouldHaveAnimationTimesUpdated) {
+ // We use a ValidationMessageClientImpl here to create our delegate since we
+ // need the official path from PageWidgetDelegate::Animate to work.
+ auto* client = MakeGarbageCollected<ValidationMessageClientImpl>(GetPage());
+ ValidationMessageClient* original_client =
+ &GetPage().GetValidationMessageClient();
+ GetPage().SetValidationMessageClientForTesting(client);
+
+ SetBodyInnerHTML(R"HTML(
+ <style>#anchor { width: 100px; height: 100px; }</style>
+ <div id='anchor'></div>
+ )HTML");
+ Element* anchor = GetElementById("anchor");
+ ASSERT_TRUE(anchor);
+
+ client->ShowValidationMessage(*anchor, "Test message", TextDirection::kLtr,
+ "Sub-message", TextDirection::kLtr);
+ ValidationMessageOverlayDelegate* delegate = client->GetDelegateForTesting();
+ ASSERT_TRUE(delegate);
+
+ // Initially the AnimationClock will be at 0.
+ // TODO(crbug.com/785940): Re-enable this EXPECT_EQ once the AnimationClock no
+ // longer jumps ahead on its own accord.
+ AnimationClock& internal_clock =
+ delegate->GetPageForTesting()->Animator().Clock();
+ // EXPECT_EQ(internal_clock.CurrentTime(), 0);
+
+ // Now update the main Page's clock. This should trickle down and update the
+ // inner Page's clock too.
+ AnimationClock& external_clock = GetPage().Animator().Clock();
+ base::TimeTicks current_time = external_clock.CurrentTime();
+
+ base::TimeTicks new_time = current_time + base::TimeDelta::FromSeconds(1);
+ PageWidgetDelegate::Animate(GetPage(), new_time);
+
+ // TODO(crbug.com/785940): Until this bug is fixed, this comparison could pass
+ // even if the underlying behavior regresses (because calling CurrentTime
+ // could advance the clocks anyway).
+ EXPECT_EQ(external_clock.CurrentTime(), internal_clock.CurrentTime());
+
+ GetPage().SetValidationMessageClientForTesting(original_client);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/audits/auditsPanel.css b/chromium/third_party/blink/renderer/devtools/front_end/audits/auditsPanel.css
index bba66cffaa9..4a1819cc917 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/audits/auditsPanel.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/audits/auditsPanel.css
@@ -28,6 +28,6 @@ button.view-trace {
/** `window.opener` is null for windows opened from DevTools. This breaks
the LH viewer app, so disable this feature. */
-.lh-export--viewer {
+.lh-tools--viewer {
display: none !important;
}
diff --git a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
index 7b5253ab56e..92be9fe9c0e 100644
--- a/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
+++ b/chromium/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
@@ -441,7 +441,7 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
}
.CodeMirror .text-editor-coverage-unused-marker::after {
- content: " ";
+ content: "\200B";
}
.CodeMirror .text-editor-coverage-used-marker {
@@ -451,7 +451,7 @@ div.CodeMirror:focus-within span.CodeMirror-nonmatchingbracket {
}
.CodeMirror .text-editor-coverage-used-marker::after {
- content: " ";
+ content: "\200B";
}
.CodeMirror .text-editor-line-decoration {
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 d3ca692a2fa..5eaeb7e4cc2 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
@@ -607,12 +607,25 @@ bool AXLayoutObject::ComputeAccessibilityIsIgnored(
DCHECK(initialized_);
#endif
+ // All nodes must have an unignored parent within their tree under
+ // kRootWebArea, so force kRootWebArea to always be unignored.
+ if (role_ == ax::mojom::Role::kRootWebArea)
+ return false;
+
if (!layout_object_) {
if (ignored_reasons)
ignored_reasons->push_back(IgnoredReason(kAXNotRendered));
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;
+ }
+
// Check first if any of the common reasons cause this element to be ignored.
AXObjectInclusion default_inclusion = DefaultObjectInclusion(ignored_reasons);
if (default_inclusion == kIncludeObject)
@@ -633,14 +646,6 @@ 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;
- }
-
// 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())
@@ -2045,8 +2050,12 @@ void AXLayoutObject::AddChildren() {
if (IsDetached())
return;
+ // Avoid calling AXNodeObject logic for continuations.
+ bool is_continuation = layout_object_->IsElementContinuation();
+
if (auto* element = DynamicTo<Element>(GetNode())) {
- if (!IsHTMLMapElement(*element) && // Handled in AddImageMapChildren (img)
+ if (!is_continuation &&
+ !IsHTMLMapElement(*element) && // Handled in AddImageMapChildren (img)
!IsHTMLRubyElement(*element) && // Special layout handling
!IsHTMLTableElement(*element) && // thead/tfoot move around
!element->IsPseudoElement()) { // Not visited in layout traversal
@@ -2065,10 +2074,8 @@ void AXLayoutObject::AddChildren() {
ComputeAriaOwnsChildren(owned_children);
for (AXObject* obj = RawFirstChild(); obj; obj = obj->RawNextSibling()) {
- if (!AXObjectCache().IsAriaOwned(obj)) {
- obj->SetParent(this);
+ if (!AXObjectCache().IsAriaOwned(obj))
AddChild(obj);
- }
}
AddHiddenChildren();
@@ -2080,8 +2087,11 @@ void AXLayoutObject::AddChildren() {
AddAccessibleNodeChildren();
for (const auto& child : children_) {
- if (!child->CachedParentObject())
+ if (!is_continuation && !child->CachedParentObject()) {
+ // Never set continuations as a parent object. The first layout object
+ // in the chain must be used instead.
child->SetParent(this);
+ }
}
for (const auto& owned_child : owned_children)
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 5c76a39946c..e3d7132ddd8 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
@@ -332,6 +332,12 @@ bool AXNodeObject::ComputeAccessibilityIsIgnored(
// it's been initialized.
DCHECK(initialized_);
#endif
+
+ // All nodes must have an unignored parent within their tree under
+ // kRootWebArea, so force kRootWebArea to always be unignored.
+ if (role_ == ax::mojom::Role::kRootWebArea)
+ return false;
+
if (GetLayoutObject()) {
if (role_ == ax::mojom::Role::kUnknown) {
if (ignored_reasons)
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 9b6f96373c8..c84797f978b 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
@@ -442,8 +442,8 @@ VideoTrackRecorder::VideoTrackRecorder(
DCHECK(track_->Source()->GetType() == MediaStreamSource::kTypeVideo);
initialize_encoder_callback_ = WTF::BindRepeating(
- &VideoTrackRecorder::InitializeEncoder, weak_ptr_factory_.GetWeakPtr(),
- codec, on_encoded_video_callback, bits_per_second);
+ &VideoTrackRecorder::InitializeEncoder, WrapWeakPersistent(this), codec,
+ on_encoded_video_callback, bits_per_second);
// InitializeEncoder() will be called on Render Main thread.
ConnectToTrack(media::BindToCurrentLoop(WTF::BindRepeating(
@@ -508,7 +508,7 @@ void VideoTrackRecorder::InitializeEncoder(
encoder_ = VEAEncoder::Create(
on_encoded_video_callback,
media::BindToCurrentLoop(WTF::BindRepeating(
- &VideoTrackRecorder::OnError, weak_ptr_factory_.GetWeakPtr())),
+ &VideoTrackRecorder::OnError, WrapWeakPersistent(this))),
bits_per_second, vea_profile, input_size, main_task_runner_);
} else {
UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", false);
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 ae8c208b615..f9d37271fdc 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
@@ -317,8 +317,6 @@ class MODULES_EXPORT VideoTrackRecorder
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
- base::WeakPtrFactory<VideoTrackRecorder> weak_ptr_factory_{this};
-
DISALLOW_COPY_AND_ASSIGN(VideoTrackRecorder);
};
diff --git a/chromium/third_party/blink/renderer/platform/graphics/color_behavior.h b/chromium/third_party/blink/renderer/platform/graphics/color_behavior.h
index ce04f84a5c5..7d3c6ab9616 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/color_behavior.h
+++ b/chromium/third_party/blink/renderer/platform/graphics/color_behavior.h
@@ -7,6 +7,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/cross_thread_copier.h"
#include "ui/gfx/color_space.h"
namespace blink {
@@ -49,4 +50,15 @@ class PLATFORM_EXPORT ColorBehavior {
} // namespace blink
+namespace WTF {
+
+template <>
+struct CrossThreadCopier<blink::ColorBehavior> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = blink::ColorBehavior;
+ static Type Copy(Type pointer) { return pointer; }
+};
+
+} // namespace WTF
+
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_BEHAVIOR_H_
diff --git a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
index 3775eab8b07..e4fac40131b 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
+++ b/chromium/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -292,6 +292,7 @@ jumbo_source_set("wtf_unittests_sources") {
"allocator/partitions_test.cc",
"ascii_ctype_test.cc",
"assertions_test.cc",
+ "cross_thread_functional_test.cc",
"decimal_test.cc",
"deque_test.cc",
"doubly_linked_list_test.cc",
diff --git a/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional.h b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional.h
index 2940e661189..92706732025 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional.h
@@ -33,30 +33,65 @@ namespace WTF {
// Bind(&Func1, 42, str);
// Bind(&Func1, 42, str.IsolatedCopy());
+namespace internal {
+
+// Deduction of the signature to avoid complicated calls to MakeUnboundRunType.
+
+template <typename Signature>
+auto MakeCrossThreadFunction(base::RepeatingCallback<Signature> callback) {
+ return CrossThreadFunction<Signature>(std::move(callback));
+}
+
+template <typename Signature>
+auto MakeCrossThreadOnceFunction(base::OnceCallback<Signature> callback) {
+ return CrossThreadOnceFunction<Signature>(std::move(callback));
+}
+
+// Insertion of coercion for specific types; transparent forwarding otherwise.
+
+template <typename T>
+decltype(auto) CoerceFunctorForCrossThreadBind(T&& functor) {
+ return std::forward<T>(functor);
+}
+
+template <typename Signature>
+base::RepeatingCallback<Signature> CoerceFunctorForCrossThreadBind(
+ CrossThreadFunction<Signature>&& functor) {
+ return ConvertToBaseCallback(std::move(functor));
+}
+
+template <typename Signature>
+base::OnceCallback<Signature> CoerceFunctorForCrossThreadBind(
+ CrossThreadOnceFunction<Signature>&& functor) {
+ return ConvertToBaseOnceCallback(std::move(functor));
+}
+
+} // namespace internal
+
template <typename FunctionType, typename... Ps>
-CrossThreadFunction<base::MakeUnboundRunType<FunctionType, Ps...>>
-CrossThreadBindRepeating(FunctionType&& function, Ps&&... parameters) {
+auto CrossThreadBindRepeating(FunctionType&& function, Ps&&... parameters) {
static_assert(
internal::CheckGCedTypeRestrictions<std::index_sequence_for<Ps...>,
std::decay_t<Ps>...>::ok,
"A bound argument uses a bad pattern.");
- using UnboundRunType = base::MakeUnboundRunType<FunctionType, Ps...>;
- return CrossThreadFunction<UnboundRunType>(
- base::Bind(function, CrossThreadCopier<std::decay_t<Ps>>::Copy(
- std::forward<Ps>(parameters))...));
+ return internal::MakeCrossThreadFunction(
+ base::Bind(internal::CoerceFunctorForCrossThreadBind(
+ std::forward<FunctionType>(function)),
+ CrossThreadCopier<std::decay_t<Ps>>::Copy(
+ std::forward<Ps>(parameters))...));
}
template <typename FunctionType, typename... Ps>
-CrossThreadOnceFunction<base::MakeUnboundRunType<FunctionType, Ps...>>
-CrossThreadBindOnce(FunctionType&& function, Ps&&... parameters) {
+auto CrossThreadBindOnce(FunctionType&& function, Ps&&... parameters) {
static_assert(
internal::CheckGCedTypeRestrictions<std::index_sequence_for<Ps...>,
std::decay_t<Ps>...>::ok,
"A bound argument uses a bad pattern.");
- using UnboundRunType = base::MakeUnboundRunType<FunctionType, Ps...>;
- return CrossThreadOnceFunction<UnboundRunType>(base::BindOnce(
- std::move(function), CrossThreadCopier<std::decay_t<Ps>>::Copy(
- std::forward<Ps>(parameters))...));
+ return internal::MakeCrossThreadOnceFunction(
+ base::BindOnce(internal::CoerceFunctorForCrossThreadBind(
+ std::forward<FunctionType>(function)),
+ CrossThreadCopier<std::decay_t<Ps>>::Copy(
+ std::forward<Ps>(parameters))...));
}
} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional_test.cc b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional_test.cc
new file mode 100644
index 00000000000..35639f18423
--- /dev/null
+++ b/chromium/third_party/blink/renderer/platform/wtf/cross_thread_functional_test.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+
+#include <utility>
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace WTF {
+namespace {
+
+// Tests that "currying" CrossThreadFunction and CrossThreadOnceFunction works,
+// as it does with the base counterparts.
+
+struct SomeFunctor;
+
+static_assert(std::is_same<decltype(internal::CoerceFunctorForCrossThreadBind(
+ std::declval<SomeFunctor&>())),
+ SomeFunctor&>(),
+ "functor coercion should not affect Functor lvalue ref type");
+static_assert(std::is_same<decltype(internal::CoerceFunctorForCrossThreadBind(
+ std::declval<SomeFunctor>())),
+ SomeFunctor&&>(),
+ "functor coercion should not affect Functor rvalue ref type");
+
+TEST(CrossThreadFunctionalTest, CrossThreadBindRepeating_CrossThreadFunction) {
+ auto adder = CrossThreadBindRepeating([](int x, int y) { return x + y; });
+ auto five_adder = CrossThreadBindRepeating(std::move(adder), 5);
+ EXPECT_EQ(five_adder.Run(7), 12);
+}
+
+TEST(CrossThreadFunctionalTest, CrossThreadBindOnce_CrossThreadOnceFunction) {
+ auto adder = CrossThreadBindOnce([](int x, int y) { return x + y; });
+ auto five_adder = CrossThreadBindOnce(std::move(adder), 5);
+ EXPECT_EQ(std::move(five_adder).Run(7), 12);
+}
+
+TEST(CrossThreadFunctionalTest, CrossThreadBindOnce_CrossThreadFunction) {
+ auto adder = CrossThreadBindRepeating([](int x, int y) { return x + y; });
+ auto five_adder = CrossThreadBindOnce(std::move(adder), 5);
+ EXPECT_EQ(std::move(five_adder).Run(7), 12);
+}
+
+} // namespace
+} // namespace WTF
diff --git a/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h b/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
index 601046eca67..14d9943c352 100644
--- a/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
+++ b/chromium/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
@@ -32,6 +32,7 @@
#include "base/memory/scoped_refptr.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/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/wtf.h"
#include "third_party/blink/renderer/platform/wtf/wtf_export.h"
@@ -56,6 +57,8 @@ class WTF_EXPORT ArrayBufferContents {
DISALLOW_COPY_AND_ASSIGN(DataHandle);
public:
+ DataHandle() : DataHandle(nullptr, 0, nullptr, nullptr) {}
+
DataHandle(void* data,
size_t length,
DataDeleter deleter,
@@ -82,6 +85,8 @@ class WTF_EXPORT ArrayBufferContents {
return *this;
}
+ void reset() { *this = DataHandle(); }
+
void* Data() const { return data_; }
size_t DataLength() const { return data_length_; }
@@ -226,6 +231,15 @@ class WTF_EXPORT ArrayBufferContents {
DISALLOW_COPY_AND_ASSIGN(ArrayBufferContents);
};
+template <>
+struct CrossThreadCopier<ArrayBufferContents::DataHandle> {
+ STATIC_ONLY(CrossThreadCopier);
+ using Type = ArrayBufferContents::DataHandle;
+ static Type Copy(Type handle) {
+ return handle; // This is in fact a move.
+ }
+};
+
} // namespace WTF
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TYPED_ARRAYS_ARRAY_BUFFER_CONTENTS_H_
diff --git a/chromium/third_party/skia/src/pdf/SkPDFFont.cpp b/chromium/third_party/skia/src/pdf/SkPDFFont.cpp
index 33ec05b76ab..ba79a15c9a5 100644
--- a/chromium/third_party/skia/src/pdf/SkPDFFont.cpp
+++ b/chromium/third_party/skia/src/pdf/SkPDFFont.cpp
@@ -231,7 +231,11 @@ SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
: fTypeface(std::move(typeface))
, fGlyphUsage(firstGlyphID, lastGlyphID)
, fIndirectReference(indirectReference)
- , fFontType(fontType) {}
+ , fFontType(fontType)
+{
+ // Always include glyph 0
+ this->noteGlyphUsage(0);
+}
void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
const SkAdvancedTypefaceMetrics& metrics,
@@ -290,7 +294,7 @@ static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
auto descriptor = SkPDFMakeDict("FontDescriptor");
uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm());
- SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize , 0);
+ SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
int ttcIndex;
std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex);
@@ -369,7 +373,7 @@ static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
SkScalar defaultWidth = 0;
{
std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
- *face, &font.glyphUsage(), &defaultWidth);
+ *face, font.glyphUsage(), &defaultWidth);
if (widths && widths->size() > 0) {
newCIDFont->insertObject("W", std::move(widths));
}
diff --git a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
index 589cfa76202..210202db4d1 100644
--- a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
+++ b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
@@ -13,6 +13,7 @@
#include "src/core/SkStrikeSpec.h"
#include "src/pdf/SkPDFGlyphUse.h"
+#include <algorithm>
#include <vector>
// TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray().
@@ -23,28 +24,8 @@
namespace {
-struct AdvanceMetric {
- enum MetricType {
- kDefault, // Default advance: fAdvance.count = 1
- kRange, // Advances for a range: fAdvance.count = fEndID-fStartID
- kRun // fStartID-fEndID have same advance: fAdvance.count = 1
- };
- MetricType fType;
- uint16_t fStartId;
- uint16_t fEndId;
- std::vector<int16_t> fAdvance;
- AdvanceMetric(uint16_t startId) : fStartId(startId) {}
- AdvanceMetric(AdvanceMetric&&) = default;
- AdvanceMetric& operator=(AdvanceMetric&& other) = default;
- AdvanceMetric(const AdvanceMetric&) = delete;
- AdvanceMetric& operator=(const AdvanceMetric&) = delete;
-};
-const int16_t kInvalidAdvance = SK_MinS16;
-const int16_t kDontCareAdvance = SK_MinS16 + 1;
-} // namespace
-
// scale from em-units to base-1000, returning as a SkScalar
-static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
+SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
if (emSize == 1000) {
return scaled;
} else {
@@ -52,224 +33,174 @@ static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
}
}
-static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
+SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
return from_font_units(SkIntToScalar(val), emSize);
}
-static void strip_uninteresting_trailing_advances_from_range(
- AdvanceMetric* range) {
- SkASSERT(range);
-
- int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
- if (SkToInt(range->fAdvance.size()) < expectedAdvanceCount) {
- return;
- }
-
- for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
- if (range->fAdvance[i] != kDontCareAdvance &&
- range->fAdvance[i] != kInvalidAdvance &&
- range->fAdvance[i] != 0) {
- range->fEndId = range->fStartId + i;
- break;
- }
- }
-}
-
-static void zero_wildcards_in_range(AdvanceMetric* range) {
- SkASSERT(range);
- if (range->fType != AdvanceMetric::kRange) {
- return;
+// Unfortunately poppler does not appear to respect the default width setting.
+#if defined(SK_PDF_CAN_USE_DW)
+int16_t findMode(SkSpan<const int16_t> advances) {
+ if (advances.empty()) {
+ return 0;
}
- SkASSERT(SkToInt(range->fAdvance.size()) == range->fEndId - range->fStartId + 1);
- // Zero out wildcards.
- for (size_t i = 0; i < range->fAdvance.size(); ++i) {
- if (range->fAdvance[i] == kDontCareAdvance) {
- range->fAdvance[i] = 0;
- }
- }
-}
+ int16_t previousAdvance = advances[0];
+ int16_t currentModeAdvance = advances[0];
+ size_t currentCount = 1;
+ size_t currentModeCount = 1;
-static void finish_range(
- AdvanceMetric* range,
- int endId,
- AdvanceMetric::MetricType type) {
- range->fEndId = endId;
- range->fType = type;
- strip_uninteresting_trailing_advances_from_range(range);
- size_t newLength;
- if (type == AdvanceMetric::kRange) {
- newLength = range->fEndId - range->fStartId + 1;
- } else {
- if (range->fEndId == range->fStartId) {
- range->fType = AdvanceMetric::kRange;
+ for (size_t i = 1; i < advances.size(); ++i) {
+ if (advances[i] == previousAdvance) {
+ ++currentCount;
+ } else {
+ if (currentCount > currentModeCount) {
+ currentModeAdvance = previousAdvance;
+ currentModeCount = currentCount;
+ }
+ previousAdvance = advances[i];
+ currentCount = 1;
}
- newLength = 1;
}
- SkASSERT(range->fAdvance.size() >= newLength);
- range->fAdvance.resize(newLength);
- zero_wildcards_in_range(range);
-}
-static void compose_advance_data(const AdvanceMetric& range,
- uint16_t emSize,
- SkScalar* defaultAdvance,
- SkPDFArray* result) {
- switch (range.fType) {
- case AdvanceMetric::kDefault: {
- SkASSERT(range.fAdvance.size() == 1);
- *defaultAdvance = scale_from_font_units(range.fAdvance[0], emSize);
- break;
- }
- case AdvanceMetric::kRange: {
- auto advanceArray = SkPDFMakeArray();
- for (size_t j = 0; j < range.fAdvance.size(); j++)
- advanceArray->appendScalar(scale_from_font_units(range.fAdvance[j], emSize));
- result->appendInt(range.fStartId);
- result->appendObject(std::move(advanceArray));
- break;
- }
- case AdvanceMetric::kRun: {
- SkASSERT(range.fAdvance.size() == 1);
- result->appendInt(range.fStartId);
- result->appendInt(range.fEndId);
- result->appendScalar(scale_from_font_units(range.fAdvance[0], emSize));
- break;
- }
- }
+ return currentCount > currentModeCount ? previousAdvance : currentModeAdvance;
}
+#endif
+} // namespace
/** Retrieve advance data for glyphs. Used by the PDF backend. */
// TODO(halcanary): this function is complex enough to need its logic
// tested with unit tests.
std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface,
- const SkPDFGlyphUse* subset,
+ const SkPDFGlyphUse& subset,
SkScalar* defaultAdvance) {
- // Assuming that on average, the ASCII representation of an advance plus
- // a space is 8 characters and the ASCII representation of a glyph id is 3
- // characters, then the following cut offs for using different range types
- // apply:
- // The cost of stopping and starting the range is 7 characters
- // a. Removing 4 0's or don't care's is a win
- // The cost of stopping and starting the range plus a run is 22
- // characters
- // b. Removing 3 repeating advances is a win
- // c. Removing 2 repeating advances and 3 don't cares is a win
- // When not currently in a range the cost of a run over a range is 16
- // characters, so:
- // d. Removing a leading 0/don't cares is a win because it is omitted
- // e. Removing 2 repeating advances is a win
+ // There are two ways of expressing advances
+ //
+ // range: " gfid [adv.ances adv.ances ... adv.ances]"
+ // run: " gfid gfid adv.ances"
+ //
+ // Assuming that on average
+ // the ASCII representation of an advance plus a space is 10 characters
+ // the ASCII representation of a glyph id plus a space is 4 characters
+ // the ASCII representation of unused gid plus a space in a range is 2 characters
+ //
+ // When not in a range or run
+ // a. Skipping don't cares or defaults is a win (trivial)
+ // b. Run wins for 2+ repeats " gid gid adv.ances"
+ // " gid [adv.ances adv.ances]"
+ // rule: 2+ repeats create run as long as possible, else start range
+ //
+ // When in a range
+ // Cost of stopping and starting a range is 8 characters "] gid ["
+ // c. Skipping defaults is always a win " adv.ances"
+ // rule: end range if default seen
+ // d. Skipping 4+ don't cares is a win " 0 0 0 0"
+ // rule: end range if 4+ don't cares
+ // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid ["
+ // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances"
+ // rule: end range for 2+ repeats with 4+ don't cares
+ // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances"
+ // rule: end range for 3+ repeats
int emSize;
SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize);
SkBulkGlyphMetricsAndPaths paths{strikeSpec};
auto result = SkPDFMakeArray();
- int num_glyphs = SkToInt(typeface.countGlyphs());
-
- bool prevRange = false;
-
- int16_t lastAdvance = kInvalidAdvance;
- int repeatedAdvances = 0;
- int wildCardsInRun = 0;
- int trailingWildCards = 0;
- // Limit the loop count to glyph id ranges provided.
- int lastIndex = num_glyphs;
- if (subset) {
- while (!subset->has(lastIndex - 1) && lastIndex > 0) {
- --lastIndex;
- }
- }
- AdvanceMetric curRange(0);
-
- SkAutoTArray<SkGlyphID> glyphIDs{lastIndex + 1};
- for (int gId = 0; gId <= lastIndex; gId++) {
- glyphIDs[gId] = gId;
+ std::vector<SkGlyphID> glyphIDs;
+ subset.getSetValues([&](unsigned index) {
+ glyphIDs.push_back(SkToU16(index));
+ });
+ auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs));
+
+#if defined(SK_PDF_CAN_USE_DW)
+ std::vector<int16_t> advances;
+ advances.reserve(glyphs.size());
+ for (const SkGlyph* glyph : glyphs) {
+ advances.push_back((int16_t)glyph->advanceX());
}
-
- auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs.get(), lastIndex + 1));
-
- for (int gId = 0; gId <= lastIndex; gId++) {
- int16_t advance = kInvalidAdvance;
- if (gId < lastIndex) {
- if (!subset || 0 == gId || subset->has(gId)) {
- advance = (int16_t)glyphs[gId]->advanceX();
- } else {
- advance = kDontCareAdvance;
- }
+ std::sort(advances.begin(), advances.end());
+ int16_t modeAdvance = findMode(SkMakeSpan(advances));
+ *defaultAdvance = scale_from_font_units(modeAdvance, emSize);
+#else
+ *defaultAdvance = 0;
+#endif
+
+ for (size_t i = 0; i < glyphs.size(); ++i) {
+ int16_t advance = (int16_t)glyphs[i]->advanceX();
+
+#if defined(SK_PDF_CAN_USE_DW)
+ // a. Skipping don't cares or defaults is a win (trivial)
+ if (advance == modeAdvance) {
+ continue;
}
- if (advance == lastAdvance) {
- repeatedAdvances++;
- trailingWildCards = 0;
- } else if (advance == kDontCareAdvance) {
- wildCardsInRun++;
- trailingWildCards++;
- } else if (SkToInt(curRange.fAdvance.size()) ==
- repeatedAdvances + 1 + wildCardsInRun) { // All in run.
- if (lastAdvance == 0) {
- curRange.fStartId = gId; // reset
- curRange.fAdvance.resize(0);
- trailingWildCards = 0;
- } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
- finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
- prevRange = true;
- curRange = AdvanceMetric(gId);
- trailingWildCards = 0;
+#endif
+
+ // b. 2+ repeats create run as long as possible, else start range
+ {
+ size_t j = i + 1; // j is always one past the last known repeat
+ for (; j < glyphs.size(); ++j) {
+ int16_t next_advance = (int16_t)glyphs[j]->advanceX();
+ if (advance != next_advance) {
+ break;
+ }
}
- repeatedAdvances = 0;
- wildCardsInRun = trailingWildCards;
- trailingWildCards = 0;
- } else {
- if (lastAdvance == 0 &&
- repeatedAdvances + 1 + wildCardsInRun >= 4) {
- finish_range(&curRange,
- gId - repeatedAdvances - wildCardsInRun - 2,
- AdvanceMetric::kRange);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
- prevRange = true;
- curRange = AdvanceMetric(gId);
- trailingWildCards = 0;
- } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
- finish_range(&curRange, gId - trailingWildCards - 1,
- AdvanceMetric::kRange);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
- prevRange = true;
- curRange = AdvanceMetric(gId);
- trailingWildCards = 0;
- } else if (lastAdvance != 0 &&
- (repeatedAdvances + 1 >= 3 ||
- (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
- finish_range(&curRange,
- gId - repeatedAdvances - wildCardsInRun - 2,
- AdvanceMetric::kRange);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
- curRange =
- AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
- curRange.fAdvance.push_back(lastAdvance);
- finish_range(&curRange, gId - 1, AdvanceMetric::kRun);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
- prevRange = true;
- curRange = AdvanceMetric(gId);
- trailingWildCards = 0;
+ if (j - i >= 2) {
+ result->appendInt(glyphs[i]->getGlyphID());
+ result->appendInt(glyphs[j - 1]->getGlyphID());
+ result->appendScalar(scale_from_font_units(advance, emSize));
+ i = j - 1;
+ continue;
}
- repeatedAdvances = 0;
- wildCardsInRun = trailingWildCards;
- trailingWildCards = 0;
- }
- curRange.fAdvance.push_back(advance);
- if (advance != kDontCareAdvance) {
- lastAdvance = advance;
}
- }
- if (curRange.fStartId == lastIndex) {
- if (!prevRange) {
- return nullptr; // https://crbug.com/567031
+
+ {
+ result->appendInt(glyphs[i]->getGlyphID());
+ auto advanceArray = SkPDFMakeArray();
+ advanceArray->appendScalar(scale_from_font_units(advance, emSize));
+ size_t j = i + 1; // j is always one past the last output
+ for (; j < glyphs.size(); ++j) {
+ advance = (int16_t)glyphs[j]->advanceX();
+#if defined(SK_PDF_CAN_USE_DW)
+ // c. end range if default seen
+ if (advance == modeAdvance) {
+ break;
+ }
+#endif
+
+ int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1;
+ // d. end range if 4+ don't cares
+ if (dontCares >= 4) {
+ break;
+ }
+
+ int16_t next_advance = 0;
+ // e. end range for 2+ repeats with 4+ don't cares
+ if (j + 1 < glyphs.size()) {
+ next_advance = (int16_t)glyphs[j+1]->advanceX();
+ int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1;
+ if (advance == next_advance && dontCares + next_dontCares >= 4) {
+ break;
+ }
+ }
+
+ // f. end range for 3+ repeats
+ if (j + 2 < glyphs.size() && advance == next_advance) {
+ next_advance = (int16_t)glyphs[j+2]->advanceX();
+ if (advance == next_advance) {
+ break;
+ }
+ }
+
+ while (dontCares --> 0) {
+ advanceArray->appendScalar(0);
+ }
+ advanceArray->appendScalar(scale_from_font_units(advance, emSize));
+ }
+ result->appendObject(std::move(advanceArray));
+ i = j - 1;
}
- } else {
- finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange);
- compose_advance_data(curRange, emSize, defaultAdvance, result.get());
}
+
return result;
}
diff --git a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
index b2e1e1df55a..041fe28d8cb 100644
--- a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
+++ b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
@@ -17,7 +17,7 @@ class SkTypeface;
format that can specify individual widths for consecutive CIDs or
one width for a range of CIDs". */
std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface,
- const SkPDFGlyphUse* subset,
+ const SkPDFGlyphUse& subset,
SkScalar* defaultAdvance);
#endif // SkPDFMakeCIDGlyphWidthsArray_DEFINED
diff --git a/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp b/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp
index 0bb92bb9622..5485f3b4ba3 100644
--- a/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp
+++ b/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp
@@ -68,7 +68,6 @@ static sk_sp<SkData> subset_harfbuzz(sk_sp<SkData> fontData,
return nullptr;
}
hb_set_t* glyphs = hb_subset_input_glyph_set(input.get());
- hb_set_add(glyphs, 0);
glyphUsage.getSetValues([&glyphs](unsigned gid) { hb_set_add(glyphs, gid);});
hb_subset_input_set_retain_gids(input.get(), true);
@@ -99,9 +98,6 @@ static sk_sp<SkData> subset_sfntly(sk_sp<SkData> fontData,
// Generate glyph id array in format needed by sfntly.
// TODO(halcanary): sfntly should take a more compact format.
std::vector<unsigned> subset;
- if (!glyphUsage.has(0)) {
- subset.push_back(0); // Always include glyph 0.
- }
glyphUsage.getSetValues([&subset](unsigned v) { subset.push_back(v); });
unsigned char* subsetFont{nullptr};
diff --git a/chromium/tools/mb/mb.py b/chromium/tools/mb/mb.py
index ba3af5aa1a7..d7ab48952ef 100755
--- a/chromium/tools/mb/mb.py
+++ b/chromium/tools/mb/mb.py
@@ -36,8 +36,31 @@ sys.path = [os.path.join(CHROMIUM_SRC_DIR, 'build')] + sys.path
import gn_helpers
+def PruneVirtualEnv():
+ # Set by VirtualEnv, no need to keep it.
+ os.environ.pop('VIRTUAL_ENV', None)
+
+ # Set by VPython, if scripts want it back they have to set it explicitly.
+ os.environ.pop('PYTHONNOUSERSITE', None)
+
+ # Look for "activate_this.py" in this path, which is installed by VirtualEnv.
+ # This mechanism is used by vpython as well to sanitize VirtualEnvs from
+ # $PATH.
+ os.environ['PATH'] = os.pathsep.join([
+ p for p in os.environ.get('PATH', '').split(os.pathsep)
+ if not os.path.isfile(os.path.join(p, 'activate_this.py'))
+ ])
+
def main(args):
+ # Prune all evidence of VPython/VirtualEnv out of the environment. This means
+ # that we 'unwrap' vpython VirtualEnv path/env manipulation. Invocations of
+ # `python` from GN should never inherit the gn.py's own VirtualEnv. This also
+ # helps to ensure that generated ninja files do not reference python.exe from
+ # the VirtualEnv generated from depot_tools' own .vpython file (or lack
+ # thereof), but instead reference the default python from the PATH.
+ PruneVirtualEnv()
+
mbw = MetaBuildWrapper()
return mbw.Main(args)
diff --git a/chromium/tools/metrics/actions/actions.xml b/chromium/tools/metrics/actions/actions.xml
index 63b12be472b..4ad24223407 100644
--- a/chromium/tools/metrics/actions/actions.xml
+++ b/chromium/tools/metrics/actions/actions.xml
@@ -6256,6 +6256,9 @@ should be able to be added at any place in this file.
</action>
<action name="GridTabSwitcher.Drag.AddToGroupOrCreateGroup">
+ <obsolete>
+ Deprecated as of 8/2019. Replaced with TabGroup.Created.DropToMerge.
+ </obsolete>
<owner>yusufo@chromium.org</owner>
<owner>wychen@chromium.org</owner>
<description>
@@ -12225,6 +12228,9 @@ should be able to be added at any place in this file.
</action>
<action name="MobileNewTabOpenedTabStrip">
+ <obsolete>
+ Deprecated as of 8/2019. Replaced with MobileNewTabOpened.TabStrip.
+ </obsolete>
<owner>yusufo@chromium.org</owner>
<owner>wychen@chromium.org</owner>
<description>
@@ -21306,7 +21312,16 @@ should be able to be added at any place in this file.
<description>User drags a tab to reorder it.</description>
</action>
+<action name="TabGridDialog">
+ <owner>yusufo@chromium.org</owner>
+ <owner>wychen@chromium.org</owner>
+ <description>User took an action on the TabGridDialog.</description>
+</action>
+
<action name="TabGridDialog.Drag.RemoveFromGroup">
+ <obsolete>
+ Deprecated as of 8/2019. Replaced with TabGrid.Drag.RemoveFromGroup.
+ </obsolete>
<owner>yusufo@chromium.org</owner>
<owner>wychen@chromium.org</owner>
<description>
@@ -21333,8 +21348,8 @@ should be able to be added at any place in this file.
<owner>yusufo@chromium.org</owner>
<owner>wychen@chromium.org</owner>
<description>
- Users tapped &quot;^&quot; button on the tab strip, causing tab group bottom
- sheet to be shown.
+ Users tapped &quot;^&quot; button on the tab strip, causing tab group
+ component to be shown.
</description>
</action>
@@ -22853,6 +22868,9 @@ should be able to be added at any place in this file.
<action-suffix separator="." ordering="suffix">
<suffix name="DeveloperRequestedNewTab"
label="Users tapped on a link with a target=_blank"/>
+ <suffix name="DropToMerge"
+ label="Users dragged a single tab and dropped it on another single tab
+ to create a group."/>
<suffix name="OpenInNewTab"
label="Users long pressed a link and opened in new tab."/>
<suffix name="TabMultiSelect"
@@ -22865,6 +22883,10 @@ should be able to be added at any place in this file.
<action-suffix separator="." ordering="suffix">
<suffix name="GridTabSwitcher"
label="Users switched tabs from the grid layout TabSwitcher."/>
+ <suffix name="TabGridDialogFromStrip"
+ label="Users switched tabs within the tab grid dialog."/>
+ <suffix name="TabGridDialogInSwitcher"
+ label="Users switched tabs between groups using tab grid dialog."/>
<suffix name="TabGridSheet"
label="Users switched tabs from the tab group in the bottom sheet
switcher."/>
@@ -22873,6 +22895,14 @@ should be able to be added at any place in this file.
</action-suffix>
<action-suffix separator="." ordering="suffix">
+ <suffix name="TabGridDialogFromStrip"
+ label="Users tapped '+' button on the tab group dialog toolbar, causing
+ a new tab to be created in the group. The dialog is expanded
+ from tab strip"/>
+ <suffix name="TabGridDialogInSwitcher"
+ label="Users tapped '+' button on the tab group dialog toolbar, causing
+ a new tab to be created in the group. The dialog is in tab
+ switcher."/>
<suffix name="TabGridSheet"
label="Users tapped '+' button on the tab group bottom sheet toolbar
causes a new tab to be created in the group."/>
@@ -22916,25 +22946,47 @@ should be able to be added at any place in this file.
<action-suffix separator="." ordering="suffix">
<suffix name="GridTabSwitcher"
label="Users swipe to close a tab in grid layout TabSwitcher."/>
- <suffix name="TabGridDialog"
- label="Users swipe to close a tab in tab grid dialog."/>
+ <suffix name="TabGridDialogFromStrip"
+ label="Users swipe to close a tab in tab grid dialog from tab strip."/>
+ <suffix name="TabGridDialogInSwitcher"
+ label="Users swipe to close a tab in tab grid dialog from grid tab
+ switcher."/>
<suffix name="TabGridSheet"
label="Users swipe to close a tab in tab group bottom sheet."/>
<affected-action name="MobileStackViewSwipeCloseTab"/>
</action-suffix>
<action-suffix separator="." ordering="suffix">
+ <suffix name="DropToMerge"
+ label="Users use drop-to-merge to combine a single tab and a group or
+ two groups."/>
+ <suffix name="RemoveFromGroup.TabGridDialogFromStrip"
+ label="Users ungroup a tab by dropping it on the ungroup bar in tab
+ grid dialog from tab strip."/>
+ <suffix name="RemoveFromGroup.TabGridDialogInSwitcher"
+ label="Users ungroup a tab by dropping it on the ungroup bar in tab
+ grid dialog from grid tab switcher."/>
<suffix name="Reordered.GridTabSwitcher"
- label="Users drag to reorder tabs in grid layout TabSwitcher."/>
- <suffix name="Reordered.TabGridDialog"
- label="Users drag to reorder tabs in tab grid dialog."/>
+ label="Users drag to reorder tabs in grid layout TabSwitcher. Recorded
+ at each mini reordering during the gesture."/>
+ <suffix name="Reordered.TabGridDialogFromStrip"
+ label="Users drag to reorder tabs in tab grid dialog from tab strip.
+ Recorded at each mini reordering during the gesture."/>
+ <suffix name="Reordered.TabGridDialogInSwitcher"
+ label="Users drag to reorder tabs in tab grid dialog from grid tab
+ switcher. Recorded at each mini reordering during the gesture."/>
<suffix name="Reordered.TabGridSheet"
- label="Users drag to reorder tabs in tab group bottom sheet."/>
+ label="Users drag to reorder tabs in tab group bottom sheet. Recorded
+ at each mini reordering during the gesture."/>
<suffix name="Start.GridTabSwitcher"
label="Users long tap on a tab to trigger dragging in grid layout
TabSwitcher."/>
- <suffix name="Start.TabGridDialog"
- label="Users long tap on a tab to trigger dragging in tab grid dialog."/>
+ <suffix name="Start.TabGridDialogFromStrip"
+ label="Users long tap on a tab to trigger dragging in tab grid dialog
+ from tab strip."/>
+ <suffix name="Start.TabGridDialogInSwitcher"
+ label="Users long tap on a tab to trigger dragging in tab grid dialog
+ from grid tab switcher."/>
<suffix name="Start.TabGridSheet"
label="Users long tap on a tab to trigger dragging in tab group bottom
sheet."/>
@@ -22954,4 +23006,42 @@ should be able to be added at any place in this file.
<affected-action name="TabMultiSelect"/>
</action-suffix>
+<action-suffix separator="." ordering="suffix">
+ <suffix name="LongTapMenu" label="Users closed a tab by long tap menu"/>
+ <affected-action name="MobileMenuCloseTab"/>
+</action-suffix>
+
+<action-suffix separator="." ordering="suffix">
+ <suffix name="AppMenu" label="Users opened a new tab by app menu"/>
+ <suffix name="LongTapMenu" label="Users opened a new tab by long tap menu"/>
+ <affected-action name="MobileMenuNewTab"/>
+</action-suffix>
+
+<action-suffix separator="." ordering="suffix">
+ <suffix name="AppMenu" label="Users opened a new incognito tab by app menu"/>
+ <suffix name="LongTapMenu"
+ label="Users opened a new incognito tab by long tap menu"/>
+ <affected-action name="MobileMenuNewIncognitoTab"/>
+</action-suffix>
+
+<action-suffix separator="." ordering="suffix">
+ <suffix name="TabGridDialog"
+ label="Users tapped expand button on the tab strip, causing tab grid
+ dialog to be shown."/>
+ <suffix name="TabGridSheet"
+ label="Users tapped expand button on the tab strip, causing tab grid
+ sheet to be shown."/>
+ <affected-action name="TabGroup.ExpandedFromStrip"/>
+</action-suffix>
+
+<action-suffix separator="." ordering="suffix">
+ <suffix name="Exit"
+ label="Users click the back button or the scrim to exit the tab group
+ dialog."/>
+ <suffix name="ExpandedFromSwitcher"
+ label="Users click a card in TabSwitcher to open a dialog. See also
+ TabGroup.ExpandedFromStrip.TabGridDialog."/>
+ <affected-action name="TabGridDialog"/>
+</action-suffix>
+
</actions>
diff --git a/chromium/tools/metrics/histograms/enums.xml b/chromium/tools/metrics/histograms/enums.xml
index 8a646ec6d79..a3742c46b76 100644
--- a/chromium/tools/metrics/histograms/enums.xml
+++ b/chromium/tools/metrics/histograms/enums.xml
@@ -31813,6 +31813,20 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="3" label="App Bundle URL, not handled"/>
</enum>
+<enum name="IOSJavaScriptDialogDismissalCause">
+ <int value="0" label="Tab closed">The tab owning the dialog was closed</int>
+ <int value="1" label="Closed by user">
+ The user tapped on the OK or Cancel button.
+ </int>
+ <int value="2" label="Blocked by user">
+ Dialog was blocked because the user tapped the &quot;Suppress Dialogs&quot;
+ option.
+ </int>
+ <int value="3" label="Closed for navigation">
+ The user navigated the tab (e.g. back/forward, reload)
+ </int>
+</enum>
+
<enum name="IosLocationAuthorizationStatus">
<int value="0" label="User has not made a choice"/>
<int value="1" label="Restricted"/>
@@ -64101,6 +64115,26 @@ Full version information for the fingerprint enum values:
</int>
</enum>
+<enum name="ZeroSuggestEligibleOnFocusForRemoteNoUrlOnNTP">
+ <int value="0" label="Eligible"/>
+ <int value="1" label="Ineligible: Off the Record">
+ The user is in incognito mode.
+ </int>
+ <int value="2" label="Ineligible: Suggestions disabled">
+ Suggestion mechanism is disabled by user.
+ </int>
+ <int value="3" label="Ineligible: User not authenticated">
+ User is not signed in.
+ </int>
+ <int value="4" label="Ineligible: Unsupported suggestion server">
+ User is using an unsupported search engine.
+ </int>
+ <int value="5" label="Ineligible: Not participating">
+ User is not participating in an experiment that enables RemoteNoURL
+ suggestions on the NTP.
+ </int>
+</enum>
+
</enums>
</histogram-configuration>
diff --git a/chromium/tools/metrics/histograms/histograms.xml b/chromium/tools/metrics/histograms/histograms.xml
index eb0f5a6c940..9a5e6f5dfbf 100644
--- a/chromium/tools/metrics/histograms/histograms.xml
+++ b/chromium/tools/metrics/histograms/histograms.xml
@@ -53310,6 +53310,13 @@ uploading your change for review.
</summary>
</histogram>
+<histogram name="IOS.Dialogs.JavaScriptDialogClosed"
+ enum="IOSJavaScriptDialogDismissalCause" expires_after="M80">
+ <owner>kkhorimoto@chromium.org</owner>
+ <owner>michaeldo@chromium.org</owner>
+ <summary>Tracks the way JavaScript dialogs are closed on iOS.</summary>
+</histogram>
+
<histogram name="IOS.DragAndDrop.DragContent" enum="DragContent"
expires_after="M77">
<owner>jif@chromium.org</owner>
@@ -89439,6 +89446,25 @@ uploading your change for review.
</summary>
</histogram>
+<histogram name="Omnibox.SuggestionDeleted.ProviderAndResultType"
+ enum="OmniboxProviderAndResultType" expires_after="2020-09-01">
+ <owner>mpearson@chromium.org</owner>
+ <owner>jdonnelly@chromium.org</owner>
+ <owner>ender@chromium.org</owner>
+ <summary>
+ The provider and result type of the suggestion the user deleted. In case of
+ duplicate suggestions, only the displayed one (the one chosen as canonical
+ representative) is considered. As such, some deletion requests will not be
+ recorded here. This is because if something in the set of duplicates was
+ deletable then Chrome was willing to allow a delete action to happen on the
+ set. However, if the canonical item is not deletable, the histogram will not
+ be emitted.
+
+ This histogram records all user suggestion delete interactions, both local
+ and remote.
+ </summary>
+</histogram>
+
<histogram name="Omnibox.SuggestionUsed.AnswerInSuggest"
enum="SuggestionAnswerOptionalType" expires_after="M83">
<owner>chrome-android-omnibox-team@google.com</owner>
@@ -90030,6 +90056,42 @@ uploading your change for review.
</summary>
</histogram>
+<histogram name="Omnibox.ZeroSuggest.Eligible.RemoteNoUrl.OnNTP.OnFocus"
+ enum="ZeroSuggestEligibleOnFocusForRemoteNoUrlOnNTP"
+ expires_after="2020-01-20">
+ <owner>mpearson@chromium.org</owner>
+ <owner>jdonnelly@chromium.org</owner>
+ <owner>ender@chromium.org</owner>
+ <summary>
+ Whether the user is eligible to receive personalized zero suggestions on the
+ NTP. This histogram is updated only when the user focuses the omnibox on the
+ NTP and is emitted only once even if multiple criteria make a user
+ ineligible. Consult the source code to learn more about the precedence of
+ these values.
+
+ This metric is recorded for all contexts (including users non-syncing, in
+ incognito mode, or using different search engines) and targets specifically
+ eligibility in the current situation.
+ </summary>
+</histogram>
+
+<histogram name="Omnibox.ZeroSuggest.Eligible.RemoteNoUrl.OnNTP.OnProfileOpen"
+ enum="ZeroSuggestEligibleOnFocusForRemoteNoUrlOnNTP"
+ expires_after="2020-01-20">
+ <owner>mpearson@chromium.org</owner>
+ <owner>jdonnelly@chromium.org</owner>
+ <owner>ender@chromium.org</owner>
+ <summary>
+ Whether the user is eligible to receive personalized zero suggestions on the
+ NTP. This histogram is updated every time Chrome registers a profile change.
+
+ This metric is recorded for all contexts (including users non-syncing, in
+ incognito mode, or using different search engines) and targets overall
+ profile eligibility to receive zero-prefix query suggestions on a New Tab
+ Page.
+ </summary>
+</histogram>
+
<histogram name="Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual">
<owner>mpearson@chromium.org</owner>
<owner>jdonnelly@chromium.org</owner>
@@ -105704,6 +105766,26 @@ uploading your change for review.
</summary>
</histogram>
+<histogram name="Previews.DeferAllScript.DenyListMatch" enum="BooleanDetected"
+ expires_after="2020-01-20">
+ <owner>tbansal@chromium.org</owner>
+ <owner>dougarnett@chromium.org</owner>
+ <summary>
+ Records true when a URL matches the regex of denylist. Recorded at the time
+ of navigation commit.
+ </summary>
+</histogram>
+
+<histogram name="Previews.DeferAllScript.RedirectLoopDetectedUsingCache"
+ enum="BooleanDetected" expires_after="2020-01-20">
+ <owner>tbansal@chromium.org</owner>
+ <owner>dougarnett@chromium.org</owner>
+ <summary>
+ Records true when a redirect loop is detected when defer all script is in
+ use. Recorded at the time of navigation commit.
+ </summary>
+</histogram>
+
<histogram name="Previews.EligibilityReason" enum="PreviewsEligibilityReason"
expires_after="2020-01-20">
<owner>ryansturm@chromium.org</owner>
diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc
index 6af53ea7c69..bedd582557e 100644
--- a/chromium/ui/accessibility/ax_event_generator.cc
+++ b/chromium/ui/accessibility/ax_event_generator.cc
@@ -143,9 +143,9 @@ void AXEventGenerator::AddEvent(AXNode* node, AXEventGenerator::Event event) {
node_events.emplace(event, ax::mojom::EventFrom::kNone);
}
-void AXEventGenerator::OnNodeDataWillChange(AXTree* tree,
- const AXNodeData& old_node_data,
- const AXNodeData& new_node_data) {
+void AXEventGenerator::OnNodeDataChanged(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) {
DCHECK_EQ(tree_, tree);
// Fire CHILDREN_CHANGED events when the list of children updates.
// Internally we store inline text box nodes as children of a static text
@@ -179,8 +179,6 @@ void AXEventGenerator::OnStateChanged(AXTree* tree,
case ax::mojom::State::kExpanded:
AddEvent(node, new_value ? Event::EXPANDED : Event::COLLAPSED);
- // TODO(dtseng): tree in the midst of updates. Disallow access to
- // |node|.
if (node->data().role == ax::mojom::Role::kRow ||
node->data().role == ax::mojom::Role::kTreeItem) {
AXNode* container = node;
@@ -248,8 +246,6 @@ void AXEventGenerator::OnStringAttributeChanged(AXTree* tree,
// Fire a LIVE_REGION_CREATED if the previous value was off, and the new
// value is not-off.
- // TODO(dtseng): tree in the midst of updates. Disallow access to
- // |node|.
if (!IsAlert(node->data().role)) {
bool old_state = !old_value.empty() && old_value != "off";
bool new_state = !new_value.empty() && new_value != "off";
@@ -263,8 +259,6 @@ void AXEventGenerator::OnStringAttributeChanged(AXTree* tree,
if (node != tree->root())
AddEvent(node, Event::NAME_CHANGED);
- // TODO(dtseng): tree in the midst of updates. Disallow
- // access to |node|.
if (node->data().HasStringAttribute(
ax::mojom::StringAttribute::kContainerLiveStatus)) {
FireLiveRegionEvents(node);
diff --git a/chromium/ui/accessibility/ax_event_generator.h b/chromium/ui/accessibility/ax_event_generator.h
index a2e89a99e9a..4016e915fe9 100644
--- a/chromium/ui/accessibility/ax_event_generator.h
+++ b/chromium/ui/accessibility/ax_event_generator.h
@@ -165,9 +165,9 @@ class AX_EXPORT AXEventGenerator : public AXTreeObserver {
protected:
// AXTreeObserver overrides.
- void OnNodeDataWillChange(AXTree* tree,
- const AXNodeData& old_node_data,
- const AXNodeData& new_node_data) override;
+ void OnNodeDataChanged(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) override;
void OnRoleChanged(AXTree* tree,
AXNode* node,
ax::mojom::Role old_role,
diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc
index f818c1f4163..88c61870a9d 100644
--- a/chromium/ui/accessibility/ax_node.cc
+++ b/chromium/ui/accessibility/ax_node.cc
@@ -34,6 +34,7 @@ AXNode::AXNode(AXNode::OwnerTree* tree,
AXNode::~AXNode() = default;
size_t AXNode::GetUnignoredChildCount() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return unignored_child_count_;
}
@@ -42,6 +43,7 @@ AXNodeData&& AXNode::TakeData() {
}
AXNode* AXNode::GetUnignoredChildAtIndex(size_t index) const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
size_t count = 0;
for (auto it = UnignoredChildrenBegin(); it != UnignoredChildrenEnd(); ++it) {
if (count == index)
@@ -52,6 +54,7 @@ AXNode* AXNode::GetUnignoredChildAtIndex(size_t index) const {
}
AXNode* AXNode::GetUnignoredParent() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
AXNode* result = parent();
while (result && result->data().HasState(ax::mojom::State::kIgnored))
result = result->parent();
@@ -59,14 +62,17 @@ AXNode* AXNode::GetUnignoredParent() const {
}
size_t AXNode::GetUnignoredIndexInParent() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return unignored_index_in_parent_;
}
AXNode* AXNode::GetFirstUnignoredChild() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return ComputeFirstUnignoredChildRecursive();
}
AXNode* AXNode::GetLastUnignoredChild() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return ComputeLastUnignoredChildRecursive();
}
@@ -95,6 +101,7 @@ AXNode* AXNode::GetDeepestLastUnignoredChild() const {
}
AXNode* AXNode::GetNextUnignoredSibling() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
AXNode* parent_node = parent();
size_t index = index_in_parent() + 1;
while (parent_node) {
@@ -122,6 +129,7 @@ AXNode* AXNode::GetNextUnignoredSibling() const {
}
AXNode* AXNode::GetPreviousUnignoredSibling() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
AXNode* parent_node = parent();
bool before_first_child = index_in_parent() <= 0;
size_t index = index_in_parent() - 1;
@@ -179,10 +187,12 @@ AXNode* AXNode::GetPreviousUnignoredInTreeOrder() const {
}
AXNode::UnignoredChildIterator AXNode::UnignoredChildrenBegin() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return UnignoredChildIterator(this, GetFirstUnignoredChild());
}
AXNode::UnignoredChildIterator AXNode::UnignoredChildrenEnd() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
return UnignoredChildIterator(this, nullptr);
}
@@ -700,6 +710,10 @@ base::Optional<int> AXNode::GetPosInSet() {
return base::nullopt;
}
+ if (data().HasState(ax::mojom::State::kIgnored)) {
+ return base::nullopt;
+ }
+
const AXNode* ordered_set = GetOrderedSet();
if (!ordered_set) {
return base::nullopt;
@@ -720,6 +734,10 @@ base::Optional<int> AXNode::GetSetSize() {
if (!(IsOrderedSetItem() || IsOrderedSet()))
return base::nullopt;
+ if (data().HasState(ax::mojom::State::kIgnored)) {
+ return base::nullopt;
+ }
+
// If node is item-like, find its outerlying ordered set. Otherwise,
// this node is the ordered set.
const AXNode* ordered_set = this;
@@ -812,6 +830,7 @@ AXNode* AXNode::GetOrderedSet() const {
}
AXNode* AXNode::ComputeLastUnignoredChildRecursive() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
if (children().size() == 0)
return nullptr;
@@ -828,6 +847,7 @@ AXNode* AXNode::ComputeLastUnignoredChildRecursive() const {
}
AXNode* AXNode::ComputeFirstUnignoredChildRecursive() const {
+ DCHECK(!tree_->GetTreeUpdateInProgressState());
for (size_t i = 0; i < children().size(); i++) {
AXNode* child = children_[i];
if (!child->data().HasState(ax::mojom::State::kIgnored))
diff --git a/chromium/ui/accessibility/ax_node_position.cc b/chromium/ui/accessibility/ax_node_position.cc
index 7fb00c3947e..4666187473a 100644
--- a/chromium/ui/accessibility/ax_node_position.cc
+++ b/chromium/ui/accessibility/ax_node_position.cc
@@ -43,6 +43,30 @@ base::string16 AXNodePosition::GetText() const {
return text;
}
+int AXNodePosition::MaxTextOffset() const {
+ if (IsNullPosition())
+ return INVALID_INDEX;
+
+ const AXNode* anchor = GetAnchor();
+ DCHECK(anchor);
+ const std::string& value =
+ anchor->data().GetStringAttribute(ax::mojom::StringAttribute::kValue);
+ if (!value.empty())
+ return value.length();
+
+ if (anchor->IsText()) {
+ return anchor->data()
+ .GetStringAttribute(ax::mojom::StringAttribute::kName)
+ .length();
+ }
+
+ int max_text_offset = 0;
+ for (int i = 0; i < AnchorChildCount(); ++i)
+ max_text_offset += CreateChildPositionAt(i)->MaxTextOffset();
+
+ return max_text_offset;
+}
+
// static
AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
AXTreeID tree_id,
diff --git a/chromium/ui/accessibility/ax_node_position.h b/chromium/ui/accessibility/ax_node_position.h
index 31ae32ee59c..4da288035df 100644
--- a/chromium/ui/accessibility/ax_node_position.h
+++ b/chromium/ui/accessibility/ax_node_position.h
@@ -34,6 +34,7 @@ class AX_EXPORT AXNodePosition : public AXPosition<AXNodePosition, AXNode> {
AXPositionInstance Clone() const override;
+ int MaxTextOffset() const override;
bool IsInLineBreak() const override;
bool IsInTextObject() const override;
bool IsInWhiteSpace() const override;
diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc
index a57c4f8e029..25466296878 100644
--- a/chromium/ui/accessibility/ax_node_position_unittest.cc
+++ b/chromium/ui/accessibility/ax_node_position_unittest.cc
@@ -50,6 +50,38 @@ class AXPositionTest : public testing::Test {
void SetUp() override;
void TearDown() override;
+ void AssertTextLengthEquals(const AXTree* tree,
+ int32_t node_id,
+ int expected_text_length) {
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ tree->data().tree_id, node_id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, text_position);
+ ASSERT_TRUE(text_position->IsTextPosition());
+ ASSERT_EQ(expected_text_length, text_position->MaxTextOffset());
+ ASSERT_EQ(expected_text_length,
+ static_cast<int>(text_position->GetText().length()));
+ }
+
+ // Creates a new AXTree from a vector of nodes.
+ // Assumes the first node in the vector is the root.
+ std::unique_ptr<AXTree> CreateAXTree(
+ const std::vector<ui::AXNodeData>& nodes) {
+ ui::AXTreeUpdate update;
+ ui::AXTreeData tree_data;
+ tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ update.tree_data = tree_data;
+ update.has_tree_data = true;
+ update.root_id = nodes[0].id;
+ update.nodes = nodes;
+
+ tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+ update.tree_data = tree_data;
+ std::unique_ptr<AXTree> tree = std::make_unique<AXTree>(update);
+ AXNodePosition::SetTree(tree.get());
+ return tree;
+ }
+
AXNodeData root_;
AXNodeData button_;
AXNodeData check_box_;
@@ -276,6 +308,60 @@ TEST_F(AXPositionTest, Clone) {
EXPECT_EQ(AXNodePosition::INVALID_INDEX, copy_position->child_index());
}
+TEST_F(AXPositionTest, Serialize) {
+ TestPositionType null_position = AXNodePosition::CreateNullPosition();
+ ASSERT_NE(nullptr, null_position);
+ TestPositionType copy_position =
+ AXNodePosition::Unserialize(null_position->Serialize());
+ ASSERT_NE(nullptr, copy_position);
+ EXPECT_TRUE(copy_position->IsNullPosition());
+
+ TestPositionType tree_position = AXNodePosition::CreateTreePosition(
+ tree_.data().tree_id, root_.id, 1 /* child_index */);
+ ASSERT_NE(nullptr, tree_position);
+ copy_position = AXNodePosition::Unserialize(tree_position->Serialize());
+ ASSERT_NE(nullptr, copy_position);
+ EXPECT_TRUE(copy_position->IsTreePosition());
+ EXPECT_EQ(root_.id, copy_position->anchor_id());
+ EXPECT_EQ(1, copy_position->child_index());
+ EXPECT_EQ(AXNodePosition::INVALID_OFFSET, copy_position->text_offset());
+
+ tree_position = AXNodePosition::CreateTreePosition(
+ tree_.data().tree_id, root_.id, AXNodePosition::BEFORE_TEXT);
+ ASSERT_NE(nullptr, tree_position);
+ copy_position = AXNodePosition::Unserialize(tree_position->Serialize());
+ ASSERT_NE(nullptr, copy_position);
+ EXPECT_TRUE(copy_position->IsTreePosition());
+ EXPECT_EQ(root_.id, copy_position->anchor_id());
+ EXPECT_EQ(AXNodePosition::BEFORE_TEXT, copy_position->child_index());
+ EXPECT_EQ(AXNodePosition::INVALID_OFFSET, copy_position->text_offset());
+
+ TestPositionType text_position = AXNodePosition::CreateTextPosition(
+ tree_.data().tree_id, text_field_.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kUpstream);
+ ASSERT_NE(nullptr, text_position);
+ ASSERT_TRUE(text_position->IsTextPosition());
+ copy_position = AXNodePosition::Unserialize(text_position->Serialize());
+ ASSERT_NE(nullptr, copy_position);
+ EXPECT_TRUE(copy_position->IsTextPosition());
+ EXPECT_EQ(text_field_.id, copy_position->anchor_id());
+ EXPECT_EQ(0, copy_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, copy_position->affinity());
+
+ text_position = AXNodePosition::CreateTextPosition(
+ tree_.data().tree_id, text_field_.id, 0 /* text_offset */,
+ ax::mojom::TextAffinity::kDownstream);
+ ASSERT_NE(nullptr, text_position);
+ ASSERT_TRUE(text_position->IsTextPosition());
+ copy_position = AXNodePosition::Unserialize(text_position->Serialize());
+ ASSERT_NE(nullptr, copy_position);
+ EXPECT_TRUE(copy_position->IsTextPosition());
+ EXPECT_EQ(text_field_.id, copy_position->anchor_id());
+ EXPECT_EQ(0, copy_position->text_offset());
+ EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, copy_position->affinity());
+ EXPECT_EQ(AXNodePosition::INVALID_INDEX, copy_position->child_index());
+}
+
TEST_F(AXPositionTest, GetTextFromNullPosition) {
TestPositionType text_position = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, text_position);
@@ -416,6 +502,49 @@ TEST_F(AXPositionTest, GetMaxTextOffsetFromLineBreak) {
ASSERT_EQ(1, text_position->MaxTextOffset());
}
+TEST_F(AXPositionTest, GetMaxTextOffsetUpdate) {
+ AXNodePosition::SetTree(nullptr);
+
+ ui::AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kRootWebArea;
+
+ ui::AXNodeData text_data;
+ text_data.id = 2;
+ text_data.role = ax::mojom::Role::kStaticText;
+ text_data.SetName("some text");
+
+ ui::AXNodeData more_text_data;
+ more_text_data.id = 3;
+ more_text_data.role = ax::mojom::Role::kStaticText;
+ more_text_data.SetName("more text");
+
+ root_data.child_ids = {2, 3};
+
+ std::unique_ptr<AXTree> new_tree =
+ CreateAXTree({root_data, text_data, more_text_data});
+
+ AssertTextLengthEquals(new_tree.get(), text_data.id, 9);
+ AssertTextLengthEquals(new_tree.get(), root_data.id, 18);
+
+ text_data.SetName("Adjusted line 1");
+ new_tree = CreateAXTree({root_data, text_data, more_text_data});
+ AssertTextLengthEquals(new_tree.get(), text_data.id, 15);
+ AssertTextLengthEquals(new_tree.get(), root_data.id, 24);
+
+ // Value should override name
+ text_data.SetValue("Value should override name");
+ new_tree = CreateAXTree({root_data, text_data, more_text_data});
+ AssertTextLengthEquals(new_tree.get(), text_data.id, 26);
+ AssertTextLengthEquals(new_tree.get(), root_data.id, 35);
+
+ // An empty value should fall back to name
+ text_data.SetValue("");
+ new_tree = CreateAXTree({root_data, text_data, more_text_data});
+ AssertTextLengthEquals(new_tree.get(), text_data.id, 15);
+ AssertTextLengthEquals(new_tree.get(), root_data.id, 24);
+}
+
TEST_F(AXPositionTest, AtStartOfAnchorWithNullPosition) {
TestPositionType null_position = AXNodePosition::CreateNullPosition();
ASSERT_NE(nullptr, null_position);
@@ -1487,20 +1616,20 @@ TEST_F(AXPositionTest, CreatePositionAtFormatBoundaryWithTextPosition) {
AXNodePosition::SetTree(nullptr);
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData text_data;
- text_data.id = 1;
+ text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
AXNodeData more_text_data;
- more_text_data.id = 2;
+ more_text_data.id = 3;
more_text_data.role = ax::mojom::Role::kStaticText;
more_text_data.SetName("more text");
- root_data.child_ids = {1, 2};
+ root_data.child_ids = {text_data.id, more_text_data.id};
AXTreeUpdate update;
AXTreeData tree_data;
@@ -2793,30 +2922,30 @@ TEST_F(AXPositionTest, CreateNextAnchorPosition) {
AXNodePosition::SetTree(nullptr);
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData text_data;
- text_data.id = 1;
+ text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
AXNodeData text_field_data;
- text_field_data.id = 2;
+ text_field_data.id = 3;
text_field_data.role = ax::mojom::Role::kTextField;
AXNodeData empty_text_data;
- empty_text_data.id = 3;
+ empty_text_data.id = 4;
empty_text_data.role = ax::mojom::Role::kStaticText;
empty_text_data.SetName("");
AXNodeData more_text_data;
- more_text_data.id = 4;
+ more_text_data.id = 5;
more_text_data.role = ax::mojom::Role::kStaticText;
more_text_data.SetName("more text");
- root_data.child_ids = {1, 2, 4};
- text_field_data.child_ids = {3};
+ root_data.child_ids = {text_data.id, text_field_data.id, more_text_data.id};
+ text_field_data.child_ids = {empty_text_data.id};
AXTreeUpdate update;
AXTreeData tree_data;
diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h
index b35a9eb09c5..a2ff769886a 100644
--- a/chromium/ui/accessibility/ax_position.h
+++ b/chromium/ui/accessibility/ax_position.h
@@ -10,6 +10,7 @@
#include <memory>
#include <ostream>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -133,6 +134,48 @@ class AXPosition {
virtual AXPositionInstance Clone() const = 0;
+ // A serialization of a position as POD. Not for sharing on disk or sharing
+ // across thread or process boundaries, just for passing a position to an
+ // API that works with positions as opaque objects.
+ struct SerializedPosition {
+ AXPositionKind kind;
+ int32_t anchor_id;
+ int child_index;
+ int text_offset;
+ ax::mojom::TextAffinity affinity;
+ char tree_id[33];
+ };
+
+ static_assert(std::is_trivially_copyable<SerializedPosition>::value,
+ "SerializedPosition must be POD");
+
+ SerializedPosition Serialize() {
+ SerializedPosition result;
+ result.kind = kind_;
+
+ // A tree ID can be serialized as a 32-byte string.
+ std::string tree_id_string = tree_id_.ToString();
+ DCHECK_LE(tree_id_string.size(), 32U);
+ strncpy(result.tree_id, tree_id_string.c_str(), 32);
+ result.tree_id[32] = 0;
+
+ result.anchor_id = anchor_id_;
+ result.child_index = child_index_;
+ result.text_offset = text_offset_;
+ result.affinity = affinity_;
+ return result;
+ }
+
+ static AXPositionInstance Unserialize(
+ const SerializedPosition& serialization) {
+ AXPositionInstance new_position(new AXPositionType());
+ new_position->Initialize(serialization.kind,
+ ui::AXTreeID::FromString(serialization.tree_id),
+ serialization.anchor_id, serialization.child_index,
+ serialization.text_offset, serialization.affinity);
+ return new_position;
+ }
+
virtual bool IsIgnoredPosition() const { return false; }
virtual AXPositionInstance AsUnignoredTextPosition(
@@ -1790,7 +1833,7 @@ class AXPosition {
// Returns the length of the text that is present inside the anchor node,
// including any text found in descendant text nodes.
- int MaxTextOffset() const {
+ virtual int MaxTextOffset() const {
if (IsNullPosition())
return INVALID_INDEX;
return static_cast<int>(GetText().length());
@@ -1840,7 +1883,8 @@ class AXPosition {
(child_index_ != BEFORE_TEXT &&
(child_index_ < 0 || child_index_ > AnchorChildCount()))) ||
(kind_ == AXPositionKind::TEXT_POSITION &&
- (text_offset_ < 0 || text_offset_ > MaxTextOffset()))) {
+ (text_offset_ < 0 ||
+ (text_offset > 0 && text_offset_ > MaxTextOffset())))) {
// Reset to the null position.
kind_ = AXPositionKind::NULL_POSITION;
tree_id_ = AXTreeIDUnknown();
diff --git a/chromium/ui/accessibility/ax_table_info_unittest.cc b/chromium/ui/accessibility/ax_table_info_unittest.cc
index e4b990ae692..ccc1409d8bb 100644
--- a/chromium/ui/accessibility/ax_table_info_unittest.cc
+++ b/chromium/ui/accessibility/ax_table_info_unittest.cc
@@ -247,7 +247,7 @@ TEST_F(AXTableInfoTest, AuthorRowAndColumnCountsAreRespected) {
initial_state.nodes[0].child_ids = {2};
MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {3};
- MakeCell(&initial_state.nodes[2], 2, 0, 1);
+ MakeCell(&initial_state.nodes[2], 3, 0, 1);
AXTree tree(initial_state);
AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index d464561d01e..9c26f68ce8f 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -12,6 +12,7 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "ui/accessibility/accessibility_switches.h"
@@ -28,6 +29,9 @@ namespace ui {
namespace {
std::string TreeToStringHelper(const AXNode* node, int indent) {
+ if (!node)
+ return "";
+
return std::accumulate(
node->children().cbegin(), node->children().cend(),
std::string(2 * indent, ' ') + node->data().ToString() + "\n",
@@ -101,27 +105,158 @@ bool IsCollapsed(const AXNode* node) {
} // namespace
+// This object is used to track structure changes that will occur for a specific
+// AXID. This includes how many times we expect that a node with a specific AXID
+// will be created and/or destroyed, and how many times a subtree rooted at AXID
+// expects to be destroyed during an AXTreeUpdate.
+//
+// An AXTreeUpdate is a serialized representation of an atomic change to an
+// AXTree. See also |AXTreeUpdate| which documents the nature and invariants
+// required to atomically update the AXTree.
+//
+// The reason that we must track these counts, and the reason these are counts
+// rather than a bool/flag is because an AXTreeUpdate may contain multiple
+// AXNodeData updates for a given AXID. A common way that this occurs is when
+// multiple AXTreeUpdates are merged together, combining their AXNodeData list.
+// Additionally AXIDs may be reused after being removed from the tree,
+// most notably when "reparenting" a node. A "reparent" occurs when an AXID is
+// first destroyed from the tree then created again in the same AXTreeUpdate,
+// which may also occur multiple times with merged updates.
+//
+// We need to accumulate these counts for 3 reasons :
+// 1. To determine what structure changes *will* occur before applying
+// updates to the tree so that we can notify observers of structure changes
+// when the tree is still in a stable and unchanged state.
+// 2. Capture any errors *before* applying updates to the tree structure
+// due to the order of (or lack of) AXNodeData entries in the update
+// so we can abort a bad update instead of applying it partway.
+// 3. To validate that the expectations we accumulate actually match
+// updates that are applied to the tree.
+//
+// To reiterate the invariants that this structure is taking a dependency on
+// from |AXTreeUpdate|, suppose that the next AXNodeData to be applied is
+// |node|. The following invariants must hold:
+// 1. Either
+// a) |node.id| is already in the tree, or
+// b) the tree is empty, and
+// |node| is the new root of the tree, and
+// |node.role| == WebAXRoleRootWebArea.
+// 2. Every child id in |node.child_ids| must either be already a child
+// of this node, or a new id not previously in the tree. It is not
+// allowed to "reparent" a child to this node without first removing
+// that child from its previous parent.
+// 3. When a new id appears in |node.child_ids|, the tree should create a
+// new uninitialized placeholder node for it immediately. That
+// placeholder must be updated within the same AXTreeUpdate, otherwise
+// it's a fatal error. This guarantees the tree is always complete
+// before or after an AXTreeUpdate.
+struct PendingStructureChanges {
+ PendingStructureChanges(const AXNode* node)
+ : destroy_subtree_count(0),
+ destroy_node_count(0),
+ create_node_count(0),
+ node_exists(!!node),
+ parent_node_id((node && node->parent())
+ ? base::Optional<AXNode::AXID>{node->parent()->id()}
+ : base::nullopt),
+ last_known_data(node ? &node->data() : nullptr) {}
+
+ // Returns true if this node has any changes remaining.
+ // This includes pending subtree or node destruction, and node creation.
+ bool DoesNodeExpectAnyStructureChanges() const {
+ return DoesNodeExpectSubtreeWillBeDestroyed() ||
+ DoesNodeExpectNodeWillBeDestroyed() ||
+ DoesNodeExpectNodeWillBeCreated();
+ }
+
+ // Returns true if there are any pending changes that require destroying
+ // this node or its subtree.
+ bool DoesNodeExpectSubtreeOrNodeWillBeDestroyed() const {
+ return DoesNodeExpectSubtreeWillBeDestroyed() ||
+ DoesNodeExpectNodeWillBeDestroyed();
+ }
+
+ // Returns true if the subtree rooted at this node needs to be destroyed
+ // during the update, but this may not be the next action that needs to be
+ // performed on the node.
+ bool DoesNodeExpectSubtreeWillBeDestroyed() const {
+ return destroy_subtree_count;
+ }
+
+ // Returns true if this node needs to be destroyed during the update, but this
+ // may not be the next action that needs to be performed on the node.
+ bool DoesNodeExpectNodeWillBeDestroyed() const { return destroy_node_count; }
+
+ // Returns true if this node needs be created during the update, but this
+ // may not be the next action that needs to be performed on the node.
+ bool DoesNodeExpectNodeWillBeCreated() const { return create_node_count; }
+
+ // Returns true if this node would exist in the tree as of the last pending
+ // update that was processed, and the node has not been provided node data.
+ bool DoesNodeRequireInit() const { return node_exists && !last_known_data; }
+
+ // Keep track of the number of times the subtree rooted at this node
+ // will be destroyed.
+ // An example of when this count may be larger than 1 is if updates were
+ // merged together. A subtree may be [created,] destroyed, created, and
+ // destroyed again within the same |AXTreeUpdate|. The important takeaway here
+ // is that an update may request destruction of a subtree rooted at an
+ // AXID more than once, not that a specific subtree is being destroyed
+ // more than once.
+ int32_t destroy_subtree_count;
+
+ // Keep track of the number of times this node will be destroyed.
+ // An example of when this count may be larger than 1 is if updates were
+ // merged together. A node may be [created,] destroyed, created, and destroyed
+ // again within the same |AXTreeUpdate|. The important takeaway here is that
+ // an AXID may request destruction more than once, not that a specific node
+ // is being destroyed more than once.
+ int32_t destroy_node_count;
+
+ // Keep track of the number of times this node will be created.
+ // An example of when this count may be larger than 1 is if updates were
+ // merged together. A node may be [destroyed,] created, destroyed, and created
+ // again within the same |AXTreeUpdate|. The important takeaway here is that
+ // an AXID may request creation more than once, not that a specific node is
+ // being created more than once.
+ int32_t create_node_count;
+
+ // Keep track of whether this node exists in the tree as of the last pending
+ // update that was processed.
+ bool node_exists;
+
+ // Keep track of the parent id for this node as of the last pending
+ // update that was processed.
+ base::Optional<AXNode::AXID> parent_node_id;
+
+ // Keep track of the last known node data for this node.
+ // This will be null either when a node does not exist in the tree, or
+ // when the node is new and has not been initialized with node data yet.
+ // This is needed to determine what children have changed between pending
+ // updates.
+ const AXNodeData* last_known_data;
+};
+
// Intermediate state to keep track of during a tree update.
struct AXTreeUpdateState {
- AXTreeUpdateState() : new_root(nullptr) {}
- // Returns whether this update changes |node|.
- bool IsChangedNode(const AXNode* node) {
- return changed_node_ids.find(node->id()) != changed_node_ids.end();
- }
+ AXTreeUpdateState(const AXTree& tree)
+ : computing_pending_changes(false),
+ root_will_be_created(false),
+ tree(tree) {}
// Returns whether this update removes |node|.
bool IsRemovedNode(const AXNode* node) const {
- return removed_node_ids.find(node->id()) != removed_node_ids.end();
+ return base::Contains(removed_node_ids, node->id());
}
// Returns whether this update creates |node|.
- bool IsNewNode(const AXNode* node) {
- return new_nodes.find(node) != new_nodes.end();
+ bool IsCreatedNode(const AXNode* node) const {
+ return base::Contains(new_node_ids, node->id());
}
// If this node is removed, it should be considered reparented.
bool IsPotentiallyReparentedNode(const AXNode* node) const {
- return base::Contains(potentially_reparented_ids, node->id());
+ return base::Contains(node_ids_found_in_update, node->id());
}
// Returns whether this update reparents |node|.
@@ -129,49 +264,281 @@ struct AXTreeUpdateState {
return IsPotentiallyReparentedNode(node) && IsRemovedNode(node);
}
+ // Returns true if the node should exist in the tree but doesn't have
+ // any node data yet.
+ bool DoesPendingNodeRequireInit(AXNode::AXID node_id) const {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ PendingStructureChanges* data = GetPendingStructureChanges(node_id);
+ return data && data->DoesNodeRequireInit();
+ }
+
+ // Returns the parent node id for the pending node.
+ base::Optional<AXNode::AXID> GetParentIdForPendingNode(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ PendingStructureChanges* data = GetOrCreatePendingStructureChanges(node_id);
+ DCHECK(!data->parent_node_id ||
+ ShouldPendingNodeExistInTree(*data->parent_node_id));
+ return data->parent_node_id;
+ }
+
+ // Returns true if this node should exist in the tree.
+ bool ShouldPendingNodeExistInTree(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ return GetOrCreatePendingStructureChanges(node_id)->node_exists;
+ }
+
+ // Returns the last known node data for a pending node.
+ const AXNodeData& GetLastKnownPendingNodeData(AXNode::AXID node_id) const {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ static base::NoDestructor<ui::AXNodeData> empty_data;
+ PendingStructureChanges* data = GetPendingStructureChanges(node_id);
+ return (data && data->last_known_data) ? *data->last_known_data
+ : *empty_data;
+ }
+
+ // Clear the last known pending data for |node_id|.
+ void ClearLastKnownPendingNodeData(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ GetOrCreatePendingStructureChanges(node_id)->last_known_data = nullptr;
+ }
+
+ // Update the last known pending node data for |node_data.id|.
+ void SetLastKnownPendingNodeData(const AXNodeData* node_data) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ GetOrCreatePendingStructureChanges(node_data->id)->last_known_data =
+ node_data;
+ }
+
+ // Returns the number of times the update is expected to destroy a
+ // subtree rooted at |node_id|.
+ int32_t GetPendingDestroySubtreeCount(AXNode::AXID node_id) const {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id))
+ return data->destroy_subtree_count;
+ return 0;
+ }
+
+ // Increments the number of times the update is expected to
+ // destroy a subtree rooted at |node_id|.
+ // Returns true on success, false on failure when the node will not exist.
+ bool IncrementPendingDestroySubtreeCount(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ PendingStructureChanges* data = GetOrCreatePendingStructureChanges(node_id);
+ if (!data->node_exists)
+ return false;
+
+ ++data->destroy_subtree_count;
+ return true;
+ }
+
+ // Decrements the number of times the update is expected to
+ // destroy a subtree rooted at |node_id|.
+ void DecrementPendingDestroySubtreeCount(AXNode::AXID node_id) {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id)) {
+ DCHECK_GT(data->destroy_subtree_count, 0);
+ --data->destroy_subtree_count;
+ }
+ }
+
+ // Returns the number of times the update is expected to destroy
+ // a node with |node_id|.
+ int32_t GetPendingDestroyNodeCount(AXNode::AXID node_id) const {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id))
+ return data->destroy_node_count;
+ return 0;
+ }
+
+ // Increments the number of times the update is expected to
+ // destroy a node with |node_id|.
+ // Returns true on success, false on failure when the node will not exist.
+ bool IncrementPendingDestroyNodeCount(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ PendingStructureChanges* data = GetOrCreatePendingStructureChanges(node_id);
+ if (!data->node_exists)
+ return false;
+
+ ++data->destroy_node_count;
+ data->node_exists = false;
+ data->last_known_data = nullptr;
+ data->parent_node_id = base::nullopt;
+ if (pending_root_id == node_id)
+ pending_root_id = base::nullopt;
+ return true;
+ }
+
+ // Decrements the number of times the update is expected to
+ // destroy a node with |node_id|.
+ void DecrementPendingDestroyNodeCount(AXNode::AXID node_id) {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id)) {
+ DCHECK_GT(data->destroy_node_count, 0);
+ --data->destroy_node_count;
+ }
+ }
+
+ // Returns the number of times the update is expected to create
+ // a node with |node_id|.
+ int32_t GetPendingCreateNodeCount(AXNode::AXID node_id) const {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id))
+ return data->create_node_count;
+ return 0;
+ }
+
+ // Increments the number of times the update is expected to
+ // create a node with |node_id|.
+ // Returns true on success, false on failure when the node will already exist.
+ bool IncrementPendingCreateNodeCount(
+ AXNode::AXID node_id,
+ base::Optional<AXNode::AXID> parent_node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ PendingStructureChanges* data = GetOrCreatePendingStructureChanges(node_id);
+ if (data->node_exists)
+ return false;
+
+ ++data->create_node_count;
+ data->node_exists = true;
+ data->parent_node_id = parent_node_id;
+ return true;
+ }
+
+ // Decrements the number of times the update is expected to
+ // create a node with |node_id|.
+ void DecrementPendingCreateNodeCount(AXNode::AXID node_id) {
+ DCHECK(!computing_pending_changes)
+ << "This method should not be called before any updates are made to "
+ "the tree.";
+ if (PendingStructureChanges* data = GetPendingStructureChanges(node_id)) {
+ DCHECK_GT(data->create_node_count, 0);
+ --data->create_node_count;
+ }
+ }
+
+ // Returns whether this update must invalidate the unignored cached
+ // values for |node_id|.
+ bool InvalidatesUnignoredCachedValues(AXNode::AXID node_id) {
+ return base::Contains(invalidate_unignored_cached_values_ids, node_id);
+ }
+
+ // Adds the parent of |node_id| to the list of nodes to invalidate unignored
+ // cached values.
+ void InvalidateParentNodeUnignoredCacheValues(AXNode::AXID node_id) {
+ DCHECK(computing_pending_changes) << "This method should be called before "
+ "any updates are made to the tree.";
+ base::Optional<AXNode::AXID> parent_node_id =
+ GetParentIdForPendingNode(node_id);
+ if (parent_node_id) {
+ invalidate_unignored_cached_values_ids.insert(*parent_node_id);
+ }
+ }
+
+ // Indicates if the tree is calculating what changes will occur during
+ // an update before the update applies changes.
+ bool computing_pending_changes;
+
+ // Keeps track of the root node id when calculating what changes will occur
+ // during an update before the update applies changes.
+ base::Optional<AXNode::AXID> pending_root_id;
+
+ // Keeps track of whether the root node will need to be created as a new node.
+ // This may occur either when the root node does not exist before applying
+ // updates to the tree (new tree), or if the root is the |node_id_to_clear|
+ // and will be destroyed before applying AXNodeData updates to the tree.
+ bool root_will_be_created;
+
// During an update, this keeps track of all nodes that have been
// implicitly referenced as part of this update, but haven't been
// updated yet. It's an error if there are any pending nodes at the
// end of Unserialize.
- std::set<const AXNode*> pending_nodes;
-
- // This is similar to above, but we store node ids here because this list gets
- // generated before any nodes get created or re-used. Its purpose is to allow
- // us to know what nodes will be updated so we can make more intelligent
- // decisions about when to notify observers of removals or reparenting.
- std::set<int> changed_node_ids;
+ std::set<AXNode::AXID> pending_nodes;
- // keeps track of nodes whose cached unignored child count, or unignored
+ // Keeps track of nodes whose cached unignored child count, or unignored
// index in parent may have changed, and must be updated.
- std::unordered_set<int> invalidate_unignored_cached_values_ids;
+ std::set<AXNode::AXID> invalidate_unignored_cached_values_ids;
- // Potentially reparented node ids include any child node ids touched by the
- // update, as well as any new root node id. Nodes are considered
- // reparented if they are in this list and removed from somewhere else.
- std::set<int> potentially_reparented_ids;
+ // All child node ids touched by the update, as well as the new root
+ // node id. Nodes are considered reparented if they are in this list
+ // and removed from somewhere else.
+ std::set<AXNode::AXID> node_ids_found_in_update;
- std::unordered_set<int> node_data_changed_ids;
+ // Keeps track of nodes that have changed their node data.
+ std::set<AXNode::AXID> node_data_changed_ids;
// Keeps track of new nodes created during this update.
- std::set<const AXNode*> new_nodes;
-
- // The new root in this update, if any.
- AXNode* new_root;
+ std::set<AXNode::AXID> new_node_ids;
+
+ // Keeps track of any nodes removed. Nodes are removed when their AXID no
+ // longer exist in the parent |child_ids| list, or the node is part of to the
+ // subtree of the AXID that was explicitally cleared with |node_id_to_clear|.
+ // Used to identify re-parented nodes. A re-parented occurs when any AXID
+ // is first removed from the tree then added to the tree again.
+ std::set<AXNode::AXID> removed_node_ids;
+
+ // Maps between a node id and its pending update information.
+ std::map<AXNode::AXID, std::unique_ptr<PendingStructureChanges>>
+ node_id_to_pending_data;
+
+ // Maps between a node id and the data it owned before being updated.
+ // We need to keep this around in order to correctly fire post-update events.
+ std::map<AXNode::AXID, AXNodeData> old_node_id_to_data;
+
+ // Optional copy of the old tree data, only populated when the tree
+ // data has changed.
+ base::Optional<AXTreeData> old_tree_data;
+
+ private:
+ PendingStructureChanges* GetPendingStructureChanges(
+ AXNode::AXID node_id) const {
+ auto iter = node_id_to_pending_data.find(node_id);
+ return (iter != node_id_to_pending_data.cend()) ? iter->second.get()
+ : nullptr;
+ }
- // Keeps track of any nodes removed. Used to identify re-parented nodes.
- std::set<int> removed_node_ids;
+ PendingStructureChanges* GetOrCreatePendingStructureChanges(
+ AXNode::AXID node_id) {
+ auto iter = node_id_to_pending_data.find(node_id);
+ if (iter == node_id_to_pending_data.cend()) {
+ const AXNode* node = tree.GetFromId(node_id);
+ iter = node_id_to_pending_data
+ .emplace(std::make_pair(
+ node_id, std::make_unique<PendingStructureChanges>(node)))
+ .first;
+ }
+ return iter->second.get();
+ }
- // Maps between a node id and its data. We need to keep this around because
- // the reparented nodes in this update were actually deleted.
- std::map<int32_t, AXNodeData> reparented_node_id_to_data;
+ // We need to hold onto a reference to the AXTree so that we can
+ // lazily initialize |PendingStructureChanges| objects.
+ const AXTree& tree;
};
AXTree::AXTree() {
AXNodeData root;
- root.id = -1;
+ root.id = AXNode::kInvalidAXID;
AXTreeUpdate initial_state;
- initial_state.root_id = -1;
+ initial_state.root_id = AXNode::kInvalidAXID;
initial_state.nodes.push_back(root);
CHECK(Unserialize(initial_state)) << error();
// TODO(chrishall): should language_detection_manager be a member or pointer?
@@ -188,8 +555,12 @@ AXTree::AXTree(const AXTreeUpdate& initial_state) {
}
AXTree::~AXTree() {
- if (root_)
+ if (root_) {
+ RecursivelyNotifyNodeWillBeDeleted(root_);
+ base::AutoReset<bool> update_state_resetter(&tree_update_in_progress_,
+ true);
DestroyNodeAndSubtree(root_, nullptr);
+ }
for (auto& entry : table_info_map_)
delete entry.second;
table_info_map_.clear();
@@ -398,65 +769,114 @@ const std::set<AXTreeID> AXTree::GetAllChildTreeIds() const {
}
bool AXTree::Unserialize(const AXTreeUpdate& update) {
- // Set update state to true.
- // tree_update_in_progress_ gets set back to false whenever this function
- // exits.
- base::AutoReset<bool> update_state_resetter(&tree_update_in_progress_, true);
-
- AXTreeUpdateState update_state;
- int32_t old_root_id = root_ ? root_->id() : 0;
-
- // First, make a note of any nodes we will touch as part of this update.
- for (size_t i = 0; i < update.nodes.size(); ++i)
- update_state.changed_node_ids.insert(update.nodes[i].id);
-
- if (update.has_tree_data)
- UpdateData(update.tree_data);
+ AXTreeUpdateState update_state(*this);
+ const AXNode::AXID old_root_id = root_ ? root_->id() : AXNode::kInvalidAXID;
// Get all of the node ids that are certain to exist after the update.
// These are the nodes that are considered reparented if they are removed from
// somewhere else.
- update_state.potentially_reparented_ids.emplace(update.root_id);
+ if (update.root_id != AXNode::kInvalidAXID)
+ update_state.node_ids_found_in_update.emplace(update.root_id);
for (const AXNodeData& update_node_data : update.nodes) {
- update_state.potentially_reparented_ids.insert(
+ update_state.node_ids_found_in_update.insert(
update_node_data.child_ids.begin(), update_node_data.child_ids.end());
}
+ // Accumulates the work that will be required to update the AXTree.
+ // This allows us to notify observers of structure changes when the
+ // tree is still in a stable and unchanged state.
+ if (!ComputePendingChanges(update, update_state))
+ return false;
+
+ // Notify observers of subtrees and nodes that are about to be destroyed or
+ // reparented, this must be done before applying any updates to the tree.
+ for (auto&& pair : update_state.node_id_to_pending_data) {
+ const AXNode::AXID node_id = pair.first;
+ const std::unique_ptr<PendingStructureChanges>& data = pair.second;
+ if (data->DoesNodeExpectSubtreeOrNodeWillBeDestroyed()) {
+ if (AXNode* node = GetFromId(node_id)) {
+ if (data->DoesNodeExpectSubtreeWillBeDestroyed())
+ NotifySubtreeWillBeReparentedOrDeleted(node, &update_state);
+ if (data->DoesNodeExpectNodeWillBeDestroyed())
+ NotifyNodeWillBeReparentedOrDeleted(node, &update_state);
+ }
+ }
+ }
+
+ // Notify observers of nodes that are about to change their data.
+ // This must be done before applying any updates to the tree.
+ // This is iterating in reverse order so that we only notify once per node id,
+ // and that we only notify the initial node data against the final node data,
+ // unless the node is a new root.
+ std::set<int32_t> notified_node_data_will_change;
+ for (size_t i = update.nodes.size(); i-- > 0;) {
+ const AXNodeData& new_data = update.nodes[i];
+ const bool is_new_root =
+ update_state.root_will_be_created && new_data.id == update.root_id;
+ if (!is_new_root) {
+ AXNode* node = GetFromId(new_data.id);
+ if (node && notified_node_data_will_change.insert(new_data.id).second)
+ NotifyNodeDataWillChange(node->data(), new_data);
+ }
+ }
+
+ // Now that we have finished sending events for changes that will happen,
+ // set update state to true. |tree_update_in_progress_| gets set back to
+ // false whenever this function exits.
+ base::AutoReset<bool> update_state_resetter(&tree_update_in_progress_, true);
+
+ // Handle |node_id_to_clear| before applying ordinary node updates.
// We distinguish between updating the root, e.g. changing its children or
- // some of its attributes, or replacing the root completely.
+ // some of its attributes, or replacing the root completely. If the root is
+ // being updated, update.node_id_to_clear should hold the current root's ID.
+ // Otherwise if the root is being replaced, update.root_id should hold the ID
+ // of the new root.
bool root_updated = false;
- if (update.node_id_to_clear != 0) {
- AXNode* node = GetFromId(update.node_id_to_clear);
-
- // Only destroy the root if the root was replaced and not if it's simply
- // updated. To figure out if the root was simply updated, we compare the ID
- // of the new root with the existing root ID.
- if (node && node == root_) {
- if (update.root_id != old_root_id) {
- // Clear root_ before calling DestroySubtree so that root_ doesn't ever
- // point to an invalid node.
- AXNode* old_root = root_;
- root_ = nullptr;
- DestroySubtree(old_root, &update_state);
- } else {
- root_updated = true;
+ if (update.node_id_to_clear != AXNode::kInvalidAXID) {
+ if (AXNode* cleared_node = GetFromId(update.node_id_to_clear)) {
+ DCHECK(root_);
+ if (cleared_node == root_) {
+ // Only destroy the root if the root was replaced and not if it's simply
+ // updated. To figure out if the root was simply updated, we compare
+ // the ID of the new root with the existing root ID.
+ if (update.root_id != old_root_id) {
+ // Clear root_ before calling DestroySubtree so that root_ doesn't
+ // ever point to an invalid node.
+ AXNode* old_root = root_;
+ root_ = nullptr;
+ DestroySubtree(old_root, &update_state);
+ } else {
+ // If the root has simply been updated, we treat it like an update to
+ // any other node.
+ root_updated = true;
+ }
}
- }
- // If the root has simply been updated, we treat it like an update to any
- // other node.
- if (node && root_ && (node != root_ || root_updated)) {
- for (auto* child : node->children())
- DestroySubtree(child, &update_state);
- std::vector<AXNode*> children;
- node->SwapChildren(children);
- update_state.pending_nodes.insert(node);
+ // If the tree doesn't exists any more because the root has just been
+ // replaced, there is nothing more to clear.
+ if (root_) {
+ for (auto* child : cleared_node->children())
+ DestroySubtree(child, &update_state);
+ std::vector<AXNode*> children;
+ cleared_node->SwapChildren(children);
+ update_state.pending_nodes.insert(cleared_node->id());
+ }
}
}
- bool root_exists = GetFromId(update.root_id) != nullptr;
+ DCHECK_EQ(!GetFromId(update.root_id), update_state.root_will_be_created);
+
+ // Update the tree data, do not call |UpdateData| since we want to defer
+ // the |OnTreeDataChanged| event until after the tree has finished updating.
+ if (update.has_tree_data && data_ != update.tree_data) {
+ update_state.old_tree_data = data_;
+ data_ = update.tree_data;
+ }
+
+ // Update all of the nodes in the update.
for (size_t i = 0; i < update.nodes.size(); ++i) {
- bool is_new_root = !root_exists && update.nodes[i].id == update.root_id;
+ const bool is_new_root = update_state.root_will_be_created &&
+ update.nodes[i].id == update.root_id;
if (!UpdateNode(update.nodes[i], is_new_root, &update_state))
return false;
}
@@ -466,12 +886,8 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
return false;
}
- if (!update_state.pending_nodes.empty()) {
- error_ = "Nodes left pending by the update:";
- for (const AXNode* pending : update_state.pending_nodes)
- error_ += base::StringPrintf(" %d", pending->id());
+ if (!ValidatePendingChangesComplete(update_state))
return false;
- }
// Look for changes to nodes that are a descendant of a table,
// and invalidate their table info if so. We have to walk up the
@@ -495,7 +911,6 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Clear list_info_map_
ordered_set_info_map_.clear();
- std::set<const AXNode*>& new_nodes = update_state.new_nodes;
std::vector<AXTreeObserver::Change> changes;
changes.reserve(update.nodes.size());
for (size_t i = 0; i < update.nodes.size(); ++i) {
@@ -503,7 +918,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
if (!node)
continue;
- bool is_new_node = update_state.IsNewNode(node);
+ bool is_new_node = update_state.IsCreatedNode(node);
bool is_reparented_node = update_state.IsReparentedNode(node);
AXTreeObserver::ChangeType change = AXTreeObserver::NODE_CHANGED;
@@ -514,7 +929,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Note that we also need to check for the special case when we update
// the root without replacing it.
bool is_subtree = !node->parent() ||
- new_nodes.find(node->parent()) == new_nodes.end() ||
+ !update_state.IsCreatedNode(node->parent()) ||
(node->parent() == root_ && root_updated);
change = is_subtree ? AXTreeObserver::SUBTREE_REPARENTED
: AXTreeObserver::NODE_REPARENTED;
@@ -524,7 +939,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
// Note that we also need to check for the special case when we update
// the root without replacing it.
bool is_subtree = !node->parent() ||
- new_nodes.find(node->parent()) == new_nodes.end() ||
+ !update_state.IsCreatedNode(node->parent()) ||
update_state.IsRemovedNode(node->parent()) ||
(node->parent() == root_ && root_updated);
change = is_subtree ? AXTreeObserver::SUBTREE_CREATED
@@ -534,25 +949,58 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
changes.push_back(AXTreeObserver::Change(node, change));
}
- // Update the unignored cached values as necessary.
- for (int parent_id : update_state.invalidate_unignored_cached_values_ids) {
- AXNode* parent = GetFromId(parent_id);
- if (parent)
- parent->UpdateUnignoredCachedValues();
+ // Update the unignored cached values as necessary, ensuring that we only
+ // update once for each unignored node.
+ // If the node is ignored, we must update from an unignored ancestor.
+ std::set<AXNode::AXID> updated_unignored_cached_values_ids;
+ for (AXNode::AXID node_id :
+ update_state.invalidate_unignored_cached_values_ids) {
+ AXNode* node = GetFromId(node_id);
+ while (node && node->data().HasState(ax::mojom::State::kIgnored))
+ node = node->parent();
+ if (node && updated_unignored_cached_values_ids.insert(node->id()).second)
+ node->UpdateUnignoredCachedValues();
+ }
+
+ // Tree is no longer updating.
+ SetTreeUpdateInProgressState(false);
+
+ // Now that the tree is stable and its nodes have been updated, notify if
+ // the tree data changed. We must do this after updating nodes in case the
+ // root has been replaced, so observers have the most up-to-date information.
+ if (update_state.old_tree_data) {
+ for (AXTreeObserver& observer : observers_)
+ observer.OnTreeDataChanged(this, *update_state.old_tree_data, data_);
+ }
+
+ // Now that the unignored cached values are up to date, update observers to
+ // new nodes in the tree.
+ for (AXNode::AXID node_id : update_state.new_node_ids) {
+ NotifyNodeHasBeenReparentedOrCreated(GetFromId(node_id), &update_state);
}
// Now that the unignored cached values are up to date, update observers to
// node changes.
- for (int node_data_changed_id : update_state.node_data_changed_ids) {
+ for (AXNode::AXID node_data_changed_id : update_state.node_data_changed_ids) {
AXNode* node = GetFromId(node_data_changed_id);
- if (node) {
- for (AXTreeObserver& observer : observers_)
- observer.OnNodeChanged(this, node);
+ DCHECK(node);
+
+ // If the node exists and is in the old data map, then the node data
+ // may have changed unless this is a new root.
+ const bool is_new_root = update_state.root_will_be_created &&
+ node_data_changed_id == update.root_id;
+ if (!is_new_root) {
+ auto it = update_state.old_node_id_to_data.find(node_data_changed_id);
+ if (it != update_state.old_node_id_to_data.end()) {
+ const AXNodeData& old_node_data = it->second;
+ NotifyNodeDataHasBeenChanged(node, old_node_data, node->data());
+ }
}
- }
- // Tree is no longer updating.
- SetTreeUpdateInProgressState(false);
+ // |OnNodeChanged| should be fired for all nodes that have been updated.
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeChanged(this, node);
+ }
for (AXTreeObserver& observer : observers_) {
observer.OnAtomicUpdateFinished(this, root_->id() != old_root_id, changes);
@@ -562,6 +1010,7 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
}
AXTableInfo* AXTree::GetTableInfo(const AXNode* const_table_node) const {
+ DCHECK(!GetTreeUpdateInProgressState());
// Note: the const_casts are here because we want this function to be able
// to be called from a const virtual function on AXNode. AXTableInfo is
// computed on demand and cached, but that's an implementation detail
@@ -607,31 +1056,211 @@ std::string AXTree::ToString() const {
}
AXNode* AXTree::CreateNode(AXNode* parent,
- int32_t id,
+ AXNode::AXID id,
size_t index_in_parent,
AXTreeUpdateState* update_state) {
+ DCHECK(GetTreeUpdateInProgressState());
+ // |update_state| must already contain information about all of the expected
+ // changes and invalidations to apply. If any of these are missing, observers
+ // may not be notified of changes.
+ DCHECK(!GetFromId(id));
+ DCHECK_GT(update_state->GetPendingCreateNodeCount(id), 0);
+ DCHECK(update_state->InvalidatesUnignoredCachedValues(id));
+ DCHECK(!parent ||
+ update_state->InvalidatesUnignoredCachedValues(parent->id()));
+ update_state->DecrementPendingCreateNodeCount(id);
+ update_state->new_node_ids.insert(id);
// If this node is the root, use the given index_in_parent as the unignored
// index in parent to provide consistency with index_in_parent.
AXNode* new_node = new AXNode(this, parent, id, index_in_parent,
parent ? 0 : index_in_parent);
id_map_[new_node->id()] = new_node;
- for (AXTreeObserver& observer : observers_) {
- if (update_state->IsReparentedNode(new_node))
- observer.OnNodeReparented(this, new_node);
- else
- observer.OnNodeCreated(this, new_node);
+ return new_node;
+}
+
+bool AXTree::ComputePendingChanges(const AXTreeUpdate& update,
+ AXTreeUpdateState& update_state) {
+ base::AutoReset<bool> computing_pending_changes_resetter(
+ &update_state.computing_pending_changes, true);
+ base::AutoReset<base::Optional<AXNode::AXID>> pending_root_id_resetter(
+ &update_state.pending_root_id,
+ root_ ? base::Optional<AXNode::AXID>{root_->id()} : base::nullopt);
+
+ // We distinguish between updating the root, e.g. changing its children or
+ // some of its attributes, or replacing the root completely. If the root is
+ // being updated, update.node_id_to_clear should hold the current root's ID.
+ // Otherwise if the root is being replaced, update.root_id should hold the ID
+ // of the new root.
+ if (update.node_id_to_clear != AXNode::kInvalidAXID) {
+ if (AXNode* cleared_node = GetFromId(update.node_id_to_clear)) {
+ DCHECK(root_);
+ if (cleared_node == root_ &&
+ update.root_id != update_state.pending_root_id) {
+ // Only destroy the root if the root was replaced and not if it's simply
+ // updated. To figure out if the root was simply updated, we compare
+ // the ID of the new root with the existing root ID.
+ MarkSubtreeForDestruction(*update_state.pending_root_id, &update_state);
+ }
+
+ // If the tree has been marked for destruction because the root will be
+ // replaced, there is nothing more to clear.
+ if (update_state.ShouldPendingNodeExistInTree(root_->id())) {
+ update_state.invalidate_unignored_cached_values_ids.insert(
+ cleared_node->id());
+ update_state.ClearLastKnownPendingNodeData(cleared_node->id());
+ for (AXNode* child : cleared_node->children()) {
+ MarkSubtreeForDestruction(child->id(), &update_state);
+ }
+ }
+ }
}
- AXNode* unignored_parent = new_node->GetUnignoredParent();
- if (unignored_parent) {
- update_state->invalidate_unignored_cached_values_ids.insert(
- unignored_parent->id());
+
+ update_state.root_will_be_created =
+ !GetFromId(update.root_id) ||
+ !update_state.ShouldPendingNodeExistInTree(update.root_id);
+
+ // Populate |update_state| with all of the changes that will be performed
+ // on the tree during the update.
+ for (const AXNodeData& new_data : update.nodes) {
+ bool is_new_root =
+ update_state.root_will_be_created && new_data.id == update.root_id;
+ if (!ComputePendingChangesToNode(new_data, is_new_root, &update_state)) {
+ return false;
+ }
}
- return new_node;
+
+ return true;
+}
+
+bool AXTree::ComputePendingChangesToNode(const AXNodeData& new_data,
+ bool is_new_root,
+ AXTreeUpdateState* update_state) {
+ // If the node does not exist in the tree throw an error unless this
+ // is the new root and it can be created.
+ if (!update_state->ShouldPendingNodeExistInTree(new_data.id)) {
+ if (!is_new_root) {
+ error_ = base::StringPrintf(
+ "%d will not be in the tree and is not the new root", new_data.id);
+ return false;
+ }
+
+ // Creation is implicit for new root nodes. If |new_data.id| is already
+ // pending for creation, then it must be a duplicate entry in the tree.
+ if (!update_state->IncrementPendingCreateNodeCount(new_data.id,
+ base::nullopt)) {
+ error_ = base::StringPrintf(
+ "Node %d is already pending for creation, cannot be the new root",
+ new_data.id);
+ return false;
+ }
+ if (update_state->pending_root_id) {
+ MarkSubtreeForDestruction(*update_state->pending_root_id, update_state);
+ }
+ update_state->pending_root_id = new_data.id;
+ }
+
+ // Create a set of new child ids so we can use it to find the nodes that
+ // have been added and removed. Returns false if a duplicate is found.
+ std::set<AXNode::AXID> new_child_id_set;
+ for (AXNode::AXID new_child_id : new_data.child_ids) {
+ if (base::Contains(new_child_id_set, new_child_id)) {
+ error_ = base::StringPrintf("Node %d has duplicate child id %d",
+ new_data.id, new_child_id);
+ return false;
+ }
+ new_child_id_set.insert(new_child_id);
+ }
+
+ // If the node has not been initialized yet then its node data has either been
+ // cleared when handling |node_id_to_clear|, or it's a new node.
+ // In either case, all children must be created.
+ if (update_state->DoesPendingNodeRequireInit(new_data.id)) {
+ update_state->invalidate_unignored_cached_values_ids.insert(new_data.id);
+
+ // If this node has been cleared via |node_id_to_clear| or is a new node,
+ // the last-known parent's unignored cache needs to be updated.
+ update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
+
+ for (AXNode::AXID child_id : new_child_id_set) {
+ // If a |child_id| is already pending for creation, then it must be a
+ // duplicate entry in the tree.
+ update_state->invalidate_unignored_cached_values_ids.insert(child_id);
+ if (!update_state->IncrementPendingCreateNodeCount(child_id,
+ new_data.id)) {
+ error_ = base::StringPrintf(
+ "Node %d is already pending for creation, cannot be a new child",
+ child_id);
+ return false;
+ }
+ }
+
+ update_state->SetLastKnownPendingNodeData(&new_data);
+ return true;
+ }
+
+ const AXNodeData& old_data =
+ update_state->GetLastKnownPendingNodeData(new_data.id);
+
+ // Create a set of old child ids so we can use it to find the nodes that
+ // have been added and removed.
+ std::set<AXNode::AXID> old_child_id_set(old_data.child_ids.cbegin(),
+ old_data.child_ids.cend());
+
+ std::vector<AXNode::AXID> create_or_destroy_ids;
+ std::set_symmetric_difference(
+ old_child_id_set.cbegin(), old_child_id_set.cend(),
+ new_child_id_set.cbegin(), new_child_id_set.cend(),
+ std::back_inserter(create_or_destroy_ids));
+
+ // If the node has changed ignored state or there are any differences in
+ // its children, then its unignored cached values must be invalidated.
+ const bool ignored_changed = old_data.HasState(ax::mojom::State::kIgnored) !=
+ new_data.HasState(ax::mojom::State::kIgnored);
+ if (!create_or_destroy_ids.empty() || ignored_changed) {
+ update_state->invalidate_unignored_cached_values_ids.insert(new_data.id);
+
+ // If this ignored state had changed also invalidate the parent.
+ update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
+ }
+
+ for (AXNode::AXID child_id : create_or_destroy_ids) {
+ if (base::Contains(new_child_id_set, child_id)) {
+ // This is a serious error - nodes should never be reparented without
+ // first being removed from the tree. If a node exists in the tree already
+ // then adding it to a new parent would mean stealing the node from its
+ // old parent which hadn't been updated to reflect the change.
+ if (update_state->ShouldPendingNodeExistInTree(child_id)) {
+ error_ = base::StringPrintf(
+ "Node %d is not marked for destruction, would be reparented to %d",
+ child_id, new_data.id);
+ return false;
+ }
+
+ // If a |child_id| is already pending for creation, then it must be a
+ // duplicate entry in the tree.
+ update_state->invalidate_unignored_cached_values_ids.insert(child_id);
+ if (!update_state->IncrementPendingCreateNodeCount(child_id,
+ new_data.id)) {
+ error_ = base::StringPrintf(
+ "Node %d is already pending for creation, cannot be a new child",
+ child_id);
+ return false;
+ }
+ } else {
+ // If |child_id| does not exist in the new set, then it has
+ // been removed from |node|, and the subtree must be deleted.
+ MarkSubtreeForDestruction(child_id, update_state);
+ }
+ }
+
+ update_state->SetLastKnownPendingNodeData(&new_data);
+ return true;
}
bool AXTree::UpdateNode(const AXNodeData& src,
bool is_new_root,
AXTreeUpdateState* update_state) {
+ DCHECK(GetTreeUpdateInProgressState());
// This method updates one node in the tree based on serialized data
// received in an AXTreeUpdate. See AXTreeUpdate for pre and post
// conditions.
@@ -641,51 +1270,13 @@ bool AXTree::UpdateNode(const AXNodeData& src,
// and this is a serious error.
AXNode* node = GetFromId(src.id);
if (node) {
- update_state->pending_nodes.erase(node);
-
- // TODO(accessibility): CallNodeChangeCallbacks should not pass |node|,
- // since the tree and the node data are not yet in a consistent
- // state. Possibly only pass id.
- if (!update_state->IsNewNode(node) ||
+ update_state->pending_nodes.erase(node->id());
+ UpdateReverseRelations(node, src);
+ if (!update_state->IsCreatedNode(node) ||
update_state->IsReparentedNode(node)) {
- auto it = update_state->reparented_node_id_to_data.find(node->id());
- const AXNodeData& old_data =
- it != update_state->reparented_node_id_to_data.end() ? it->second
- : node->data();
- CallNodeChangeCallbacks(node, old_data, src);
- if (old_data.HasState(ax::mojom::State::kIgnored) !=
- src.HasState(ax::mojom::State::kIgnored)) {
- AXNode* unignored_parent = node->GetUnignoredParent();
- if (unignored_parent) {
- update_state->invalidate_unignored_cached_values_ids.insert(
- unignored_parent->id());
- }
-
- // We must invalidate the node if it's no longer State::kIgnored.
- // Since nodes updated in no particular order, this node may
- // not be added to the set later or update its cached values.
- //
- // For example, given the following tree, :
- // A unignored
- // |
- // B ignored
- // |
- // C unignored
- //
- // ... and the following updates :
- // Update C unignored => ignored
- // Update B ignored => unignored
- //
- // Both updates would add A to the set of nodes which have invalid
- // cached values, but B would never be added because ignored nodes
- // are skipped over.
- if (!src.HasState(ax::mojom::State::kIgnored)) {
- update_state->invalidate_unignored_cached_values_ids.insert(
- node->id());
- }
- }
+ update_state->old_node_id_to_data.insert(
+ std::make_pair(node->id(), node->TakeData()));
}
- UpdateReverseRelations(node, src);
node->SetData(src);
} else {
if (!is_new_root) {
@@ -694,9 +1285,7 @@ bool AXTree::UpdateNode(const AXNodeData& src,
return false;
}
- update_state->new_root = CreateNode(nullptr, src.id, 0, update_state);
- node = update_state->new_root;
- update_state->new_nodes.insert(node);
+ node = CreateNode(nullptr, src.id, 0, update_state);
UpdateReverseRelations(node, src);
node->SetData(src);
}
@@ -705,26 +1294,7 @@ bool AXTree::UpdateNode(const AXNodeData& src,
// First, delete nodes that used to be children of this node but aren't
// anymore.
- if (!DeleteOldChildren(node, src.child_ids, update_state)) {
- // If DeleteOldChildren failed, we need to carefully clean up before
- // returning false as well. In particular, if this node was a new root,
- // we need to safely destroy the whole tree.
- if (update_state->new_root) {
- AXNode* old_root = root_;
- root_ = nullptr;
-
- DestroySubtree(old_root, update_state);
-
- // Delete |node|'s subtree too as long as it wasn't already removed
- // or added elsewhere in the tree.
- if (update_state->removed_node_ids.find(src.id) ==
- update_state->removed_node_ids.end() &&
- update_state->new_nodes.find(node) != update_state->new_nodes.end()) {
- DestroySubtree(node, update_state);
- }
- }
- return false;
- }
+ DeleteOldChildren(node, src.child_ids, update_state);
// Now build a new children vector, reusing nodes when possible,
// and swap it in.
@@ -746,11 +1316,84 @@ bool AXTree::UpdateNode(const AXNodeData& src,
return success;
}
-void AXTree::CallNodeChangeCallbacks(AXNode* node,
- const AXNodeData& old_data,
- const AXNodeData& new_data) {
+void AXTree::NotifySubtreeWillBeReparentedOrDeleted(
+ AXNode* node,
+ const AXTreeUpdateState* update_state) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (node->id() == AXNode::kInvalidAXID)
+ return;
+
+ for (AXTreeObserver& observer : observers_) {
+ if (update_state->IsPotentiallyReparentedNode(node)) {
+ observer.OnSubtreeWillBeReparented(this, node);
+ } else {
+ observer.OnSubtreeWillBeDeleted(this, node);
+ }
+ }
+}
+
+void AXTree::NotifyNodeWillBeReparentedOrDeleted(
+ AXNode* node,
+ const AXTreeUpdateState* update_state) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (node->id() == AXNode::kInvalidAXID)
+ return;
+
+ for (AXTreeObserver& observer : observers_) {
+ if (update_state->IsPotentiallyReparentedNode(node)) {
+ observer.OnNodeWillBeReparented(this, node);
+ } else {
+ observer.OnNodeWillBeDeleted(this, node);
+ }
+ }
+}
+
+void AXTree::RecursivelyNotifyNodeWillBeDeleted(AXNode* node) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (node->id() == AXNode::kInvalidAXID)
+ return;
+
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeWillBeDeleted(this, node);
+ for (auto* child : node->children())
+ RecursivelyNotifyNodeWillBeDeleted(child);
+}
+
+void AXTree::NotifyNodeHasBeenReparentedOrCreated(
+ AXNode* node,
+ const AXTreeUpdateState* update_state) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (node->id() == AXNode::kInvalidAXID)
+ return;
+
+ for (AXTreeObserver& observer : observers_) {
+ if (update_state->IsReparentedNode(node)) {
+ observer.OnNodeReparented(this, node);
+ } else {
+ observer.OnNodeCreated(this, node);
+ }
+ }
+}
+
+void AXTree::NotifyNodeDataWillChange(const AXNodeData& old_data,
+ const AXNodeData& new_data) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (new_data.id == AXNode::kInvalidAXID)
+ return;
+
for (AXTreeObserver& observer : observers_)
observer.OnNodeDataWillChange(this, old_data, new_data);
+}
+
+void AXTree::NotifyNodeDataHasBeenChanged(AXNode* node,
+ const AXNodeData& old_data,
+ const AXNodeData& new_data) {
+ DCHECK(!GetTreeUpdateInProgressState());
+ if (node->id() == AXNode::kInvalidAXID)
+ return;
+
+ for (AXTreeObserver& observer : observers_)
+ observer.OnNodeDataChanged(this, old_data, new_data);
if (old_data.role != new_data.role) {
for (AXTreeObserver& observer : observers_)
@@ -832,6 +1475,7 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node,
}
void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
+ DCHECK(GetTreeUpdateInProgressState());
const AXNodeData& old_data = node->data();
int id = new_data.id;
auto int_callback = [this, id](ax::mojom::IntAttribute attr,
@@ -905,20 +1549,89 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
string_callback);
}
+bool AXTree::ValidatePendingChangesComplete(
+ const AXTreeUpdateState& update_state) {
+ if (!update_state.pending_nodes.empty()) {
+ error_ = "Nodes left pending by the update:";
+ for (const AXNode::AXID pending_id : update_state.pending_nodes)
+ error_ += base::StringPrintf(" %d", pending_id);
+ return false;
+ }
+
+ if (!update_state.node_id_to_pending_data.empty()) {
+ std::string destroy_subtree_ids;
+ std::string destroy_node_ids;
+ std::string create_node_ids;
+
+ bool has_pending_changes = false;
+ for (auto&& pair : update_state.node_id_to_pending_data) {
+ const AXNode::AXID pending_id = pair.first;
+ const std::unique_ptr<PendingStructureChanges>& data = pair.second;
+ if (data->DoesNodeExpectAnyStructureChanges()) {
+ if (data->DoesNodeExpectSubtreeWillBeDestroyed())
+ destroy_subtree_ids += base::StringPrintf(" %d", pending_id);
+ if (data->DoesNodeExpectNodeWillBeDestroyed())
+ destroy_node_ids += base::StringPrintf(" %d", pending_id);
+ if (data->DoesNodeExpectNodeWillBeCreated())
+ create_node_ids += base::StringPrintf(" %d", pending_id);
+ has_pending_changes = true;
+ }
+ }
+ if (has_pending_changes) {
+ error_ = base::StringPrintf(
+ "Changes left pending by the update; "
+ "destroy subtrees: %s, destroy nodes: %s, create nodes: %s",
+ destroy_subtree_ids.c_str(), destroy_node_ids.c_str(),
+ create_node_ids.c_str());
+ }
+ return !has_pending_changes;
+ }
+
+ return true;
+}
+
+void AXTree::MarkSubtreeForDestruction(AXNode::AXID node_id,
+ AXTreeUpdateState* update_state) {
+ update_state->IncrementPendingDestroySubtreeCount(node_id);
+ MarkNodesForDestructionRecursive(node_id, update_state);
+}
+
+void AXTree::MarkNodesForDestructionRecursive(AXNode::AXID node_id,
+ AXTreeUpdateState* update_state) {
+ // If this subtree has already been marked for destruction, return so
+ // we don't walk it again.
+ if (!update_state->ShouldPendingNodeExistInTree(node_id))
+ return;
+
+ const AXNodeData& last_known_data =
+ update_state->GetLastKnownPendingNodeData(node_id);
+
+ update_state->IncrementPendingDestroyNodeCount(node_id);
+ for (AXNode::AXID child_id : last_known_data.child_ids) {
+ MarkNodesForDestructionRecursive(child_id, update_state);
+ }
+}
+
void AXTree::DestroySubtree(AXNode* node,
AXTreeUpdateState* update_state) {
+ DCHECK(GetTreeUpdateInProgressState());
+ // |update_state| must already contain information about all of the expected
+ // changes and invalidations to apply. If any of these are missing, observers
+ // may not be notified of changes.
DCHECK(update_state);
- for (AXTreeObserver& observer : observers_) {
- if (update_state->IsPotentiallyReparentedNode(node))
- observer.OnSubtreeWillBeReparented(this, node);
- else
- observer.OnSubtreeWillBeDeleted(this, node);
- }
+ DCHECK_GT(update_state->GetPendingDestroySubtreeCount(node->id()), 0);
+ DCHECK(!node->parent() ||
+ update_state->InvalidatesUnignoredCachedValues(node->parent()->id()));
+ update_state->DecrementPendingDestroySubtreeCount(node->id());
DestroyNodeAndSubtree(node, update_state);
}
void AXTree::DestroyNodeAndSubtree(AXNode* node,
AXTreeUpdateState* update_state) {
+ DCHECK(GetTreeUpdateInProgressState());
+ DCHECK(!update_state ||
+ update_state->GetPendingDestroyNodeCount(node->id()) > 0);
+
// Clear out any reverse relations.
AXNodeData empty_data;
empty_data.id = node->id();
@@ -931,62 +1644,46 @@ void AXTree::DestroyNodeAndSubtree(AXNode* node,
table_info_map_.erase(node->id());
}
- for (AXTreeObserver& observer : observers_) {
- if (update_state && update_state->IsPotentiallyReparentedNode(node))
- observer.OnNodeWillBeReparented(this, node);
- else
- observer.OnNodeWillBeDeleted(this, node);
- }
id_map_.erase(node->id());
for (auto* child : node->children())
DestroyNodeAndSubtree(child, update_state);
if (update_state) {
- AXNode* unignored_parent = node->GetUnignoredParent();
- if (unignored_parent) {
- update_state->invalidate_unignored_cached_values_ids.insert(
- unignored_parent->id());
- }
- update_state->pending_nodes.erase(node);
+ update_state->pending_nodes.erase(node->id());
+ update_state->DecrementPendingDestroyNodeCount(node->id());
update_state->removed_node_ids.insert(node->id());
- }
-
- if (update_state && update_state->IsReparentedNode(node)) {
- update_state->reparented_node_id_to_data.insert(
- std::make_pair(node->id(), node->TakeData()));
+ update_state->new_node_ids.erase(node->id());
+ update_state->node_data_changed_ids.erase(node->id());
+ if (update_state->IsReparentedNode(node)) {
+ update_state->old_node_id_to_data.emplace(
+ std::make_pair(node->id(), node->TakeData()));
+ }
}
node->Destroy();
}
-bool AXTree::DeleteOldChildren(AXNode* node,
+void AXTree::DeleteOldChildren(AXNode* node,
const std::vector<int32_t>& new_child_ids,
AXTreeUpdateState* update_state) {
- // Create a set of child ids in |src| for fast lookup, and return false
- // if a duplicate is found;
- std::set<int32_t> new_child_id_set;
- for (size_t i = 0; i < new_child_ids.size(); ++i) {
- if (new_child_id_set.find(new_child_ids[i]) != new_child_id_set.end()) {
- error_ = base::StringPrintf("Node %d has duplicate child id %d",
- node->id(), new_child_ids[i]);
- return false;
- }
- new_child_id_set.insert(new_child_ids[i]);
- }
+ DCHECK(GetTreeUpdateInProgressState());
+ // Create a set of child ids in |src| for fast lookup, we know the set does
+ // not contain duplicate entries already, because that was handled when
+ // populating |update_state| with information about all of the expected
+ // changes to be applied.
+ std::set<int32_t> new_child_id_set(new_child_ids.begin(),
+ new_child_ids.end());
// Delete the old children.
- const std::vector<AXNode*>& old_children = node->children();
- for (size_t i = 0; i < old_children.size(); ++i) {
- int old_id = old_children[i]->id();
- if (new_child_id_set.find(old_id) == new_child_id_set.end())
- DestroySubtree(old_children[i], update_state);
+ for (AXNode* child : node->children()) {
+ if (!base::Contains(new_child_id_set, child->id()))
+ DestroySubtree(child, update_state);
}
-
- return true;
}
bool AXTree::CreateNewChildVector(AXNode* node,
const std::vector<int32_t>& new_child_ids,
std::vector<AXNode*>* new_children,
AXTreeUpdateState* update_state) {
+ DCHECK(GetTreeUpdateInProgressState());
bool success = true;
for (size_t i = 0; i < new_child_ids.size(); ++i) {
int32_t child_id = new_child_ids[i];
@@ -1007,8 +1704,7 @@ bool AXTree::CreateNewChildVector(AXNode* node,
child->SetIndexInParent(i);
} else {
child = CreateNode(node, child_id, i, update_state);
- update_state->pending_nodes.insert(child);
- update_state->new_nodes.insert(child);
+ update_state->pending_nodes.insert(child->id());
}
new_children->push_back(child);
}
@@ -1037,8 +1733,8 @@ void AXTree::PopulateOrderedSetItems(const AXNode* ordered_set,
const AXNode* local_parent,
std::vector<const AXNode*>& items,
const AXNode& original_node) const {
- // ignored nodes are not a part of ordered sets.
- if (original_node.data().HasState(ax::mojom::State::kIgnored))
+ // Ignored nodes are not a part of ordered sets.
+ if (original_node.IsIgnored())
return;
// Stop searching current path if roles of local_parent and ordered set match.
diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h
index 5a657d2e30f..fc27e059651 100644
--- a/chromium/ui/accessibility/ax_tree.h
+++ b/chromium/ui/accessibility/ax_tree.h
@@ -173,25 +173,78 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
AXTableInfo* GetTableInfo(const AXNode* table_node) const override;
AXNode* CreateNode(AXNode* parent,
- int32_t id,
+ AXNode::AXID id,
size_t index_in_parent,
AXTreeUpdateState* update_state);
+ // Accumulates the work that will be required to update the AXTree.
+ // This allows us to notify observers of structure changes when the
+ // tree is still in a stable and unchanged state.
+ bool ComputePendingChanges(const AXTreeUpdate& update,
+ AXTreeUpdateState& update_state);
+
+ // Populates |update_state| with information about actions that will
+ // be performed on the tree during the update, such as adding or
+ // removing nodes in the tree. Returns true on success.
+ // Nothing within this call should modify tree structure or node data.
+ bool ComputePendingChangesToNode(const AXNodeData& new_data,
+ bool is_new_root,
+ AXTreeUpdateState* update_state);
+
// This is called from within Unserialize(), it returns true on success.
bool UpdateNode(const AXNodeData& src,
bool is_new_root,
AXTreeUpdateState* update_state);
- void CallNodeChangeCallbacks(AXNode* node,
- const AXNodeData& old_data,
- const AXNodeData& new_data);
+ // Notify the delegate that the subtree rooted at |node| will be
+ // destroyed or reparented.
+ void NotifySubtreeWillBeReparentedOrDeleted(
+ AXNode* node,
+ const AXTreeUpdateState* update_state);
+
+ // Notify the delegate that |node| will be destroyed or reparented.
+ void NotifyNodeWillBeReparentedOrDeleted(
+ AXNode* node,
+ const AXTreeUpdateState* update_state);
+
+ // Notify the delegate that |node| and all of its descendants will be
+ // destroyed.
+ void RecursivelyNotifyNodeWillBeDeleted(AXNode* node);
+
+ // Notify the delegate that |node| has been created or reparented.
+ void NotifyNodeHasBeenReparentedOrCreated(
+ AXNode* node,
+ const AXTreeUpdateState* update_state);
+
+ // Notify the delegate that a node will change its data.
+ void NotifyNodeDataWillChange(const AXNodeData& old_data,
+ const AXNodeData& new_data);
+
+ // Notify the delegate that |node| has changed its data.
+ void NotifyNodeDataHasBeenChanged(AXNode* node,
+ const AXNodeData& old_data,
+ const AXNodeData& new_data);
void UpdateReverseRelations(AXNode* node, const AXNodeData& new_data);
- void OnRootChanged();
+ // Returns true if all pending changes in the |update_state| have been
+ // handled. If this returns false, the |error_| message will be populated.
+ // It's a fatal error to have pending changes after exhausting
+ // the AXTreeUpdate.
+ bool ValidatePendingChangesComplete(const AXTreeUpdateState& update_state);
+
+ // Modifies |update_state| so that it knows what subtree and nodes are
+ // going to be destroyed for the subtree rooted at |node|.
+ void MarkSubtreeForDestruction(AXNode::AXID node_id,
+ AXTreeUpdateState* update_state);
+
+ // Modifies |update_state| so that it knows what nodes are
+ // going to be destroyed for the subtree rooted at |node|.
+ void MarkNodesForDestructionRecursive(AXNode::AXID node_id,
+ AXTreeUpdateState* update_state);
- // Notify the delegate that the subtree rooted at |node| will be destroyed,
- // then call DestroyNodeAndSubtree on it.
+ // Validates that destroying the subtree rooted at |node| has required
+ // information in |update_state|, then calls DestroyNodeAndSubtree on it.
void DestroySubtree(AXNode* node, AXTreeUpdateState* update_state);
// Call Destroy() on |node|, and delete it from the id map, and then
@@ -199,9 +252,8 @@ class AX_EXPORT AXTree : public AXNode::OwnerTree {
void DestroyNodeAndSubtree(AXNode* node, AXTreeUpdateState* update_state);
// Iterate over the children of |node| and for each child, destroy the
- // child and its subtree if its id is not in |new_child_ids|. Returns
- // true on success, false on fatal error.
- bool DeleteOldChildren(AXNode* node,
+ // child and its subtree if its id is not in |new_child_ids|.
+ void DeleteOldChildren(AXNode* node,
const std::vector<int32_t>& new_child_ids,
AXTreeUpdateState* update_state);
diff --git a/chromium/ui/accessibility/ax_tree_observer.h b/chromium/ui/accessibility/ax_tree_observer.h
index eec7d75498b..d6652aca47c 100644
--- a/chromium/ui/accessibility/ax_tree_observer.h
+++ b/chromium/ui/accessibility/ax_tree_observer.h
@@ -18,33 +18,34 @@ struct AXTreeData;
// Used when you want to be notified when changes happen to an AXTree.
//
-// Some of the notifications are called in the middle of an update operation.
-// Be careful, as the tree may be in an inconsistent state at this time;
-// don't walk the parents and children at this time:
-// OnNodeWillBeDeleted
-// OnSubtreeWillBeDeleted
-// OnNodeWillBeReparented
-// OnSubtreeWillBeReparented
-// OnNodeCreated
-// OnNodeReparented
-// OnNodeChanged
-//
-// In addition, one additional notification is fired at the end of an
-// atomic update, and it provides a vector of nodes that were added or
-// changed, for final postprocessing:
-// OnAtomicUpdateFinished
-//
+// |OnAtomicUpdateFinished| is notified at the end of an atomic update.
+// It provides a vector of nodes that were added or changed, for final
+// postprocessing.
class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
public:
AXTreeObserver();
~AXTreeObserver() override;
- // Called before a node's data gets updated.
+ // Called before any tree modifications have occurred, notifying that a single
+ // node will change its data. Its id and data will be valid, but its links to
+ // parents and children are only valid within this callstack. Do not hold a
+ // reference to the node or any relative nodes such as ancestors or
+ // descendants described by the node data outside of this event.
virtual void OnNodeDataWillChange(AXTree* tree,
const AXNodeData& old_node_data,
const AXNodeData& new_node_data) {}
+ // Called after all tree modifications have occurred, notifying that a single
+ // node has changed its data. Its id, data, and links to parent and children
+ // will all be valid, since the tree is in a stable state after updating.
+ virtual void OnNodeDataChanged(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) {}
+
// Individual callbacks for every attribute of AXNodeData that can change.
+ // Called after all tree mutations have occurred, notifying that a single node
+ // changed its data. Its id, data, and links to parent and children will all
+ // be valid, since the tree is in a stable state after updating.
virtual void OnRoleChanged(AXTree* tree,
AXNode* node,
ax::mojom::Role old_role,
@@ -85,19 +86,18 @@ class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
const std::vector<std::string>& old_value,
const std::vector<std::string>& new_value) {}
- // Called when tree data changes.
+ // Called when tree data changes, after all nodes have been updated.
virtual void OnTreeDataChanged(AXTree* tree,
const AXTreeData& old_data,
const AXTreeData& new_data) {}
- // Called just before a node is deleted. Its id and data will be valid,
- // but its links to parents and children are invalid. This is called
- // in the middle of an update, the tree may be in an invalid state!
+ // Called before any tree modifications have occurred, notifying that a single
+ // node will be deleted. Its id and data will be valid, but its links to
+ // parents and children are only valid within this callstack. Do not hold
+ // a reference to node outside of the event.
virtual void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) {}
// Same as OnNodeWillBeDeleted, but only called once for an entire subtree.
- // This is called in the middle of an update, the tree may be in an
- // invalid state!
virtual void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) {}
// Called just before a node is deleted for reparenting. See
@@ -108,16 +108,18 @@ class AX_EXPORT AXTreeObserver : public base::CheckedObserver {
// |OnSubtreeWillBeDeleted| for additional information.
virtual void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) {}
- // Called immediately after a new node is created. The tree may be in
- // the middle of an update, don't walk the parents and children now.
+ // Called after all tree mutations have occurred, notifying that a single node
+ // has been created. Its id, data, and links to parent and children will all
+ // be valid, since the tree is in a stable state after updating.
virtual void OnNodeCreated(AXTree* tree, AXNode* node) {}
- // Called immediately after a node is reparented. The tree may be in the
- // middle of an update, don't walk the parents and children now.
+ // Same as |OnNodeCreated|, but called for nodes that have been reparented.
virtual void OnNodeReparented(AXTree* tree, AXNode* node) {}
- // Called when a node changes its data or children. The tree may be in
- // the middle of an update, don't walk the parents and children now.
+ // Called after all tree mutations have occurred, notifying that a single node
+ // has updated its data or children. Its id, data, and links to parent and
+ // children will all be valid, since the tree is in a stable state after
+ // updating.
virtual void OnNodeChanged(AXTree* tree, AXNode* node) {}
enum ChangeType {
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 9dd7309d9f3..63e3bb32389 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -84,13 +84,23 @@ class TestAXTreeObserver : public AXTreeObserver {
void OnNodeDataWillChange(AXTree* tree,
const AXNodeData& old_node_data,
const AXNodeData& new_node_data) override {}
+ void OnNodeDataChanged(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) override {}
void OnTreeDataChanged(AXTree* tree,
const ui::AXTreeData& old_data,
const ui::AXTreeData& new_data) override {
tree_data_changed_ = true;
}
+
+ base::Optional<AXNode::AXID> unignored_parent_id_before_node_deleted;
void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override {
deleted_ids_.push_back(node->id());
+ if (unignored_parent_id_before_node_deleted) {
+ ASSERT_NE(nullptr, node->GetUnignoredParent());
+ ASSERT_EQ(*unignored_parent_id_before_node_deleted,
+ node->GetUnignoredParent()->id());
+ }
}
void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override {
@@ -115,8 +125,6 @@ class TestAXTreeObserver : public AXTreeObserver {
void OnNodeChanged(AXTree* tree, AXNode* node) override {
changed_ids_.push_back(node->id());
- if (call_posinset_and_setsize)
- AssertPosinsetAndSetsizeNotSet(node);
}
void OnAtomicUpdateFinished(AXTree* tree,
@@ -247,12 +255,6 @@ class TestAXTreeObserver : public AXTreeObserver {
return attribute_change_log_;
}
- bool call_posinset_and_setsize = false;
- void AssertPosinsetAndSetsizeNotSet(AXNode* node) {
- ASSERT_FALSE(node->GetPosInSet());
- ASSERT_FALSE(node->GetSetSize());
- }
-
private:
AXTree* tree_;
bool tree_data_changed_;
@@ -457,7 +459,8 @@ TEST(AXTreeTest, InvalidReparentingFails) {
update.nodes[1].id = 2;
update.nodes[2].id = 3;
EXPECT_FALSE(tree.Unserialize(update));
- ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
+ ASSERT_EQ("Node 3 is not marked for destruction, would be reparented to 1",
+ tree.error());
}
TEST(AXTreeTest, NoReparentingOfRootIfNoNewRoot) {
@@ -814,6 +817,35 @@ TEST(AXTreeTest, MultipleIgnoredChangesDoesNotBreakCache) {
EXPECT_TRUE(tree.GetFromId(3)->data().HasState(ax::mojom::State::kIgnored));
}
+TEST(AXTreeTest, NodeToClearUpdatesParentUnignoredCount) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].child_ids.push_back(2);
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].AddState(ax::mojom::State::kIgnored);
+ initial_state.nodes[1].child_ids.push_back(3);
+ initial_state.nodes[1].child_ids.push_back(4);
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[3].id = 4;
+
+ AXTree tree(initial_state);
+ EXPECT_EQ(2u, tree.GetFromId(1)->GetUnignoredChildCount());
+ EXPECT_EQ(2u, tree.GetFromId(2)->GetUnignoredChildCount());
+
+ AXTreeUpdate update;
+ update.nodes.resize(1);
+ update.node_id_to_clear = 2;
+ update.root_id = 1;
+ update.nodes[0] = initial_state.nodes[1];
+ update.nodes[0].state = 0;
+ update.nodes[0].child_ids.resize(0);
+ EXPECT_TRUE(tree.Unserialize(update)) << tree.error();
+
+ EXPECT_EQ(1u, tree.GetFromId(1)->GetUnignoredChildCount());
+}
+
TEST(AXTreeTest, TreeObserverIsNotCalledForReparenting) {
AXTreeUpdate initial_state;
initial_state.root_id = 1;
@@ -1629,6 +1661,7 @@ TEST(AXTreeTest, CachedUnignoredValues) {
root = tree.root();
EXPECT_EQ(2u, root->GetUnignoredChildCount());
EXPECT_EQ(2, root->GetUnignoredChildAtIndex(0)->id());
+ EXPECT_EQ(2u, tree.GetFromId(2)->GetUnignoredChildCount());
EXPECT_EQ(0u, tree.GetFromId(4)->GetUnignoredIndexInParent());
EXPECT_EQ(1u, tree.GetFromId(5)->GetUnignoredIndexInParent());
@@ -1639,6 +1672,7 @@ TEST(AXTreeTest, CachedUnignoredValues) {
EXPECT_TRUE(tree.Unserialize(update2));
+ EXPECT_EQ(1u, tree.GetFromId(2)->GetUnignoredChildCount());
EXPECT_EQ(0u, tree.GetFromId(5)->GetUnignoredIndexInParent());
// Ensure siblings of a deleted node are updated.
@@ -1649,6 +1683,7 @@ TEST(AXTreeTest, CachedUnignoredValues) {
EXPECT_TRUE(tree.Unserialize(update3));
+ EXPECT_EQ(1u, tree.GetFromId(1)->GetUnignoredChildCount());
EXPECT_EQ(0u, tree.GetFromId(3)->GetUnignoredIndexInParent());
// Ensure new nodes are correctly updated.
@@ -1662,6 +1697,7 @@ TEST(AXTreeTest, CachedUnignoredValues) {
EXPECT_TRUE(tree.Unserialize(update4));
+ EXPECT_EQ(2u, tree.GetFromId(1)->GetUnignoredChildCount());
EXPECT_EQ(0u, tree.GetFromId(3)->GetUnignoredIndexInParent());
EXPECT_EQ(1u, tree.GetFromId(6)->GetUnignoredIndexInParent());
EXPECT_EQ(0u, tree.GetFromId(7)->GetUnignoredIndexInParent());
@@ -1750,111 +1786,111 @@ TEST(AXTreeTest, NullUnignoredChildren) {
TEST(AXTreeTest, UnignoredChildIterator) {
AXTreeUpdate tree_update;
// (i) => node is ignored
- // 0
+ // 1
// |__________
// | | |
- // 1(i) 2 3
+ // 2(i) 3 4
// |_______________________
// | | | |
- // 4 5 6(i) 7(i)
+ // 5 6 7(i) 8(i)
// | | |________
// | | | |
- // 8 9(i) 10(i) 11
+ // 9 10(i) 11(i) 12
// | |____
// | | |
- // 12(i) 13 14
- tree_update.root_id = 0;
+ // 13(i) 14 15
+ tree_update.root_id = 1;
tree_update.nodes.resize(15);
- tree_update.nodes[0].id = 0;
- tree_update.nodes[0].child_ids = {1, 2, 3};
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
- tree_update.nodes[1].id = 1;
- tree_update.nodes[1].child_ids = {4, 5, 6, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].child_ids = {5, 6, 7, 8};
tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[2].id = 2;
- tree_update.nodes[3].id = 3;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[3].id = 4;
- tree_update.nodes[4].id = 4;
- tree_update.nodes[4].child_ids = {8};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].child_ids = {9};
- tree_update.nodes[5].id = 5;
- tree_update.nodes[5].child_ids = {9};
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].child_ids = {10};
- tree_update.nodes[6].id = 6;
- tree_update.nodes[6].child_ids = {10, 11};
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].child_ids = {11, 12};
tree_update.nodes[6].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[7].id = 7;
+ tree_update.nodes[7].id = 8;
tree_update.nodes[7].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[8].id = 8;
+ tree_update.nodes[8].id = 9;
- tree_update.nodes[9].id = 9;
- tree_update.nodes[9].child_ids = {12};
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].child_ids = {13};
tree_update.nodes[9].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[10].id = 10;
- tree_update.nodes[10].child_ids = {13, 14};
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].child_ids = {14, 15};
tree_update.nodes[10].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[11].id = 11;
+ tree_update.nodes[11].id = 12;
- tree_update.nodes[12].id = 12;
+ tree_update.nodes[12].id = 13;
tree_update.nodes[12].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[13].id = 13;
+ tree_update.nodes[13].id = 14;
- tree_update.nodes[14].id = 14;
+ tree_update.nodes[14].id = 15;
AXTree tree(tree_update);
AXNode* root = tree.root();
// Test traversal
- // UnignoredChildren(root) = {4, 5, 13, 14, 11, 2, 3}
+ // UnignoredChildren(root) = {5, 6, 14, 15, 12, 3, 4}
AXNode::UnignoredChildIterator unignored_iterator =
root->UnignoredChildrenBegin();
- EXPECT_EQ(4, (*unignored_iterator).id());
-
- EXPECT_EQ(5, (*++unignored_iterator).id());
+ EXPECT_EQ(5, (*unignored_iterator).id());
- EXPECT_EQ(13, (*++unignored_iterator).id());
+ EXPECT_EQ(6, (*++unignored_iterator).id());
EXPECT_EQ(14, (*++unignored_iterator).id());
- EXPECT_EQ(13, (*--unignored_iterator).id());
+ EXPECT_EQ(15, (*++unignored_iterator).id());
- EXPECT_EQ(5, (*--unignored_iterator).id());
+ EXPECT_EQ(14, (*--unignored_iterator).id());
- EXPECT_EQ(13, (*++unignored_iterator).id());
+ EXPECT_EQ(6, (*--unignored_iterator).id());
EXPECT_EQ(14, (*++unignored_iterator).id());
- EXPECT_EQ(11, (*++unignored_iterator).id());
+ EXPECT_EQ(15, (*++unignored_iterator).id());
- EXPECT_EQ(2, (*++unignored_iterator).id());
+ EXPECT_EQ(12, (*++unignored_iterator).id());
EXPECT_EQ(3, (*++unignored_iterator).id());
+ EXPECT_EQ(4, (*++unignored_iterator).id());
+
EXPECT_EQ(root->UnignoredChildrenEnd(), ++unignored_iterator);
// test empty list
- // UnignoredChildren(2) = {}
- AXNode* node2 = tree.GetFromId(2);
- unignored_iterator = node2->UnignoredChildrenBegin();
- EXPECT_EQ(node2->UnignoredChildrenEnd(), unignored_iterator);
+ // UnignoredChildren(3) = {}
+ AXNode* node3 = tree.GetFromId(3);
+ unignored_iterator = node3->UnignoredChildrenBegin();
+ EXPECT_EQ(node3->UnignoredChildrenEnd(), unignored_iterator);
// empty list from ignored node with no children
- // UnignoredChildren(7) = {}
- AXNode* node7 = tree.GetFromId(7);
- unignored_iterator = node7->UnignoredChildrenBegin();
- EXPECT_EQ(node7->UnignoredChildrenEnd(), unignored_iterator);
+ // UnignoredChildren(8) = {}
+ AXNode* node8 = tree.GetFromId(8);
+ unignored_iterator = node8->UnignoredChildrenBegin();
+ EXPECT_EQ(node8->UnignoredChildrenEnd(), unignored_iterator);
// empty list from ignored node with unignored children
- // UnignoredChildren(10) = {}
- AXNode* node10 = tree.GetFromId(10);
- unignored_iterator = node10->UnignoredChildrenBegin();
- EXPECT_EQ(13, (*unignored_iterator).id());
+ // UnignoredChildren(11) = {}
+ AXNode* node11 = tree.GetFromId(11);
+ unignored_iterator = node11->UnignoredChildrenBegin();
+ EXPECT_EQ(14, (*unignored_iterator).id());
// Two UnignoredChildIterators from the same parent at the same position
// should be equivalent, even in end position.
@@ -1873,216 +1909,216 @@ TEST(AXTreeTest, UnignoredChildIterator) {
TEST(AXTreeTest, UnignoredAccessors) {
AXTreeUpdate tree_update;
// (i) => node is ignored
- // 0
+ // 1
// |__________
// | | |
- // 1(i) 2 3
+ // 2(i) 3 4
// |_______________________
// | | | |
- // 4 5 6(i) 7(i)
+ // 5 6 7(i) 8(i)
// | | |________
// | | | |
- // 8 9(i) 10(i) 11
+ // 9 10(i) 11(i) 12
// | |____
// | | |
- // 12(i) 13 14
+ // 13(i) 14 15
// | |
- // 15 16(i)
- tree_update.root_id = 0;
+ // 16 17
+ tree_update.root_id = 1;
tree_update.nodes.resize(17);
- tree_update.nodes[0].id = 0;
- tree_update.nodes[0].child_ids = {1, 2, 3};
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
- tree_update.nodes[1].id = 1;
- tree_update.nodes[1].child_ids = {4, 5, 6, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].child_ids = {5, 6, 7, 8};
tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[2].id = 2;
- tree_update.nodes[3].id = 3;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[3].id = 4;
- tree_update.nodes[4].id = 4;
- tree_update.nodes[4].child_ids = {8};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].child_ids = {9};
- tree_update.nodes[5].id = 5;
- tree_update.nodes[5].child_ids = {9};
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].child_ids = {10};
- tree_update.nodes[6].id = 6;
- tree_update.nodes[6].child_ids = {10, 11};
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].child_ids = {11, 12};
tree_update.nodes[6].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[7].id = 7;
+ tree_update.nodes[7].id = 8;
tree_update.nodes[7].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[8].id = 8;
+ tree_update.nodes[8].id = 9;
- tree_update.nodes[9].id = 9;
- tree_update.nodes[9].child_ids = {12};
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].child_ids = {13};
tree_update.nodes[9].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[10].id = 10;
- tree_update.nodes[10].child_ids = {13, 14};
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].child_ids = {14, 15};
tree_update.nodes[10].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[11].id = 11;
+ tree_update.nodes[11].id = 12;
- tree_update.nodes[12].id = 12;
- tree_update.nodes[12].child_ids = {15};
+ tree_update.nodes[12].id = 13;
+ tree_update.nodes[12].child_ids = {16};
tree_update.nodes[12].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[13].id = 13;
- tree_update.nodes[13].child_ids = {16};
+ tree_update.nodes[13].id = 14;
+ tree_update.nodes[13].child_ids = {17};
- tree_update.nodes[14].id = 14;
+ tree_update.nodes[14].id = 15;
- tree_update.nodes[15].id = 15;
+ tree_update.nodes[15].id = 16;
- tree_update.nodes[16].id = 16;
+ tree_update.nodes[16].id = 17;
tree_update.nodes[16].AddState(ax::mojom::State::kIgnored);
AXTree tree(tree_update);
- EXPECT_EQ(3, tree.GetFromId(0)->GetLastUnignoredChild()->id());
- EXPECT_EQ(11, tree.GetFromId(1)->GetLastUnignoredChild()->id());
- EXPECT_EQ(nullptr, tree.GetFromId(2)->GetLastUnignoredChild());
+ EXPECT_EQ(4, tree.GetFromId(1)->GetLastUnignoredChild()->id());
+ EXPECT_EQ(12, tree.GetFromId(2)->GetLastUnignoredChild()->id());
EXPECT_EQ(nullptr, tree.GetFromId(3)->GetLastUnignoredChild());
- EXPECT_EQ(8, tree.GetFromId(4)->GetLastUnignoredChild()->id());
- EXPECT_EQ(15, tree.GetFromId(5)->GetLastUnignoredChild()->id());
- EXPECT_EQ(11, tree.GetFromId(6)->GetLastUnignoredChild()->id());
- EXPECT_EQ(nullptr, tree.GetFromId(7)->GetLastUnignoredChild());
+ EXPECT_EQ(nullptr, tree.GetFromId(4)->GetLastUnignoredChild());
+ EXPECT_EQ(9, tree.GetFromId(5)->GetLastUnignoredChild()->id());
+ EXPECT_EQ(16, tree.GetFromId(6)->GetLastUnignoredChild()->id());
+ EXPECT_EQ(12, tree.GetFromId(7)->GetLastUnignoredChild()->id());
EXPECT_EQ(nullptr, tree.GetFromId(8)->GetLastUnignoredChild());
- EXPECT_EQ(15, tree.GetFromId(9)->GetLastUnignoredChild()->id());
- EXPECT_EQ(14, tree.GetFromId(10)->GetLastUnignoredChild()->id());
- EXPECT_EQ(nullptr, tree.GetFromId(11)->GetLastUnignoredChild());
- EXPECT_EQ(15, tree.GetFromId(12)->GetLastUnignoredChild()->id());
- EXPECT_EQ(nullptr, tree.GetFromId(13)->GetLastUnignoredChild());
+ EXPECT_EQ(nullptr, tree.GetFromId(9)->GetLastUnignoredChild());
+ EXPECT_EQ(16, tree.GetFromId(10)->GetLastUnignoredChild()->id());
+ EXPECT_EQ(15, tree.GetFromId(11)->GetLastUnignoredChild()->id());
+ EXPECT_EQ(nullptr, tree.GetFromId(12)->GetLastUnignoredChild());
+ EXPECT_EQ(16, tree.GetFromId(13)->GetLastUnignoredChild()->id());
EXPECT_EQ(nullptr, tree.GetFromId(14)->GetLastUnignoredChild());
EXPECT_EQ(nullptr, tree.GetFromId(15)->GetLastUnignoredChild());
EXPECT_EQ(nullptr, tree.GetFromId(16)->GetLastUnignoredChild());
+ EXPECT_EQ(nullptr, tree.GetFromId(17)->GetLastUnignoredChild());
}
TEST(AXTreeTest, UnignoredNextPreviousChild) {
AXTreeUpdate tree_update;
// (i) => node is ignored
- // 0
+ // 1
// |__________
// | | |
- // 1(i) 2 3
+ // 2(i) 3 4
// |_______________________
// | | | |
- // 4 5 6(i) 7(i)
+ // 5 6 7(i) 8(i)
// | | |________
// | | | |
- // 8 9(i) 10(i) 11
+ // 9 10(i) 11(i) 12
// | |____
// | | |
- // 12(i) 13 14
+ // 13(i) 14 15
// |
- // 15
- tree_update.root_id = 0;
+ // 16
+ tree_update.root_id = 1;
tree_update.nodes.resize(16);
- tree_update.nodes[0].id = 0;
- tree_update.nodes[0].child_ids = {1, 2, 3};
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
- tree_update.nodes[1].id = 1;
- tree_update.nodes[1].child_ids = {4, 5, 6, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].child_ids = {5, 6, 7, 8};
tree_update.nodes[1].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[2].id = 2;
- tree_update.nodes[3].id = 3;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[3].id = 4;
- tree_update.nodes[4].id = 4;
- tree_update.nodes[4].child_ids = {8};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].child_ids = {9};
- tree_update.nodes[5].id = 5;
- tree_update.nodes[5].child_ids = {9};
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].child_ids = {10};
- tree_update.nodes[6].id = 6;
- tree_update.nodes[6].child_ids = {10, 11};
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].child_ids = {11, 12};
tree_update.nodes[6].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[7].id = 7;
+ tree_update.nodes[7].id = 8;
tree_update.nodes[7].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[8].id = 8;
+ tree_update.nodes[8].id = 9;
- tree_update.nodes[9].id = 9;
- tree_update.nodes[9].child_ids = {12};
+ tree_update.nodes[9].id = 10;
+ tree_update.nodes[9].child_ids = {13};
tree_update.nodes[9].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[10].id = 10;
- tree_update.nodes[10].child_ids = {13, 14};
+ tree_update.nodes[10].id = 11;
+ tree_update.nodes[10].child_ids = {14, 15};
tree_update.nodes[10].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[11].id = 11;
+ tree_update.nodes[11].id = 12;
- tree_update.nodes[12].id = 12;
- tree_update.nodes[12].child_ids = {15};
+ tree_update.nodes[12].id = 13;
+ tree_update.nodes[12].child_ids = {16};
tree_update.nodes[12].AddState(ax::mojom::State::kIgnored);
- tree_update.nodes[13].id = 13;
+ tree_update.nodes[13].id = 14;
- tree_update.nodes[14].id = 14;
+ tree_update.nodes[14].id = 15;
- tree_update.nodes[15].id = 15;
+ tree_update.nodes[15].id = 16;
AXTree tree(tree_update);
- EXPECT_EQ(nullptr, tree.GetFromId(0)->GetNextUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(0)->GetPreviousUnignoredSibling());
-
- EXPECT_EQ(tree.GetFromId(2), tree.GetFromId(1)->GetNextUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(1)->GetNextUnignoredSibling());
EXPECT_EQ(nullptr, tree.GetFromId(1)->GetPreviousUnignoredSibling());
EXPECT_EQ(tree.GetFromId(3), tree.GetFromId(2)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(11),
- tree.GetFromId(2)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(2)->GetPreviousUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(3)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(2),
+ EXPECT_EQ(tree.GetFromId(4), tree.GetFromId(3)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(12),
tree.GetFromId(3)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(5), tree.GetFromId(4)->GetNextUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(4)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(4)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(3),
+ tree.GetFromId(4)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(13), tree.GetFromId(5)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(4),
- tree.GetFromId(5)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(6), tree.GetFromId(5)->GetNextUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(5)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(2), tree.GetFromId(6)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(14), tree.GetFromId(6)->GetNextUnignoredSibling());
EXPECT_EQ(tree.GetFromId(5),
tree.GetFromId(6)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(2), tree.GetFromId(7)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(11),
+ EXPECT_EQ(tree.GetFromId(3), tree.GetFromId(7)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(6),
tree.GetFromId(7)->GetPreviousUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(8)->GetNextUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(8)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(3), tree.GetFromId(8)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(12),
+ tree.GetFromId(8)->GetPreviousUnignoredSibling());
EXPECT_EQ(nullptr, tree.GetFromId(9)->GetNextUnignoredSibling());
EXPECT_EQ(nullptr, tree.GetFromId(9)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(11), tree.GetFromId(10)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(5),
- tree.GetFromId(10)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(10)->GetNextUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(10)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(2), tree.GetFromId(11)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(14),
+ EXPECT_EQ(tree.GetFromId(12), tree.GetFromId(11)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(6),
tree.GetFromId(11)->GetPreviousUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(12)->GetNextUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(12)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(3), tree.GetFromId(12)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(15),
+ tree.GetFromId(12)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(14), tree.GetFromId(13)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(5),
- tree.GetFromId(13)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(13)->GetNextUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(13)->GetPreviousUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(11), tree.GetFromId(14)->GetNextUnignoredSibling());
- EXPECT_EQ(tree.GetFromId(13),
+ EXPECT_EQ(tree.GetFromId(15), tree.GetFromId(14)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(6),
tree.GetFromId(14)->GetPreviousUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(15)->GetNextUnignoredSibling());
- EXPECT_EQ(nullptr, tree.GetFromId(15)->GetPreviousUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(12), tree.GetFromId(15)->GetNextUnignoredSibling());
+ EXPECT_EQ(tree.GetFromId(14),
+ tree.GetFromId(15)->GetPreviousUnignoredSibling());
+
+ EXPECT_EQ(nullptr, tree.GetFromId(16)->GetNextUnignoredSibling());
+ EXPECT_EQ(nullptr, tree.GetFromId(16)->GetPreviousUnignoredSibling());
}
TEST(AXTreeTest, UnignoredSelection) {
@@ -3196,20 +3232,78 @@ TEST(AXTreeTest, TestSetSizePosInSetSubtreeDeleted) {
initial_state.nodes[2].role = ax::mojom::Role::kTreeItem;
AXTree tree(initial_state);
- // This should work normally.
+ AXNode* tree_node = tree.GetFromId(1);
AXNode* item = tree.GetFromId(3);
+
+ // This should work normally.
EXPECT_OPTIONAL_EQ(2, item->GetPosInSet());
EXPECT_OPTIONAL_EQ(2, item->GetSetSize());
- // Use test observer to assert posinset and setsize are 0.
- TestAXTreeObserver test_observer(&tree);
- test_observer.call_posinset_and_setsize = true;
// Remove item from tree.
AXTreeUpdate tree_update = initial_state;
tree_update.nodes.resize(1);
tree_update.nodes[0].child_ids = {2};
ASSERT_TRUE(tree.Unserialize(tree_update));
+
+ // These values are lazily created, so to test that they fail when
+ // called in the middle of a tree update, fake the update state.
+ tree.SetTreeUpdateInProgressState(true);
+ ASSERT_FALSE(tree_node->GetPosInSet());
+ ASSERT_FALSE(tree_node->GetSetSize());
+
+ // Then reset the state to make sure we have the expected values
+ // after |Unserialize|.
+ tree.SetTreeUpdateInProgressState(false);
+ ASSERT_FALSE(tree_node->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(1, tree_node->GetSetSize());
+}
+
+// Tests that GetPosInSet and GetSetSize work when there are ignored nodes.
+TEST(AXTreeTest, TestSetSizePosInSetIgnoredItem) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(3);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kTree;
+ initial_state.nodes[0].child_ids = {2, 3};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kTreeItem;
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kTreeItem;
+ AXTree tree(initial_state);
+
+ AXNode* tree_node = tree.GetFromId(1);
+ AXNode* item1 = tree.GetFromId(2);
+ AXNode* item2 = tree.GetFromId(3);
+
+ // This should work normally.
+ ASSERT_FALSE(tree_node->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(2, tree_node->GetSetSize());
+
+ EXPECT_OPTIONAL_EQ(1, item1->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(2, item1->GetSetSize());
+
+ EXPECT_OPTIONAL_EQ(2, item2->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(2, item2->GetSetSize());
+
+ // Remove item from tree.
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(1);
+ tree_update.nodes[0] = initial_state.nodes[1];
+ tree_update.nodes[0].AddState(ax::mojom::State::kIgnored);
+
+ ASSERT_TRUE(tree.Unserialize(tree_update));
+
+ ASSERT_FALSE(tree_node->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(1, tree_node->GetSetSize());
+
+ // Ignored nodes are not part of ordered sets.
+ EXPECT_FALSE(item1->GetPosInSet());
+ EXPECT_FALSE(item1->GetSetSize());
+
+ EXPECT_OPTIONAL_EQ(1, item2->GetPosInSet());
+ EXPECT_OPTIONAL_EQ(1, item2->GetSetSize());
}
// Tests that kPopUpButtons are assigned the SetSize of the wrapped
@@ -3243,4 +3337,267 @@ TEST(AXTreeTest, TestSetSizePosInSetPopUpButton) {
EXPECT_OPTIONAL_EQ(2, popup_button_2->GetSetSize());
}
+TEST(AXTreeTest, OnNodeWillBeDeletedHasValidUnignoredParent) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(3);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ initial_state.nodes[0].child_ids = {2};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ initial_state.nodes[1].child_ids = {3};
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kGenericContainer;
+ AXTree tree(initial_state);
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(1);
+ // Remove child from node:2, and add State::kIgnored
+ tree_update.nodes[0] = initial_state.nodes[1];
+ tree_update.nodes[0].AddState(ax::mojom::State::kIgnored);
+ tree_update.nodes[0].child_ids.clear();
+
+ // Before node:3 is deleted, the unignored parent is node:2.
+ // Assert that this is the case in |OnNodeWillBeDeleted|.
+ TestAXTreeObserver test_observer(&tree);
+ test_observer.unignored_parent_id_before_node_deleted = 2;
+ ASSERT_TRUE(tree.Unserialize(tree_update));
+}
+
+// Tests a fringe scenario that may happen if multiple AXTreeUpdates are merged.
+// Make sure that we correctly Unserialize if a newly created node is deleted,
+// and possibly recreated later.
+TEST(AXTreeTest, SingleUpdateDeletesNewlyCreatedChildNode) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(1);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ AXTree tree(initial_state);
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(6);
+ // Add child node:2
+ tree_update.nodes[0] = initial_state.nodes[0];
+ tree_update.nodes[0].child_ids = {2};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ // Remove child node:2
+ tree_update.nodes[2] = initial_state.nodes[0];
+ // Add child node:2
+ tree_update.nodes[3] = initial_state.nodes[0];
+ tree_update.nodes[3].child_ids = {2};
+ tree_update.nodes[4].id = 2;
+ tree_update.nodes[4].role = ax::mojom::Role::kGenericContainer;
+ // Remove child node:2
+ tree_update.nodes[5] = initial_state.nodes[0];
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+
+ // Unserialize again, but with another add child.
+ tree_update.nodes.resize(8);
+ tree_update.nodes[6] = initial_state.nodes[0];
+ tree_update.nodes[6].child_ids = {2};
+ tree_update.nodes[7].id = 2;
+ tree_update.nodes[7].role = ax::mojom::Role::kGenericContainer;
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2\n"
+ " id=2 genericContainer (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+}
+
+// Tests a fringe scenario that may happen if multiple AXTreeUpdates are merged.
+// Make sure that we correctly Unserialize if a node is reparented multiple
+// times.
+TEST(AXTreeTest, SingleUpdateReparentsNodeMultipleTimes) {
+ // ++{kRootWebArea, 1}
+ // ++++{kList, 2}
+ // ++++++{kListItem, 4}
+ // ++++{kList, 3}
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ initial_state.nodes[0].child_ids = {2, 3};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kList;
+ initial_state.nodes[1].child_ids = {4};
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kList;
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kListItem;
+ AXTree tree(initial_state);
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(6);
+ // Remove child node:4
+ tree_update.nodes[0].id = 2;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ // Reparent child node:4 onto node:3
+ tree_update.nodes[1].id = 3;
+ tree_update.nodes[1].role = ax::mojom::Role::kList;
+ tree_update.nodes[1].child_ids = {4};
+ tree_update.nodes[2].id = 4;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ // Remove child ndoe:4
+ tree_update.nodes[3].id = 3;
+ tree_update.nodes[3].role = ax::mojom::Role::kList;
+ // Reparent child node:4 onto node:2
+ tree_update.nodes[4].id = 2;
+ tree_update.nodes[4].role = ax::mojom::Role::kList;
+ tree_update.nodes[4].child_ids = {4};
+ tree_update.nodes[5].id = 4;
+ tree_update.nodes[5].role = ax::mojom::Role::kListItem;
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+ EXPECT_EQ(
+ "AXTree\nid=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2,3\n"
+ " id=2 list (0, 0)-(0, 0) actions= child_ids=4\n"
+ " id=4 listItem (0, 0)-(0, 0) actions=\n"
+ " id=3 list (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+
+ // Unserialize again, but with another reparent.
+ tree_update.nodes.resize(9);
+ tree_update.nodes[6] = tree_update.nodes[0];
+ tree_update.nodes[7] = tree_update.nodes[1];
+ tree_update.nodes[8] = tree_update.nodes[2];
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+ EXPECT_EQ(
+ "AXTree\nid=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2,3\n"
+ " id=2 list (0, 0)-(0, 0) actions=\n"
+ " id=3 list (0, 0)-(0, 0) actions= child_ids=4\n"
+ " id=4 listItem (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+}
+
+// Tests a fringe scenario that may happen if multiple AXTreeUpdates are merged.
+// Make sure that we correctly Unserialize if a newly created node toggles its
+// ignored state.
+TEST(AXTreeTest, SingleUpdateIgnoresNewlyCreatedUnignoredChildNode) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(1);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ AXTree tree(initial_state);
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(3);
+ // Add child node:2
+ tree_update.nodes[0] = initial_state.nodes[0];
+ tree_update.nodes[0].child_ids = {2};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ // Add State::kIgnored to node:2
+ tree_update.nodes[2] = tree_update.nodes[1];
+ tree_update.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2\n"
+ " id=2 genericContainer IGNORED (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+}
+
+// Tests a fringe scenario that may happen if multiple AXTreeUpdates are merged.
+// Make sure that we correctly Unserialize if a newly created node toggles its
+// ignored state.
+TEST(AXTreeTest, SingleUpdateTogglesIgnoredStateAfterCreatingNode) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(1);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ AXTree tree(initial_state);
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(5);
+ // Add child node:2, node:3
+ tree_update.nodes[0] = initial_state.nodes[0];
+ tree_update.nodes[0].child_ids = {2, 3};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kGenericContainer;
+ tree_update.nodes[2].AddState(ax::mojom::State::kIgnored);
+ // Add State::kIgnored to node:2
+ tree_update.nodes[3] = tree_update.nodes[1];
+ tree_update.nodes[3].AddState(ax::mojom::State::kIgnored);
+ // Remove State::kIgnored from node:3
+ tree_update.nodes[4] = tree_update.nodes[2];
+ tree_update.nodes[4].RemoveState(ax::mojom::State::kIgnored);
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2,3\n"
+ " id=2 genericContainer IGNORED (0, 0)-(0, 0) actions=\n"
+ " id=3 genericContainer (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+}
+
+// Tests a fringe scenario that may happen if multiple AXTreeUpdates are merged.
+// Make sure that we correctly Unserialize if a node toggles its ignored state
+// and is then removed from the tree.
+TEST(AXTreeTest, SingleUpdateTogglesIgnoredStateBeforeDestroyingNode) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(3);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+ initial_state.nodes[0].child_ids = {2, 3};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kGenericContainer;
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kGenericContainer;
+ initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+ AXTree tree(initial_state);
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions= child_ids=2,3\n"
+ " id=2 genericContainer (0, 0)-(0, 0) actions=\n"
+ " id=3 genericContainer IGNORED (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+
+ AXTreeUpdate tree_update;
+ tree_update.nodes.resize(3);
+ // Add State::kIgnored to node:2
+ tree_update.nodes[0] = initial_state.nodes[1];
+ tree_update.nodes[0].AddState(ax::mojom::State::kIgnored);
+ // Remove State::kIgnored from node:3
+ tree_update.nodes[1] = initial_state.nodes[2];
+ tree_update.nodes[1].RemoveState(ax::mojom::State::kIgnored);
+ // Remove child node:2, node:3
+ tree_update.nodes[2] = initial_state.nodes[0];
+ tree_update.nodes[2].child_ids.clear();
+
+ ASSERT_TRUE(tree.Unserialize(tree_update)) << tree.error();
+
+ ASSERT_EQ(
+ "AXTree\n"
+ "id=1 rootWebArea (0, 0)-(0, 0) actions=\n",
+ tree.ToString());
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc b/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
index 1d35919796c..635e6f855e2 100644
--- a/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
@@ -52,18 +52,18 @@ TEST_F(AXFragmentRootTest, TestUIAGetRuntimeId) {
TEST_F(AXFragmentRootTest, TestUIAElementProviderFromPoint) {
AXNodeData root_data;
- root_data.id = 0;
- root_data.child_ids.push_back(1);
- root_data.child_ids.push_back(2);
+ root_data.id = 1;
root_data.relative_bounds.bounds = gfx::RectF(0, 0, 80, 80);
AXNodeData element1_data;
- element1_data.id = 1;
+ element1_data.id = 2;
element1_data.relative_bounds.bounds = gfx::RectF(0, 0, 50, 50);
+ root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
- element2_data.id = 2;
+ element2_data.id = 3;
element2_data.relative_bounds.bounds = gfx::RectF(0, 50, 30, 30);
+ root_data.child_ids.push_back(element2_data.id);
Init(root_data, element1_data, element2_data);
InitFragmentRoot();
@@ -96,15 +96,15 @@ TEST_F(AXFragmentRootTest, TestUIAElementProviderFromPoint) {
TEST_F(AXFragmentRootTest, TestUIAGetFocus) {
AXNodeData root_data;
- root_data.id = 0;
- root_data.child_ids.push_back(1);
- root_data.child_ids.push_back(2);
+ root_data.id = 1;
AXNodeData element1_data;
- element1_data.id = 1;
+ element1_data.id = 2;
+ root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
- element2_data.id = 2;
+ element2_data.id = 3;
+ root_data.child_ids.push_back(element2_data.id);
Init(root_data, element1_data, element2_data);
InitFragmentRoot();
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index ae0050a7dac..e9971bd618a 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -632,20 +632,20 @@ TEST_F(AXPlatformNodeAuraLinuxTest, DISABLED_TestAtkObjectIntAttributes) {
TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentRefAtPoint) {
AXNodeData root;
- root.id = 0;
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
+ root.id = 1;
root.relative_bounds.bounds = gfx::RectF(0, 0, 30, 30);
AXNodeData node1;
- node1.id = 1;
+ node1.id = 2;
node1.relative_bounds.bounds = gfx::RectF(0, 0, 10, 10);
node1.SetName("Name1");
+ root.child_ids.push_back(node1.id);
AXNodeData node2;
- node2.id = 2;
+ node2.id = 3;
node2.relative_bounds.bounds = gfx::RectF(20, 20, 10, 10);
node2.SetName("Name2");
+ root.child_ids.push_back(node2.id);
Init(root, node1, node2);
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
index 3560db35030..b8825da748f 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
@@ -26,33 +26,33 @@ class AXPlatformNodeTextChildProviderTest : public ui::AXPlatformNodeWinTest {
// nontext text text
void SetUp() override {
ui::AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData nontext_child_of_root;
- nontext_child_of_root.id = 1;
+ nontext_child_of_root.id = 2;
nontext_child_of_root.role = ax::mojom::Role::kGroup;
- root.child_ids.push_back(1);
+ root.child_ids.push_back(nontext_child_of_root.id);
ui::AXNodeData text_child_of_root;
- text_child_of_root.id = 2;
+ text_child_of_root.id = 3;
text_child_of_root.role = ax::mojom::Role::kStaticText;
- root.child_ids.push_back(2);
+ root.child_ids.push_back(text_child_of_root.id);
ui::AXNodeData nontext_child_of_nontext;
- nontext_child_of_nontext.id = 3;
+ nontext_child_of_nontext.id = 4;
nontext_child_of_nontext.role = ax::mojom::Role::kGroup;
- nontext_child_of_root.child_ids.push_back(3);
+ nontext_child_of_root.child_ids.push_back(nontext_child_of_nontext.id);
ui::AXNodeData text_child_of_nontext;
- text_child_of_nontext.id = 4;
+ text_child_of_nontext.id = 5;
text_child_of_nontext.role = ax::mojom::Role::kStaticText;
- nontext_child_of_root.child_ids.push_back(4);
+ nontext_child_of_root.child_ids.push_back(text_child_of_nontext.id);
ui::AXNodeData text_child_of_text;
- text_child_of_text.id = 5;
+ text_child_of_text.id = 6;
text_child_of_text.role = ax::mojom::Role::kStaticText;
- text_child_of_root.child_ids.push_back(5);
+ text_child_of_root.child_ids.push_back(text_child_of_text.id);
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index c854497c1f1..706563f81f2 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -2292,15 +2292,15 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderMoveEndpointByUnitTextField) {
ui::AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData group1_data;
- group1_data.id = 1;
+ group1_data.id = 2;
group1_data.role = ax::mojom::Role::kGenericContainer;
ui::AXNodeData text_data;
- text_data.id = 2;
+ text_data.id = 3;
text_data.role = ax::mojom::Role::kStaticText;
std::string text_content = "some text";
text_data.SetName(text_content);
@@ -2313,15 +2313,15 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
word_end_offsets);
ui::AXNodeData text_input_data;
- text_input_data.id = 3;
+ text_input_data.id = 4;
text_input_data.role = ax::mojom::Role::kTextField;
ui::AXNodeData group2_data;
- group2_data.id = 4;
+ group2_data.id = 5;
group2_data.role = ax::mojom::Role::kGenericContainer;
ui::AXNodeData more_text_data;
- more_text_data.id = 5;
+ more_text_data.id = 6;
more_text_data.role = ax::mojom::Role::kStaticText;
text_content = "more text";
more_text_data.SetName(text_content);
@@ -2333,7 +2333,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
word_end_offsets);
ui::AXNodeData empty_text_data;
- empty_text_data.id = 6;
+ empty_text_data.id = 7;
empty_text_data.role = ax::mojom::Role::kStaticText;
text_content = "";
empty_text_data.SetName(text_content);
@@ -2344,10 +2344,10 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
empty_text_data.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
word_end_offsets);
- root_data.child_ids = {1, 3, 4};
- group1_data.child_ids = {2};
- text_input_data.child_ids = {6};
- group2_data.child_ids = {5};
+ root_data.child_ids = {group1_data.id, text_input_data.id, group2_data.id};
+ group1_data.child_ids = {text_data.id};
+ text_input_data.child_ids = {empty_text_data.id};
+ group2_data.child_ids = {more_text_data.id};
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
@@ -2839,28 +2839,28 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
// | |
// text_node3 text_node4
ui::AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData text_node1;
- text_node1.id = 1;
+ text_node1.id = 2;
text_node1.role = ax::mojom::Role::kStaticText;
- root_data.child_ids.push_back(1);
+ root_data.child_ids.push_back(text_node1.id);
ui::AXNodeData text_node2;
- text_node2.id = 2;
+ text_node2.id = 3;
text_node2.role = ax::mojom::Role::kStaticText;
- root_data.child_ids.push_back(2);
+ root_data.child_ids.push_back(text_node2.id);
ui::AXNodeData text_node3;
- text_node3.id = 3;
+ text_node3.id = 4;
text_node3.role = ax::mojom::Role::kStaticText;
- text_node1.child_ids.push_back(3);
+ text_node1.child_ids.push_back(text_node3.id);
ui::AXNodeData text_node4;
- text_node4.id = 4;
+ text_node4.id = 5;
text_node4.role = ax::mojom::Role::kStaticText;
- text_node1.child_ids.push_back(4);
+ text_node1.child_ids.push_back(text_node4.id);
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
@@ -3261,19 +3261,20 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderGetAttributeValueNotSupported) {
ui::AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
- root_data.child_ids = {1, 2};
ui::AXNodeData text_data_first;
- text_data_first.id = 1;
+ text_data_first.id = 2;
text_data_first.role = ax::mojom::Role::kStaticText;
text_data_first.SetName("first");
+ root_data.child_ids.push_back(text_data_first.id);
ui::AXNodeData text_data_second;
- text_data_second.id = 2;
+ text_data_second.id = 3;
text_data_second.role = ax::mojom::Role::kStaticText;
text_data_second.SetName("second");
+ root_data.child_ids.push_back(text_data_second.id);
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
@@ -4028,7 +4029,7 @@ TEST_F(AXPlatformNodeTextRangeProviderTest,
TEST_F(AXPlatformNodeTextRangeProviderTest, ElementNotAvailable) {
AXNodeData root_ax_node_data;
- root_ax_node_data.id = 0;
+ root_ax_node_data.id = 1;
root_ax_node_data.role = ax::mojom::Role::kRootWebArea;
Init(root_ax_node_data);
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
index 9409c8acf33..6f6562729af 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc
@@ -200,14 +200,14 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() {
*/
AXNodeData table;
- table.id = 0;
+ table.id = 1;
table.role = ax::mojom::Role::kTable;
table.AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount, 3);
table.AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, 3);
table.child_ids.push_back(50); // Header
- table.child_ids.push_back(1); // Row 1
+ table.child_ids.push_back(2); // Row 1
table.child_ids.push_back(10); // Row 2
// Table column header
@@ -249,44 +249,41 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() {
// Row 1
AXNodeData table_row_1;
- table_row_1.id = 1;
+ table_row_1.id = 2;
table_row_1.role = ax::mojom::Role::kRow;
- table_row_1.child_ids.push_back(2);
- table_row_1.child_ids.push_back(3);
- table_row_1.child_ids.push_back(4);
AXNodeData table_row_header_1;
- table_row_header_1.id = 2;
+ table_row_header_1.id = 3;
table_row_header_1.role = ax::mojom::Role::kRowHeader;
table_row_header_1.SetName("row header 1");
table_row_header_1.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellRowIndex, 1);
table_row_header_1.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellColumnIndex, 0);
+ table_row_1.child_ids.push_back(table_row_header_1.id);
AXNodeData table_cell_1;
- table_cell_1.id = 3;
+ table_cell_1.id = 4;
table_cell_1.role = ax::mojom::Role::kCell;
table_cell_1.SetName("1");
table_cell_1.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, 1);
table_cell_1.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
1);
+ table_row_1.child_ids.push_back(table_cell_1.id);
AXNodeData table_cell_2;
- table_cell_2.id = 4;
+ table_cell_2.id = 5;
table_cell_2.role = ax::mojom::Role::kCell;
table_cell_2.SetName("2");
table_cell_2.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, 1);
table_cell_2.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
2);
+ table_row_1.child_ids.push_back(table_cell_2.id);
// Row 2
AXNodeData table_row_2;
table_row_2.id = 10;
table_row_2.role = ax::mojom::Role::kRow;
- table_row_2.child_ids.push_back(11);
- table_row_2.child_ids.push_back(12);
- table_row_2.child_ids.push_back(13);
AXNodeData table_row_header_2;
table_row_header_2.id = 11;
@@ -299,6 +296,7 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() {
ax::mojom::IntAttribute::kTableCellRowIndex, 2);
table_row_header_2.AddIntAttribute(
ax::mojom::IntAttribute::kTableCellColumnIndex, 0);
+ table_row_2.child_ids.push_back(table_row_header_2.id);
AXNodeData table_cell_3;
table_cell_3.id = 12;
@@ -307,6 +305,7 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() {
table_cell_3.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, 2);
table_cell_3.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
1);
+ table_row_2.child_ids.push_back(table_cell_3.id);
AXNodeData table_cell_4;
table_cell_4.id = 13;
@@ -315,6 +314,7 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() {
table_cell_4.AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, 2);
table_cell_4.AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex,
2);
+ table_row_2.child_ids.push_back(table_cell_4.id);
AXTreeUpdate update;
update.root_id = table.id;
@@ -411,14 +411,14 @@ AXTreeUpdate AXPlatformNodeTest::BuildListBox(
bool option_3_is_selected,
ax::mojom::State additional_state /* ax::mojom::State::kNone */) {
AXNodeData listbox;
- listbox.id = 0;
+ listbox.id = 1;
listbox.SetName("ListBox");
listbox.role = ax::mojom::Role::kListBox;
if (additional_state != ax::mojom::State::kNone)
listbox.AddState(additional_state);
AXNodeData option_1;
- option_1.id = 1;
+ option_1.id = 2;
option_1.SetName("Option1");
option_1.role = ax::mojom::Role::kListBoxOption;
if (option_1_is_selected)
@@ -426,7 +426,7 @@ AXTreeUpdate AXPlatformNodeTest::BuildListBox(
listbox.child_ids.push_back(option_1.id);
AXNodeData option_2;
- option_2.id = 2;
+ option_2.id = 3;
option_2.SetName("Option2");
option_2.role = ax::mojom::Role::kListBoxOption;
if (option_2_is_selected)
@@ -434,7 +434,7 @@ AXTreeUpdate AXPlatformNodeTest::BuildListBox(
listbox.child_ids.push_back(option_2.id);
AXNodeData option_3;
- option_3.id = 3;
+ option_3.id = 4;
option_3.SetName("Option3");
option_3.role = ax::mojom::Role::kListBoxOption;
if (option_3_is_selected)
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index 46c7c431201..a47f1070c5c 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1115,9 +1115,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accState(VARIANT var_id, VARIANT* state) {
IFACEMETHODIMP AXPlatformNodeWin::get_accHelp(VARIANT var_id, BSTR* help) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ACC_HELP);
- AXPlatformNodeWin* target;
- COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, help, target);
- return target->GetHelpText(help);
+ COM_OBJECT_VALIDATE_1_ARG(help);
+ return S_FALSE;
}
IFACEMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) {
@@ -3827,8 +3826,20 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPropertyValue(PROPERTYID property_id,
break;
case UIA_HelpTextPropertyId:
- V_VT(result) = VT_BSTR;
- GetHelpText(&V_BSTR(result));
+ if (HasStringAttribute(ax::mojom::StringAttribute::kPlaceholder)) {
+ V_VT(result) = VT_BSTR;
+ GetStringAttributeAsBstr(ax::mojom::StringAttribute::kPlaceholder,
+ &V_BSTR(result));
+ } else if (data.GetNameFrom() == ax::mojom::NameFrom::kPlaceholder ||
+ data.GetNameFrom() == ax::mojom::NameFrom::kTitle) {
+ V_VT(result) = VT_BSTR;
+ GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName,
+ &V_BSTR(result));
+ } else if (HasStringAttribute(ax::mojom::StringAttribute::kTooltip)) {
+ V_VT(result) = VT_BSTR;
+ GetStringAttributeAsBstr(ax::mojom::StringAttribute::kTooltip,
+ &V_BSTR(result));
+ }
break;
case UIA_IsContentElementPropertyId:
@@ -6911,21 +6922,6 @@ HRESULT AXPlatformNodeWin::AllocateComArrayFromVector(
return S_OK;
}
-HRESULT AXPlatformNodeWin::GetHelpText(BSTR* helpText) {
- if (HasStringAttribute(ax::mojom::StringAttribute::kPlaceholder)) {
- return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kPlaceholder,
- helpText);
- } else if (GetData().GetNameFrom() == ax::mojom::NameFrom::kPlaceholder ||
- GetData().GetNameFrom() == ax::mojom::NameFrom::kTitle) {
- return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName,
- helpText);
- } else if (HasStringAttribute(ax::mojom::StringAttribute::kTooltip)) {
- return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kTooltip,
- helpText);
- }
- return S_FALSE;
-}
-
// TODO(dmazzoni): Remove this function once combo box refactoring is
// complete.
bool AXPlatformNodeWin::IsAncestorComboBox() {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h
index 2dfbbbc414f..518143a76e9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h
@@ -1234,9 +1234,6 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
// Helper method for mutating the ISelectionItemProvider selected state
HRESULT ISelectionItemProviderSetSelected(bool selected);
- // Helper method for getting the help text property.
- HRESULT GetHelpText(BSTR* helpText);
-
//
// Getters for UIA GetTextAttributeValue
//
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 5c4d87aa356..ee082da074b 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -439,20 +439,20 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleDetachedObject) {
TEST_F(AXPlatformNodeWinTest, TestIAccessibleHitTest) {
AXNodeData root;
- root.id = 0;
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
+ root.id = 1;
root.relative_bounds.bounds = gfx::RectF(0, 0, 30, 30);
AXNodeData node1;
- node1.id = 1;
+ node1.id = 2;
node1.relative_bounds.bounds = gfx::RectF(0, 0, 10, 10);
node1.SetName("Name1");
+ root.child_ids.push_back(node1.id);
AXNodeData node2;
- node2.id = 2;
+ node2.id = 3;
node2.relative_bounds.bounds = gfx::RectF(20, 20, 10, 10);
node2.SetName("Name2");
+ root.child_ids.push_back(node2.id);
Init(root, node1, node2);
@@ -542,114 +542,19 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleShortcut) {
root_obj->get_accKeyboardShortcut(bad_id, k2.Receive()));
}
-TEST_F(AXPlatformNodeWinTest, TestIAccessibleHelpText) {
- AXNodeData root;
- root.id = 0;
-
- // Test Placeholder StringAttribute is exposed.
- AXNodeData node1;
- node1.id = 1;
- node1.SetName("name-from-title");
- node1.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int>(ax::mojom::NameFrom::kTitle));
- node1.AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder,
- "placeholder");
- root.child_ids.push_back(node1.id);
-
- // Test NameFrom Title is exposed.
- AXNodeData node2;
- node2.id = 2;
- node2.SetName("name-from-title");
- node2.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int>(ax::mojom::NameFrom::kTitle));
- root.child_ids.push_back(node2.id);
-
- // Test NameFrom Placeholder is exposed.
- AXNodeData node3;
- node3.id = 3;
- node3.SetName("name-from-placeholder");
- node3.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int>(ax::mojom::NameFrom::kPlaceholder));
- root.child_ids.push_back(node3.id);
-
- // Test Tooltip StringAttribute is exposed.
- AXNodeData node4;
- node4.id = 4;
- node4.SetName("name-from-attribute");
- node4.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int>(ax::mojom::NameFrom::kAttribute));
- node4.AddStringAttribute(ax::mojom::StringAttribute::kTooltip, "tooltip");
- root.child_ids.push_back(node4.id);
-
- // Test StringAttribute is not exposed without explicit
- // Placeholder / Title / Tooltip.
- AXNodeData node5;
- node5.id = 5;
- node5.SetName("name-from-attribute");
- node5.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int>(ax::mojom::NameFrom::kAttribute));
- root.child_ids.push_back(node5.id);
-
- Init(root, node1, node2, node3, node4, node5);
-
- auto* root_node = GetRootNode();
-
- ScopedBstr helpText1;
- ComPtr<IAccessible> child_node1(
- IAccessibleFromNode(root_node->children()[0]));
- EXPECT_EQ(S_OK, child_node1->get_accHelp(SELF, helpText1.Receive()));
- EXPECT_STREQ(L"placeholder", helpText1);
-
- ScopedBstr helpText2;
- ComPtr<IAccessible> child_node2(
- IAccessibleFromNode(root_node->children()[1]));
- EXPECT_EQ(S_OK, child_node2->get_accHelp(SELF, helpText2.Receive()));
- EXPECT_STREQ(L"name-from-title", helpText2);
-
- ScopedBstr helpText3;
- ComPtr<IAccessible> child_node3(
- IAccessibleFromNode(root_node->children()[2]));
- EXPECT_EQ(S_OK, child_node3->get_accHelp(SELF, helpText3.Receive()));
- EXPECT_STREQ(L"name-from-placeholder", helpText3);
-
- ScopedBstr helpText4;
- ComPtr<IAccessible> child_node4(
- IAccessibleFromNode(root_node->children()[3]));
- EXPECT_EQ(S_OK, child_node4->get_accHelp(SELF, helpText4.Receive()));
- EXPECT_STREQ(L"tooltip", helpText4);
-
- ScopedBstr helpText5;
- ComPtr<IAccessible> child_node5(
- IAccessibleFromNode(root_node->children()[4]));
- EXPECT_EQ(S_FALSE, child_node5->get_accHelp(SELF, helpText5.Receive()));
-
- ScopedBstr helpText6;
- ScopedVariant root_id(0);
- EXPECT_EQ(S_OK, child_node4->get_accHelp(root_id, helpText6.Receive()));
- EXPECT_STREQ(L"tooltip", helpText6);
-
- EXPECT_EQ(E_INVALIDARG, child_node5->get_accHelp(SELF, nullptr));
- ScopedVariant var_id(5);
- EXPECT_EQ(E_INVALIDARG,
- child_node5->get_accHelp(var_id, helpText5.Receive()));
- ScopedVariant bad_id(999);
- EXPECT_EQ(E_INVALIDARG,
- child_node5->get_accHelp(bad_id, helpText5.Receive()));
-}
-
TEST_F(AXPlatformNodeWinTest,
TestIAccessibleSelectionListBoxOptionNothingSelected) {
AXNodeData list;
- list.id = 0;
+ list.id = 1;
list.role = ax::mojom::Role::kListBox;
AXNodeData list_item_1;
- list_item_1.id = 1;
+ list_item_1.id = 2;
list_item_1.role = ax::mojom::Role::kListBoxOption;
list_item_1.SetName("Name1");
AXNodeData list_item_2;
- list_item_2.id = 2;
+ list_item_2.id = 3;
list_item_2.role = ax::mojom::Role::kListBoxOption;
list_item_2.SetName("Name2");
@@ -669,17 +574,17 @@ TEST_F(AXPlatformNodeWinTest,
TEST_F(AXPlatformNodeWinTest,
TestIAccessibleSelectionListBoxOptionOneSelected) {
AXNodeData list;
- list.id = 0;
+ list.id = 1;
list.role = ax::mojom::Role::kListBox;
AXNodeData list_item_1;
- list_item_1.id = 1;
+ list_item_1.id = 2;
list_item_1.role = ax::mojom::Role::kListBoxOption;
list_item_1.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_1.SetName("Name1");
AXNodeData list_item_2;
- list_item_2.id = 2;
+ list_item_2.id = 3;
list_item_2.role = ax::mojom::Role::kListBoxOption;
list_item_2.SetName("Name2");
@@ -701,23 +606,23 @@ TEST_F(AXPlatformNodeWinTest,
TEST_F(AXPlatformNodeWinTest,
TestIAccessibleSelectionListBoxOptionMultipleSelected) {
AXNodeData list;
- list.id = 0;
+ list.id = 1;
list.role = ax::mojom::Role::kListBox;
AXNodeData list_item_1;
- list_item_1.id = 1;
+ list_item_1.id = 2;
list_item_1.role = ax::mojom::Role::kListBoxOption;
list_item_1.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_1.SetName("Name1");
AXNodeData list_item_2;
- list_item_2.id = 2;
+ list_item_2.id = 3;
list_item_2.role = ax::mojom::Role::kListBoxOption;
list_item_2.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
list_item_2.SetName("Name2");
AXNodeData list_item_3;
- list_item_3.id = 3;
+ list_item_3.id = 4;
list_item_3.role = ax::mojom::Role::kListBoxOption;
list_item_3.SetName("Name3");
@@ -2937,14 +2842,14 @@ TEST_F(AXPlatformNodeWinTest, TestAnnotatedImageName) {
TEST_F(AXPlatformNodeWinTest, TestIAccessibleTextGetNCharacters) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kStaticText;
- root.child_ids.push_back(1);
AXNodeData node;
- node.id = 1;
+ node.id = 2;
node.role = ax::mojom::Role::kStaticText;
node.SetName("Name");
+ root.child_ids.push_back(node.id);
Init(root, node);
@@ -3590,15 +3495,15 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertySimple) {
"role description");
root.AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 2);
root.AddIntAttribute(ax::mojom::IntAttribute::kInvalidState, 1);
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kList;
AXNodeData child1;
- child1.id = 1;
+ child1.id = 2;
child1.role = ax::mojom::Role::kListItem;
child1.AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 1);
child1.SetName("child1");
- root.child_ids.push_back(1);
+ root.child_ids.push_back(child1.id);
Init(root, child1);
@@ -3643,7 +3548,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertySimple) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueClickablePoint) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kButton;
root.relative_bounds.bounds = gfx::RectF(20, 30, 100, 200);
Init(root);
@@ -3660,7 +3565,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueClickablePoint) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValue_Histogram) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
Init(root);
ComPtr<IRawElementProviderSimple> root_node =
GetRootIRawElementProviderSimple();
@@ -3734,26 +3639,26 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetControllerForPropertyId) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetDescribedByPropertyId) {
AXNodeData root;
- std::vector<int32_t> describedby_ids = {1, 2, 3};
+ std::vector<int32_t> describedby_ids = {2, 3, 4};
root.AddIntListAttribute(ax::mojom::IntListAttribute::kDescribedbyIds,
describedby_ids);
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kMarquee;
root.SetName("root");
AXNodeData child1;
- child1.id = 1;
+ child1.id = 2;
child1.role = ax::mojom::Role::kStaticText;
child1.SetName("child1");
- root.child_ids.push_back(1);
+ root.child_ids.push_back(child1.id);
AXNodeData child2;
- child2.id = 2;
+ child2.id = 3;
child2.role = ax::mojom::Role::kStaticText;
child2.SetName("child2");
- root.child_ids.push_back(2);
+ root.child_ids.push_back(child2.id);
Init(root, child1, child2);
@@ -3835,25 +3740,25 @@ TEST_F(AXPlatformNodeWinTest, TestUIAItemStatusPropertyId) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetFlowsToPropertyId) {
AXNodeData root;
- std::vector<int32_t> flowto_ids = {1, 2, 3};
+ std::vector<int32_t> flowto_ids = {2, 3, 4};
root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, flowto_ids);
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kMarquee;
root.SetName("root");
AXNodeData child1;
- child1.id = 1;
+ child1.id = 2;
child1.role = ax::mojom::Role::kStaticText;
child1.SetName("child1");
- root.child_ids.push_back(1);
+ root.child_ids.push_back(child1.id);
AXNodeData child2;
- child2.id = 2;
+ child2.id = 3;
child2.role = ax::mojom::Role::kStaticText;
child2.SetName("child2");
- root.child_ids.push_back(2);
+ root.child_ids.push_back(child2.id);
Init(root, child1, child2);
@@ -3866,7 +3771,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetFlowsToPropertyId) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromNone) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("root");
@@ -3884,16 +3789,16 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromNone) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromSingle) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("root");
- root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {1});
+ root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {2});
AXNodeData child1;
- child1.id = 1;
+ child1.id = 2;
child1.role = ax::mojom::Role::kGenericContainer;
child1.SetName("child1");
- root.child_ids.push_back(1);
+ root.child_ids.push_back(child1.id);
Init(root, child1);
ASSERT_NE(nullptr,
@@ -3909,23 +3814,23 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromSingle) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromMultiple) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.SetName("root");
- root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {1, 2});
+ root.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {2, 3});
AXNodeData child1;
- child1.id = 1;
+ child1.id = 2;
child1.role = ax::mojom::Role::kGenericContainer;
child1.SetName("child1");
- child1.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {2});
- root.child_ids.push_back(1);
+ child1.AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, {3});
+ root.child_ids.push_back(child1.id);
AXNodeData child2;
- child2.id = 2;
+ child2.id = 3;
child2.role = ax::mojom::Role::kGenericContainer;
child2.SetName("child2");
- root.child_ids.push_back(2);
+ root.child_ids.push_back(child2.id);
Init(root, child1, child2);
ASSERT_NE(nullptr,
@@ -3953,7 +3858,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFlowsFromMultiple) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetPropertyValueFrameworkId) {
AXNodeData root_ax_node_data;
- root_ax_node_data.id = 0;
+ root_ax_node_data.id = 1;
root_ax_node_data.role = ax::mojom::Role::kRootWebArea;
Init(root_ax_node_data);
@@ -4105,7 +4010,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetHostRawElementProvider) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetBoundingRectangle) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.relative_bounds.bounds = gfx::RectF(10, 20, 30, 50);
Init(root_data);
@@ -4125,11 +4030,11 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetFragmentRoot) {
// This test needs to be run on a child node since AXPlatformRootNodeWin
// overrides the method.
AXNodeData root_data;
- root_data.id = 0;
- root_data.child_ids.push_back(1);
+ root_data.id = 1;
AXNodeData element1_data;
- element1_data.id = 1;
+ element1_data.id = 2;
+ root_data.child_ids.push_back(element1_data.id);
Init(root_data, element1_data);
InitFragmentRoot();
@@ -4163,7 +4068,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetFragmentRoot) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetEmbeddedFragmentRoots) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
Init(root_data);
ComPtr<IRawElementProviderFragment> root_provider =
@@ -4177,7 +4082,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetEmbeddedFragmentRoots) {
TEST_F(AXPlatformNodeWinTest, TestUIAGetRuntimeId) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
Init(root_data);
ComPtr<IRawElementProviderFragment> root_provider =
@@ -4207,7 +4112,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAGetRuntimeId) {
TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalUnset) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
Init(root);
@@ -4221,7 +4126,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalUnset) {
TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalFalse) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, false);
Init(root);
@@ -4240,7 +4145,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalFalse) {
TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalTrue) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
Init(root);
@@ -4259,7 +4164,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderGetIsModalTrue) {
TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderInvalidArgument) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
Init(root);
@@ -4282,7 +4187,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderInvalidArgument) {
TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderNotSupported) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
Init(root);
@@ -4320,19 +4225,19 @@ TEST_F(AXPlatformNodeWinTest, TestUIAIWindowProviderNotSupported) {
TEST_F(AXPlatformNodeWinTest, TestUIANavigate) {
AXNodeData root_data;
- root_data.id = 0;
- root_data.child_ids.push_back(1);
- root_data.child_ids.push_back(2);
+ root_data.id = 1;
AXNodeData element1_data;
- element1_data.id = 1;
- element1_data.child_ids.push_back(3);
+ element1_data.id = 2;
+ root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
- element2_data.id = 2;
+ element2_data.id = 3;
+ root_data.child_ids.push_back(element2_data.id);
AXNodeData element3_data;
- element3_data.id = 3;
+ element3_data.id = 4;
+ element1_data.child_ids.push_back(element3_data.id);
Init(root_data, element1_data, element2_data, element3_data);
@@ -4544,29 +4449,29 @@ TEST_F(AXPlatformNodeWinTest,
TEST_F(AXPlatformNodeWinTest, TestComputeUIAControlType) {
AXNodeData root;
- root.id = 0;
+ root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
AXNodeData child1;
- int32_t child1_id = 1;
+ int32_t child1_id = 2;
child1.id = child1_id;
child1.role = ax::mojom::Role::kTable;
root.child_ids.push_back(child1_id);
AXNodeData child2;
- int32_t child2_id = 2;
+ int32_t child2_id = 3;
child2.id = child2_id;
child2.role = ax::mojom::Role::kLayoutTable;
root.child_ids.push_back(child2_id);
AXNodeData child3;
- int32_t child3_id = 3;
+ int32_t child3_id = 4;
child3.id = child3_id;
child3.role = ax::mojom::Role::kTextField;
root.child_ids.push_back(child3_id);
AXNodeData child4;
- int32_t child4_id = 4;
+ int32_t child4_id = 5;
child4.id = child4_id;
child4.role = ax::mojom::Role::kSearchBox;
root.child_ids.push_back(child4_id);
@@ -4592,7 +4497,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIALandmarkType) {
base::Optional<LONG> expected_landmark_type,
const std::string& node_name = {}) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = node_role;
if (!node_name.empty())
root_data.SetName(node_name);
@@ -4634,7 +4539,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIALocalizedLandmarkType) {
const std::wstring& expected_localized_landmark,
const std::string& node_name = {}) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
root_data.role = node_role;
if (!node_name.empty())
root_data.SetName(node_name);
@@ -4673,15 +4578,15 @@ TEST_F(AXPlatformNodeWinTest, TestUIALocalizedLandmarkType) {
TEST_F(AXPlatformNodeWinTest, TestIRawElementProviderSimple2ShowContextMenu) {
AXNodeData root_data;
- root_data.id = 0;
+ root_data.id = 1;
AXNodeData element1_data;
- element1_data.id = 1;
- root_data.child_ids.push_back(1);
+ element1_data.id = 2;
+ root_data.child_ids.push_back(element1_data.id);
AXNodeData element2_data;
- element2_data.id = 2;
- root_data.child_ids.push_back(2);
+ element2_data.id = 3;
+ root_data.child_ids.push_back(element2_data.id);
Init(root_data, element1_data, element2_data);
@@ -4922,36 +4827,36 @@ TEST_F(AXPlatformNodeWinTest, TestUIAErrorHandling) {
TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderSupportedPatterns) {
ui::AXNodeData root;
- int32_t root_id = 0;
+ int32_t root_id = 1;
root.id = root_id;
root.role = ax::mojom::Role::kRootWebArea;
ui::AXNodeData text_field_with_combo_box;
- int32_t text_field_with_combo_box_id = 1;
+ int32_t text_field_with_combo_box_id = 2;
text_field_with_combo_box.id = text_field_with_combo_box_id;
text_field_with_combo_box.role = ax::mojom::Role::kTextFieldWithComboBox;
root.child_ids.push_back(text_field_with_combo_box_id);
ui::AXNodeData table;
- int32_t table_id = 2;
+ int32_t table_id = 3;
table.id = table_id;
table.role = ax::mojom::Role::kTable;
root.child_ids.push_back(table_id);
ui::AXNodeData table_cell;
- int32_t table_cell_id = 3;
+ int32_t table_cell_id = 4;
table_cell.id = table_cell_id;
table_cell.role = ax::mojom::Role::kCell;
table.child_ids.push_back(table_cell_id);
ui::AXNodeData meter;
- int32_t meter_id = 4;
+ int32_t meter_id = 5;
meter.id = meter_id;
meter.role = ax::mojom::Role::kMeter;
root.child_ids.push_back(meter_id);
ui::AXNodeData group_with_scroll;
- int32_t group_with_scroll_id = 5;
+ int32_t group_with_scroll_id = 6;
group_with_scroll.id = group_with_scroll_id;
group_with_scroll.role = ax::mojom::Role::kGroup;
group_with_scroll.AddIntAttribute(ax::mojom::IntAttribute::kScrollXMin, 10);
@@ -4960,25 +4865,25 @@ TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderSupportedPatterns) {
root.child_ids.push_back(group_with_scroll_id);
ui::AXNodeData grid;
- int32_t grid_id = 6;
+ int32_t grid_id = 7;
grid.id = grid_id;
grid.role = ax::mojom::Role::kGrid;
root.child_ids.push_back(grid_id);
ui::AXNodeData grid_cell;
- int32_t grid_cell_id = 7;
+ int32_t grid_cell_id = 8;
grid_cell.id = grid_cell_id;
grid_cell.role = ax::mojom::Role::kCell;
grid.child_ids.push_back(grid_cell_id);
ui::AXNodeData checkbox;
- int32_t checkbox_id = 8;
+ int32_t checkbox_id = 9;
checkbox.id = checkbox_id;
checkbox.role = ax::mojom::Role::kCheckBox;
root.child_ids.push_back(checkbox_id);
ui::AXNodeData link;
- int32_t link_id = 9;
+ int32_t link_id = 10;
link.id = link_id;
link.role = ax::mojom::Role::kLink;
root.child_ids.push_back(link_id);
@@ -5031,7 +4936,7 @@ TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderSupportedPatterns) {
TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderExpandCollapsePattern) {
ui::AXNodeData root;
- root.id = 0;
+ root.id = 1;
ui::AXNodeData list_box;
ui::AXNodeData list_item;
@@ -5043,25 +4948,25 @@ TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderExpandCollapsePattern) {
ui::AXNodeData disclosure_triangle;
ui::AXNodeData text_field_with_combo_box;
- list_box.id = 1;
- list_item.id = 2;
- menu_item.id = 3;
- menu_list_option.id = 4;
- tree_item.id = 5;
- combo_box_grouping.id = 6;
- combo_box_menu_button.id = 7;
- disclosure_triangle.id = 8;
- text_field_with_combo_box.id = 9;
-
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
- root.child_ids.push_back(3);
- root.child_ids.push_back(4);
- root.child_ids.push_back(5);
- root.child_ids.push_back(6);
- root.child_ids.push_back(7);
- root.child_ids.push_back(8);
- root.child_ids.push_back(9);
+ list_box.id = 2;
+ list_item.id = 3;
+ menu_item.id = 4;
+ menu_list_option.id = 5;
+ tree_item.id = 6;
+ combo_box_grouping.id = 7;
+ combo_box_menu_button.id = 8;
+ disclosure_triangle.id = 9;
+ text_field_with_combo_box.id = 10;
+
+ root.child_ids.push_back(list_box.id);
+ root.child_ids.push_back(list_item.id);
+ root.child_ids.push_back(menu_item.id);
+ root.child_ids.push_back(menu_list_option.id);
+ root.child_ids.push_back(tree_item.id);
+ root.child_ids.push_back(combo_box_grouping.id);
+ root.child_ids.push_back(combo_box_menu_button.id);
+ root.child_ids.push_back(disclosure_triangle.id);
+ root.child_ids.push_back(text_field_with_combo_box.id);
// list_box HasPopup set to false, does not support expand collapse.
list_box.role = ax::mojom::Role::kListBoxOption;
@@ -5149,22 +5054,22 @@ TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderExpandCollapsePattern) {
TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderInvokePattern) {
ui::AXNodeData root;
- root.id = 0;
+ root.id = 1;
ui::AXNodeData link;
ui::AXNodeData generic_container;
ui::AXNodeData combo_box_grouping;
ui::AXNodeData check_box;
- link.id = 1;
- generic_container.id = 2;
- combo_box_grouping.id = 3;
- check_box.id = 4;
+ link.id = 2;
+ generic_container.id = 3;
+ combo_box_grouping.id = 4;
+ check_box.id = 5;
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
- root.child_ids.push_back(3);
- root.child_ids.push_back(4);
+ root.child_ids.push_back(link.id);
+ root.child_ids.push_back(generic_container.id);
+ root.child_ids.push_back(combo_box_grouping.id);
+ root.child_ids.push_back(check_box.id);
// Role link is clickable and neither supports expand collapse nor supports
// toggle. It should support invoke pattern.
@@ -5215,22 +5120,22 @@ TEST_F(AXPlatformNodeWinTest, TestGetPatternProviderInvokePattern) {
TEST_F(AXPlatformNodeWinTest, TestIExpandCollapsePatternProviderAction) {
ui::AXNodeData root;
- root.id = 0;
+ root.id = 1;
ui::AXNodeData combo_box_grouping_has_popup;
ui::AXNodeData combo_box_grouping_expanded;
ui::AXNodeData combo_box_grouping_collapsed;
ui::AXNodeData combo_box_grouping_disabled;
- combo_box_grouping_has_popup.id = 1;
- combo_box_grouping_expanded.id = 2;
- combo_box_grouping_collapsed.id = 3;
- combo_box_grouping_disabled.id = 4;
+ combo_box_grouping_has_popup.id = 2;
+ combo_box_grouping_expanded.id = 3;
+ combo_box_grouping_collapsed.id = 4;
+ combo_box_grouping_disabled.id = 5;
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
- root.child_ids.push_back(3);
- root.child_ids.push_back(4);
+ root.child_ids.push_back(combo_box_grouping_has_popup.id);
+ root.child_ids.push_back(combo_box_grouping_expanded.id);
+ root.child_ids.push_back(combo_box_grouping_collapsed.id);
+ root.child_ids.push_back(combo_box_grouping_disabled.id);
// combo_box_grouping HasPopup set to true, can collapse, can expand.
// state is ExpandCollapseState_LeafNode.
@@ -5310,16 +5215,16 @@ TEST_F(AXPlatformNodeWinTest, TestIExpandCollapsePatternProviderAction) {
TEST_F(AXPlatformNodeWinTest, TestIInvokeProviderInvoke) {
ui::AXNodeData root;
- root.id = 0;
+ root.id = 1;
ui::AXNodeData button;
ui::AXNodeData button_disabled;
- button.id = 1;
- button_disabled.id = 2;
+ button.id = 2;
+ button_disabled.id = 3;
- root.child_ids.push_back(1);
- root.child_ids.push_back(2);
+ root.child_ids.push_back(button.id);
+ root.child_ids.push_back(button_disabled.id);
// generic button can be invoked.
button.role = ax::mojom::Role::kButton;
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
index 5944f0e86be..07dccad0c51 100644
--- a/chromium/ui/strings/translations/ui_strings_ru.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -75,7 +75,7 @@
<translation id="3234408098842461169">Стрелка вниз</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дня}many{# дней}other{# дня}}</translation>
<translation id="3295886253693811851">Позвонить:</translation>
-<translation id="335581015389089642">Озвучить</translation>
+<translation id="335581015389089642">Озвучивание</translation>
<translation id="3443810440409579745">Вкладка получена.</translation>
<translation id="3479552764303398839">Не сейчас</translation>
<translation id="348799646910989694">Временное хранилище автоматически скрыто</translation>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
index 31d7934d36b..02ef35347c1 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
@@ -79,30 +79,46 @@ const CrScrollableBehavior = {
this.requestUpdateScroll();
- let nodeList = this.root.querySelectorAll('[scrollable] iron-list');
+ const nodeList = this.root.querySelectorAll('[scrollable] iron-list');
if (!nodeList.length) {
return;
}
+ let nodesToResize = Array.from(nodeList).map(node => ({
+ node: node,
+ lastScrollHeight: 0,
+ }));
// Use setInterval to avoid initial render / sizing issues.
- this.intervalId_ = window.setInterval(function() {
- const unreadyNodes = [];
- for (let i = 0; i < nodeList.length; i++) {
- const node = nodeList[i];
- if (node.parentNode.scrollHeight == 0) {
- unreadyNodes.push(node);
- continue;
+ this.intervalId_ = window.setInterval(() => {
+ const checkAgain = [];
+ nodesToResize.forEach(({node, lastScrollHeight}) => {
+ const scrollHeight = node.parentNode.scrollHeight;
+ // A hidden scroll-container has a height of 0. When not hidden, it has
+ // a min-height of 1px and the iron-list needs a resize to show the
+ // initial items and update the |scrollHeight|. The initial item count
+ // is determined by the |scrollHeight|. A scrollHeight of 1px will
+ // result in the minimum default item count (currently 3). After the
+ // |scrollHeight| is updated to be greater than 1px, another resize is
+ // needed to correctly calculate the number of physical iron-list items
+ // to render.
+ if (scrollHeight != lastScrollHeight) {
+ const ironList = /** @type {!IronListElement} */ (node);
+ ironList.notifyResize();
}
- const ironList = /** @type {!IronListElement} */ (node);
- ironList.notifyResize();
- }
- if (unreadyNodes.length == 0) {
+ if (scrollHeight <= 1) {
+ checkAgain.push({
+ node: node,
+ lastScrollHeight: scrollHeight,
+ });
+ }
+ });
+ if (checkAgain.length == 0) {
window.clearInterval(this.intervalId_);
this.intervalId_ = null;
} else {
- nodeList = unreadyNodes;
+ nodesToResize = checkAgain;
}
- }.bind(this), 10);
+ }, 10);
},
/**
diff --git a/chromium/v8/include/v8-version.h b/chromium/v8/include/v8-version.h
index 8c333c3e1ce..0406f65b08e 100644
--- a/chromium/v8/include/v8-version.h
+++ b/chromium/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 7
#define V8_MINOR_VERSION 7
#define V8_BUILD_NUMBER 299
-#define V8_PATCH_LEVEL 8
+#define V8_PATCH_LEVEL 11
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/chromium/v8/src/builtins/base.tq b/chromium/v8/src/builtins/base.tq
index 4aa1d578374..07af1f441f8 100644
--- a/chromium/v8/src/builtins/base.tq
+++ b/chromium/v8/src/builtins/base.tq
@@ -336,10 +336,16 @@ macro NewJSObject(implicit context: Context)(): JSObject {
};
}
+extern macro HasPrototypeSlot(JSFunction): bool;
+
macro GetDerivedMap(implicit context: Context)(
target: JSFunction, newTarget: JSReceiver): Map {
try {
const constructor = Cast<JSFunction>(newTarget) otherwise SlowPath;
+ if (!HasPrototypeSlot(constructor)) {
+ goto SlowPath;
+ }
+ assert(IsConstructor(constructor));
const map =
Cast<Map>(constructor.prototype_or_initial_map) otherwise SlowPath;
if (LoadConstructorOrBackPointer(map) != target) {
diff --git a/chromium/v8/src/codegen/code-stub-assembler.cc b/chromium/v8/src/codegen/code-stub-assembler.cc
index 390746c27dc..e4f35ddcc88 100644
--- a/chromium/v8/src/codegen/code-stub-assembler.cc
+++ b/chromium/v8/src/codegen/code-stub-assembler.cc
@@ -2622,6 +2622,11 @@ TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
Int32Constant(FunctionKind::kConciseGeneratorMethod))));
}
+TNode<BoolT> CodeStubAssembler::HasPrototypeSlot(TNode<JSFunction> function) {
+ return TNode<BoolT>::UncheckedCast(IsSetWord32<Map::HasPrototypeSlotBit>(
+ LoadMapBitField(LoadMap(function))));
+}
+
TNode<BoolT> CodeStubAssembler::HasPrototypeProperty(TNode<JSFunction> function,
TNode<Map> map) {
// (has_prototype_slot() && IsConstructor()) ||
diff --git a/chromium/v8/src/codegen/code-stub-assembler.h b/chromium/v8/src/codegen/code-stub-assembler.h
index 00a84c39265..47abd027490 100644
--- a/chromium/v8/src/codegen/code-stub-assembler.h
+++ b/chromium/v8/src/codegen/code-stub-assembler.h
@@ -1272,6 +1272,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Map> LoadJSArrayElementsMap(SloppyTNode<Int32T> kind,
SloppyTNode<Context> native_context);
+ TNode<BoolT> HasPrototypeSlot(TNode<JSFunction> function);
TNode<BoolT> IsGeneratorFunction(TNode<JSFunction> function);
TNode<BoolT> HasPrototypeProperty(TNode<JSFunction> function, TNode<Map> map);
void GotoIfPrototypeRequiresRuntimeLookup(TNode<JSFunction> function,
diff --git a/chromium/v8/src/compiler/js-native-context-specialization.cc b/chromium/v8/src/compiler/js-native-context-specialization.cc
index 7d742a5f326..8f7552baa18 100644
--- a/chromium/v8/src/compiler/js-native-context-specialization.cc
+++ b/chromium/v8/src/compiler/js-native-context-specialization.cc
@@ -1060,7 +1060,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* control = NodeProperties::GetControlInput(node);
ZoneVector<PropertyAccessInfo> access_infos(zone());
- AccessInfoFactory access_info_factory(broker(), dependencies(), zone());
+ AccessInfoFactory access_info_factory(broker(), dependencies(),
+ graph()->zone());
if (!access_info_factory.FinalizePropertyAccessInfos(
feedback.access_infos(), access_mode, &access_infos)) {
return NoChange();
@@ -1765,7 +1766,7 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess(
if (name.has_value()) {
ZoneVector<PropertyAccessInfo> access_infos(zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
- zone());
+ graph()->zone());
access_info_factory.ComputePropertyAccessInfos(
receiver_maps, name->object(), access_mode, &access_infos);
processed = new (zone()) NamedAccessFeedback(*name, access_infos);
diff --git a/chromium/v8/src/inspector/custom-preview.cc b/chromium/v8/src/inspector/custom-preview.cc
index f56562341ca..77cd6dc5f56 100644
--- a/chromium/v8/src/inspector/custom-preview.cc
+++ b/chromium/v8/src/inspector/custom-preview.cc
@@ -242,10 +242,10 @@ void bodyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
} // anonymous namespace
void generateCustomPreview(int sessionId, const String16& groupName,
- v8::Local<v8::Context> context,
v8::Local<v8::Object> object,
v8::MaybeLocal<v8::Value> maybeConfig, int maxDepth,
std::unique_ptr<CustomPreview>* preview) {
+ v8::Local<v8::Context> context = object->CreationContext();
v8::Isolate* isolate = context->GetIsolate();
v8::MicrotasksScope microtasksScope(isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
diff --git a/chromium/v8/src/inspector/custom-preview.h b/chromium/v8/src/inspector/custom-preview.h
index 1ae8e25a4c7..1e8c74a154c 100644
--- a/chromium/v8/src/inspector/custom-preview.h
+++ b/chromium/v8/src/inspector/custom-preview.h
@@ -13,9 +13,9 @@ namespace v8_inspector {
const int kMaxCustomPreviewDepth = 20;
void generateCustomPreview(
- int sessionId, const String16& groupName, v8::Local<v8::Context> context,
- v8::Local<v8::Object> object, v8::MaybeLocal<v8::Value> config,
- int maxDepth, std::unique_ptr<protocol::Runtime::CustomPreview>* preview);
+ int sessionId, const String16& groupName, v8::Local<v8::Object> object,
+ v8::MaybeLocal<v8::Value> config, int maxDepth,
+ std::unique_ptr<protocol::Runtime::CustomPreview>* preview);
} // namespace v8_inspector
diff --git a/chromium/v8/src/inspector/injected-script.cc b/chromium/v8/src/inspector/injected-script.cc
index 1edd559e4ef..ad91a8e65e9 100644
--- a/chromium/v8/src/inspector/injected-script.cc
+++ b/chromium/v8/src/inspector/injected-script.cc
@@ -458,7 +458,7 @@ Response InjectedScript::wrapObjectMirror(
if (!response.isSuccess()) return response;
if (customPreviewEnabled && value->IsObject()) {
std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
- generateCustomPreview(sessionId, groupName, context, value.As<v8::Object>(),
+ generateCustomPreview(sessionId, groupName, value.As<v8::Object>(),
customPreviewConfig, maxCustomPreviewDepth,
&customPreview);
if (customPreview) (*result)->setCustomPreview(std::move(customPreview));
diff --git a/chromium/v8/src/regexp/regexp-compiler.cc b/chromium/v8/src/regexp/regexp-compiler.cc
index c643f988c0f..c70bbc3e4a5 100644
--- a/chromium/v8/src/regexp/regexp-compiler.cc
+++ b/chromium/v8/src/regexp/regexp-compiler.cc
@@ -1970,9 +1970,11 @@ void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
}
}
+namespace {
+
// Check for [0-9A-Z_a-z].
-static void EmitWordCheck(RegExpMacroAssembler* assembler, Label* word,
- Label* non_word, bool fall_through_on_word) {
+void EmitWordCheck(RegExpMacroAssembler* assembler, Label* word,
+ Label* non_word, bool fall_through_on_word) {
if (assembler->CheckSpecialCharacterClass(
fall_through_on_word ? 'w' : 'W',
fall_through_on_word ? non_word : word)) {
@@ -1994,24 +1996,37 @@ static void EmitWordCheck(RegExpMacroAssembler* assembler, Label* word,
// Emit the code to check for a ^ in multiline mode (1-character lookbehind
// that matches newline or the start of input).
-static void EmitHat(RegExpCompiler* compiler, RegExpNode* on_success,
- Trace* trace) {
+void EmitHat(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
- // We will be loading the previous character into the current character
- // register.
+
+ // We will load the previous character into the current character register.
Trace new_trace(*trace);
new_trace.InvalidateCurrentCharacter();
+ // A positive (> 0) cp_offset means we've already successfully matched a
+ // non-empty-width part of the pattern, and thus cannot be at or before the
+ // start of the subject string. We can thus skip both at-start and
+ // bounds-checks when loading the one-character lookbehind.
+ const bool may_be_at_or_before_subject_string_start =
+ new_trace.cp_offset() <= 0;
+
Label ok;
- if (new_trace.cp_offset() == 0) {
- // The start of input counts as a newline in this context, so skip to
- // ok if we are at the start.
- assembler->CheckAtStart(&ok);
+ if (may_be_at_or_before_subject_string_start) {
+ // The start of input counts as a newline in this context, so skip to ok if
+ // we are at the start.
+ // TODO(jgruber): It would be less awkward to use CheckAtStart here, but
+ // that currently does not support a non-zero cp_offset.
+ Label not_at_start;
+ assembler->CheckNotAtStart(new_trace.cp_offset(), &not_at_start);
+ assembler->GoTo(&ok);
+ assembler->Bind(&not_at_start);
}
- // We already checked that we are not at the start of input so it must be
- // OK to load the previous character.
+
+ // If we've already checked that we are not at the start of input, it's okay
+ // to load the previous character without bounds checks.
+ const bool can_skip_bounds_check = !may_be_at_or_before_subject_string_start;
assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1,
- new_trace.backtrack(), false);
+ new_trace.backtrack(), can_skip_bounds_check);
if (!assembler->CheckSpecialCharacterClass('n', new_trace.backtrack())) {
// Newline means \n, \r, 0x2028 or 0x2029.
if (!compiler->one_byte()) {
@@ -2024,6 +2039,8 @@ static void EmitHat(RegExpCompiler* compiler, RegExpNode* on_success,
on_success->Emit(compiler, &new_trace);
}
+} // namespace
+
// Emit the code to handle \b and \B (word-boundary or non-word-boundary).
void AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
@@ -2080,21 +2097,35 @@ void AssertionNode::BacktrackIfPrevious(
Trace new_trace(*trace);
new_trace.InvalidateCurrentCharacter();
- Label fall_through, dummy;
-
+ Label fall_through;
Label* non_word = backtrack_if_previous == kIsNonWord ? new_trace.backtrack()
: &fall_through;
Label* word = backtrack_if_previous == kIsNonWord ? &fall_through
: new_trace.backtrack();
- if (new_trace.cp_offset() == 0) {
+ // A positive (> 0) cp_offset means we've already successfully matched a
+ // non-empty-width part of the pattern, and thus cannot be at or before the
+ // start of the subject string. We can thus skip both at-start and
+ // bounds-checks when loading the one-character lookbehind.
+ const bool may_be_at_or_before_subject_string_start =
+ new_trace.cp_offset() <= 0;
+
+ if (may_be_at_or_before_subject_string_start) {
// The start of input counts as a non-word character, so the question is
// decided if we are at the start.
- assembler->CheckAtStart(non_word);
- }
- // We already checked that we are not at the start of input so it must be
- // OK to load the previous character.
- assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy, false);
+ // TODO(jgruber): It would be less awkward to use CheckAtStart here, but
+ // that currently does not support a non-zero cp_offset.
+ Label not_at_start;
+ assembler->CheckNotAtStart(new_trace.cp_offset(), &not_at_start);
+ assembler->GoTo(non_word);
+ assembler->Bind(&not_at_start);
+ }
+
+ // If we've already checked that we are not at the start of input, it's okay
+ // to load the previous character without bounds checks.
+ const bool can_skip_bounds_check = !may_be_at_or_before_subject_string_start;
+ assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, non_word,
+ can_skip_bounds_check);
EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord);
assembler->Bind(&fall_through);