summaryrefslogtreecommitdiff
path: root/chromium/content/browser
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-05-09 14:22:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-05-09 15:11:45 +0000
commit2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch)
treee75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/content/browser
parenta4f3d46271c57e8155ba912df46a05559d14726e (diff)
downloadqtwebengine-chromium-2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c.tar.gz
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion. Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/content/browser')
-rw-r--r--chromium/content/browser/BUILD.gn263
-rw-r--r--chromium/content/browser/DEPS15
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder_win.cc2
-rw-r--r--chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc1
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc10
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc3
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_blink.cc47
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm8
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc102
-rw-r--r--chromium/content/browser/accessibility/android_hit_testing_browsertest.cc79
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.cc301
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.h53
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.cc437
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.h4
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_auralinux.cc37
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_auralinux.h7
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.h34
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.mm1369
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac.h8
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac.mm14
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm3
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.cc438
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.h126
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.cc312
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.h12
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.h29
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm205
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc367
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.cc145
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.h24
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.cc2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl_mac.mm44
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc1
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.cc669
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.h61
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc342
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc168
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h8
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc26
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc102
-rw-r--r--chromium/content/browser/accessibility/hit_testing_browsertest.cc171
-rw-r--r--chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc246
-rw-r--r--chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h41
-rw-r--r--chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc14
-rw-r--r--chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc66
-rw-r--r--chromium/content/browser/android/browser_surface_texture_manager.h8
-rw-r--r--chromium/content/browser/android/child_process_launcher_android.cc56
-rw-r--r--chromium/content/browser/android/child_process_launcher_android.h8
-rw-r--r--chromium/content/browser/android/composited_touch_handle_drawable.cc2
-rw-r--r--chromium/content/browser/android/content_startup_flags.cc9
-rw-r--r--chromium/content/browser/android/content_video_view.cc111
-rw-r--r--chromium/content/browser/android/content_video_view.h88
-rw-r--r--chromium/content/browser/android/content_view_core_impl.cc99
-rw-r--r--chromium/content/browser/android/content_view_core_impl.h29
-rw-r--r--chromium/content/browser/android/content_view_core_impl_observer.h22
-rw-r--r--chromium/content/browser/android/content_view_render_view.cc16
-rw-r--r--chromium/content/browser/android/content_view_render_view.h7
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.cc101
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.h14
-rw-r--r--chromium/content/browser/android/in_process/context_provider_in_process.cc53
-rw-r--r--chromium/content/browser/android/in_process/context_provider_in_process.h11
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc193
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h25
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.cc60
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.h17
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.cc15
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.h16
-rw-r--r--chromium/content/browser/android/in_process/synchronous_input_event_filter.cc38
-rw-r--r--chromium/content/browser/android/in_process/synchronous_input_event_filter.h18
-rw-r--r--chromium/content/browser/android/in_process_surface_texture_manager.h8
-rw-r--r--chromium/content/browser/android/java/OWNERS2
-rw-r--r--chromium/content/browser/android/service_registry_android_impl.cc (renamed from chromium/content/browser/mojo/service_registry_android.cc)51
-rw-r--r--chromium/content/browser/android/service_registry_android_impl.h53
-rw-r--r--chromium/content/browser/android/synchronous_compositor_base.cc32
-rw-r--r--chromium/content/browser/android/synchronous_compositor_base.h3
-rw-r--r--chromium/content/browser/android/synchronous_compositor_host.cc140
-rw-r--r--chromium/content/browser/android/synchronous_compositor_host.h19
-rw-r--r--chromium/content/browser/android/web_contents_observer_proxy.cc24
-rw-r--r--chromium/content/browser/android/web_contents_observer_proxy.h4
-rw-r--r--chromium/content/browser/appcache/appcache_database.cc2
-rw-r--r--chromium/content/browser/appcache/appcache_database.h1
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.cc2
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.h2
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.cc11
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.h4
-rw-r--r--chromium/content/browser/appcache/appcache_internals_ui.cc2
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.cc2
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.h7
-rw-r--r--chromium/content/browser/appcache/appcache_response.cc30
-rw-r--r--chromium/content/browser/appcache/appcache_response.h40
-rw-r--r--chromium/content/browser/appcache/appcache_service_impl.cc5
-rw-r--r--chromium/content/browser/appcache/appcache_service_unittest.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.cc24
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.h1
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.cc6
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.h1
-rw-r--r--chromium/content/browser/appcache/chrome_appcache_service_unittest.cc9
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.cc8
-rw-r--r--chromium/content/browser/background_sync/background_sync.proto16
-rw-r--r--chromium/content/browser/background_sync/background_sync_browsertest.cc299
-rw-r--r--chromium/content/browser/background_sync/background_sync_context_impl.cc13
-rw-r--r--chromium/content/browser/background_sync/background_sync_context_impl.h12
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager.cc808
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager.h184
-rw-r--r--chromium/content/browser/background_sync/background_sync_manager_unittest.cc1048
-rw-r--r--chromium/content/browser/background_sync/background_sync_metrics.cc101
-rw-r--r--chromium/content/browser/background_sync/background_sync_metrics.h15
-rw-r--r--chromium/content/browser/background_sync/background_sync_power_observer.cc62
-rw-r--r--chromium/content/browser/background_sync/background_sync_power_observer.h51
-rw-r--r--chromium/content/browser/background_sync/background_sync_power_observer_unittest.cc72
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration.cc62
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration.h35
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration_handle.cc53
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration_handle.h95
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration_options.cc4
-rw-r--r--chromium/content/browser/background_sync/background_sync_registration_options.h3
-rw-r--r--chromium/content/browser/background_sync/background_sync_service_impl.cc216
-rw-r--r--chromium/content/browser/background_sync/background_sync_service_impl.h46
-rw-r--r--chromium/content/browser/background_sync/background_sync_service_impl_unittest.cc257
-rw-r--r--chromium/content/browser/background_sync/background_sync_status.h3
-rw-r--r--chromium/content/browser/bad_message.h13
-rw-r--r--chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc7
-rw-r--r--chromium/content/browser/blob_storage/blob_async_builder_host_unittest.cc476
-rw-r--r--chromium/content/browser/blob_storage/blob_async_transport_request_builder_unittest.cc356
-rw-r--r--chromium/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc458
-rw-r--r--chromium/content/browser/blob_storage/blob_dispatcher_host.cc370
-rw-r--r--chromium/content/browser/blob_storage/blob_dispatcher_host.h148
-rw-r--r--chromium/content/browser/blob_storage/blob_dispatcher_host_unittest.cc1199
-rw-r--r--chromium/content/browser/blob_storage/blob_storage_registry_unittest.cc27
-rw-r--r--chromium/content/browser/bluetooth/README.md24
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.cc65
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.h29
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc355
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_blacklist.cc185
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_blacklist.h104
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_blacklist_unittest.cc398
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc849
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h105
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_metrics.cc40
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_metrics.h22
-rw-r--r--chromium/content/browser/bluetooth/web_bluetooth_service_impl.cc156
-rw-r--r--chromium/content/browser/bluetooth/web_bluetooth_service_impl.h77
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.cc80
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.h9
-rw-r--r--chromium/content/browser/browser_context.cc66
-rw-r--r--chromium/content/browser/browser_main.cc1
-rw-r--r--chromium/content/browser/browser_main_loop.cc177
-rw-r--r--chromium/content/browser/browser_main_loop.h26
-rw-r--r--chromium/content/browser/browser_main_runner.cc95
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_embedder.cc4
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.cc102
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.h26
-rw-r--r--chromium/content/browser/browser_process_sub_thread.cc2
-rw-r--r--chromium/content/browser/browser_process_sub_thread.h1
-rw-r--r--chromium/content/browser/browser_side_navigation_browsertest.cc46
-rw-r--r--chromium/content/browser/browser_thread_impl.cc36
-rw-r--r--chromium/content/browser/browsing_instance.cc53
-rw-r--r--chromium/content/browser/browsing_instance.h39
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.cc353
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.h79
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.proto1
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc3
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h16
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc2
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.cc389
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.h90
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc320
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_context_impl.cc18
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_context_impl.h8
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc62
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h30
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.cc212
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.h20
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc296
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_unittest.cc26
-rw-r--r--chromium/content/browser/child_process_launcher.cc121
-rw-r--r--chromium/content/browser/child_process_launcher.h13
-rw-r--r--chromium/content/browser/child_process_security_policy_impl.cc10
-rw-r--r--chromium/content/browser/child_process_security_policy_unittest.cc9
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_helper_mac.h1
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map.mm29
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map_unittest.mm10
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface.h2
-rw-r--r--chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm9
-rw-r--r--chromium/content/browser/compositor/buffer_queue.cc25
-rw-r--r--chromium/content/browser/compositor/buffer_queue.h9
-rw-r--r--chromium/content/browser/compositor/buffer_queue_unittest.cc9
-rw-r--r--chromium/content/browser/compositor/gl_helper.cc1226
-rw-r--r--chromium/content/browser/compositor/gl_helper.h379
-rw-r--r--chromium/content/browser/compositor/gl_helper_benchmark.cc247
-rw-r--r--chromium/content/browser/compositor/gl_helper_readback_support.cc172
-rw-r--r--chromium/content/browser/compositor/gl_helper_readback_support.h75
-rw-r--r--chromium/content/browser/compositor/gl_helper_scaling.cc881
-rw-r--r--chromium/content/browser/compositor/gl_helper_scaling.h206
-rw-r--r--chromium/content/browser/compositor/gl_helper_unittest.cc1828
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc4
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h7
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.cc125
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.h7
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc4
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h9
-rw-r--r--chromium/content/browser/compositor/owned_mailbox.cc2
-rw-r--r--chromium/content/browser/compositor/reflector_texture.cc2
-rw-r--r--chromium/content/browser/compositor/software_output_device_mac.h4
-rw-r--r--chromium/content/browser/compositor/software_output_device_mac.mm4
-rw-r--r--chromium/content/browser/compositor/software_output_device_win.cc10
-rw-r--r--chromium/content/browser/compositor/software_output_device_win.h4
-rw-r--r--chromium/content/browser/compositor/surface_utils.cc177
-rw-r--r--chromium/content/browser/compositor/surface_utils.h12
-rw-r--r--chromium/content/browser/cross_site_transfer_browsertest.cc6
-rw-r--r--chromium/content/browser/database_util_unittest.cc27
-rw-r--r--chromium/content/browser/device_monitor_mac.h51
-rw-r--r--chromium/content/browser/device_monitor_mac.mm568
-rw-r--r--chromium/content/browser/device_monitor_udev.cc89
-rw-r--r--chromium/content/browser/device_monitor_udev.h44
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc1
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc3
-rw-r--r--chromium/content/browser/device_sensors/device_light_message_filter.cc43
-rw-r--r--chromium/content/browser/device_sensors/device_light_message_filter.h12
-rw-r--r--chromium/content/browser/device_sensors/device_motion_message_filter.cc45
-rw-r--r--chromium/content/browser/device_sensors/device_motion_message_filter.h12
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.cc42
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.h13
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_message_filter.cc47
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_message_filter.h12
-rw-r--r--chromium/content/browser/device_sensors/device_sensor_message_filter.cc44
-rw-r--r--chromium/content/browser/device_sensors/device_sensor_message_filter.h40
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android.cc1
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_chromeos.cc1
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc1
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.cc5
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.cc7
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.h2
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.cc2
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.h1
-rw-r--r--chromium/content/browser/devtools/devtools_manager.h1
-rw-r--r--chromium/content/browser/devtools/devtools_netlog_observer.cc4
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc32
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_client.h1
-rwxr-xr-xchromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py1
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.cc43
-rw-r--r--chromium/content/browser/devtools/protocol/emulation_handler.h26
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.cc11
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.cc5
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.h1
-rw-r--r--chromium/content/browser/devtools/protocol/memory_handler.cc6
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.cc34
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.cc15
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.h3
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.cc80
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.h6
-rw-r--r--chromium/content/browser/devtools/protocol/system_info_handler.cc7
-rw-r--r--chromium/content/browser/devtools/protocol/tethering_handler.cc9
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.cc118
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.h16
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc73
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.cc205
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.h16
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.cc4
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_agent_host.h1
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.cc12
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.h6
-rw-r--r--chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc8
-rw-r--r--chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc65
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_browsertest.cc1
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc194
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.h20
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_host.cc2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_host.h1
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.cc2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.h1
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database.cc3
-rw-r--r--chromium/content/browser/download/OWNERS2
-rw-r--r--chromium/content/browser/download/base_file.cc201
-rw-r--r--chromium/content/browser/download/base_file.h190
-rw-r--r--chromium/content/browser/download/base_file_linux.cc7
-rw-r--r--chromium/content/browser/download/base_file_mac.cc9
-rw-r--r--chromium/content/browser/download/base_file_unittest.cc459
-rw-r--r--chromium/content/browser/download/base_file_win.cc11
-rw-r--r--chromium/content/browser/download/docs/save-page-as.md137
-rw-r--r--chromium/content/browser/download/download_browsertest.cc999
-rw-r--r--chromium/content/browser/download/download_create_info.cc21
-rw-r--r--chromium/content/browser/download/download_create_info.h50
-rw-r--r--chromium/content/browser/download/download_destination_observer.h44
-rw-r--r--chromium/content/browser/download/download_file.h29
-rw-r--r--chromium/content/browser/download/download_file_factory.cc13
-rw-r--r--chromium/content/browser/download/download_file_factory.h10
-rw-r--r--chromium/content/browser/download/download_file_impl.cc158
-rw-r--r--chromium/content/browser/download/download_file_impl.h66
-rw-r--r--chromium/content/browser/download/download_file_unittest.cc221
-rw-r--r--chromium/content/browser/download/download_interrupt_reasons_impl.cc3
-rw-r--r--chromium/content/browser/download/download_item_factory.h2
-rw-r--r--chromium/content/browser/download/download_item_impl.cc1061
-rw-r--r--chromium/content/browser/download/download_item_impl.h392
-rw-r--r--chromium/content/browser/download/download_item_impl_delegate.cc5
-rw-r--r--chromium/content/browser/download/download_item_impl_delegate.h5
-rw-r--r--chromium/content/browser/download/download_item_impl_unittest.cc1180
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc305
-rw-r--r--chromium/content/browser/download/download_manager_impl.h35
-rw-r--r--chromium/content/browser/download/download_manager_impl_unittest.cc179
-rw-r--r--chromium/content/browser/download/download_net_log_parameters.cc9
-rw-r--r--chromium/content/browser/download/download_net_log_parameters.h3
-rw-r--r--chromium/content/browser/download/download_request_core.cc527
-rw-r--r--chromium/content/browser/download/download_request_core.h88
-rw-r--r--chromium/content/browser/download/download_request_handle.cc86
-rw-r--r--chromium/content/browser/download/download_request_handle.h29
-rw-r--r--chromium/content/browser/download/download_resource_handler.cc105
-rw-r--r--chromium/content/browser/download/download_resource_handler.h25
-rw-r--r--chromium/content/browser/download/drag_download_file.cc4
-rw-r--r--chromium/content/browser/download/mhtml_generation_manager.cc5
-rw-r--r--chromium/content/browser/download/mock_download_file.h9
-rw-r--r--chromium/content/browser/download/save_file.cc23
-rw-r--r--chromium/content/browser/download/save_file.h1
-rw-r--r--chromium/content/browser/download/save_file_manager.cc26
-rw-r--r--chromium/content/browser/download/save_file_manager.h14
-rw-r--r--chromium/content/browser/download/save_file_resource_handler.cc2
-rw-r--r--chromium/content/browser/download/save_item.cc4
-rw-r--r--chromium/content/browser/download/save_item.h8
-rw-r--r--chromium/content/browser/download/save_package.cc121
-rw-r--r--chromium/content/browser/download/save_package.h25
-rw-r--r--chromium/content/browser/download/save_package_unittest.cc3
-rw-r--r--chromium/content/browser/download/save_types.cc3
-rw-r--r--chromium/content/browser/download/save_types.h8
-rw-r--r--chromium/content/browser/download/url_downloader.cc115
-rw-r--r--chromium/content/browser/download/url_downloader.h48
-rw-r--r--chromium/content/browser/fileapi/blob_reader_unittest.cc54
-rw-r--r--chromium/content/browser/fileapi/blob_storage_context_unittest.cc274
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.cc116
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.h75
-rw-r--r--chromium/content/browser/fileapi/blob_url_request_job_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc4
-rw-r--r--chromium/content/browser/fileapi/dragged_file_util_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc11
-rw-r--r--chromium/content/browser/fileapi/file_system_quota_client_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.cc116
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.h25
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc2
-rw-r--r--chromium/content/browser/fileapi/local_file_util_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/native_file_util_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc1
-rw-r--r--chromium/content/browser/fileapi/upload_file_system_file_element_reader.h1
-rw-r--r--chromium/content/browser/frame_host/OWNERS1
-rw-r--r--chromium/content/browser/frame_host/PRESUBMIT.py53
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.cc145
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.h40
-rw-r--r--chromium/content/browser/frame_host/debug_urls.cc26
-rw-r--r--chromium/content/browser/frame_host/frame_mojo_shell.cc42
-rw-r--r--chromium/content/browser/frame_host/frame_mojo_shell.h34
-rw-r--r--chromium/content/browser/frame_host/frame_navigation_entry.cc19
-rw-r--r--chromium/content/browser/frame_host/frame_navigation_entry.h6
-rw-r--r--chromium/content/browser/frame_host/frame_tree.cc230
-rw-r--r--chromium/content/browser/frame_host/frame_tree.h66
-rw-r--r--chromium/content/browser/frame_host/frame_tree_browsertest.cc31
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.cc156
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.h84
-rw-r--r--chromium/content/browser/frame_host/frame_tree_unittest.cc166
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.cc81
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.h16
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.cc4
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.h6
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_delegate.h5
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.cc177
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.h26
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc424
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc403
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.cc56
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.h7
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc30
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl.cc146
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl.h76
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc560
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl_unittest.cc170
-rw-r--r--chromium/content/browser/frame_host/navigation_request.cc147
-rw-r--r--chromium/content/browser/frame_host/navigation_request.h36
-rw-r--r--chromium/content/browser/frame_host/navigator.cc5
-rw-r--r--chromium/content/browser/frame_host/navigator.h8
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.cc395
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.h24
-rw-r--r--chromium/content/browser/frame_host/navigator_impl_unittest.cc168
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.cc7
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.h11
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_factory.cc6
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_factory.h4
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.cc650
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.h225
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.cc924
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.h125
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc395
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc438
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.cc188
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.h26
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter_browsertest.cc67
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.cc35
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.h4
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc234
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.h66
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc47
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.cc150
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.h23
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc89
-rw-r--r--chromium/content/browser/frame_host/traced_frame_tree_node.cc69
-rw-r--r--chromium/content/browser/frame_host/traced_frame_tree_node.h36
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc14
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h8
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc26
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h7
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider.cc3
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider.h1
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager.cc8
-rw-r--r--chromium/content/browser/geofencing/geofencing_service.h1
-rw-r--r--chromium/content/browser/geolocation/fake_access_token_store.cc10
-rw-r--r--chromium/content/browser/geolocation/fake_access_token_store.h11
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl.cc24
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl.h10
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc8
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_context.cc2
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_context.h6
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.cc5
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.h20
-rw-r--r--chromium/content/browser/geolocation/location_api_adapter_android.cc2
-rw-r--r--chromium/content/browser/geolocation/location_api_adapter_android.h23
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator.h2
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.cc32
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.h6
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc4
-rw-r--r--chromium/content/browser/geolocation/mock_location_arbitrator.cc2
-rw-r--r--chromium/content/browser/geolocation/mock_location_arbitrator.h2
-rw-r--r--chromium/content/browser/geolocation/network_location_provider.cc18
-rw-r--r--chromium/content/browser/geolocation/network_location_provider.h2
-rw-r--r--chromium/content/browser/geolocation/network_location_provider_unittest.cc6
-rw-r--r--chromium/content/browser/geolocation/network_location_request.cc58
-rw-r--r--chromium/content/browser/geolocation/network_location_request.h6
-rw-r--r--chromium/content/browser/geolocation/wifi_data.cc2
-rw-r--r--chromium/content/browser/geolocation/wifi_data.h1
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider.cc17
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider.h16
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc18
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.h1
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc17
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_common.cc2
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc80
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm3
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc9
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_manager.h1
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win.cc1
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc5
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc83
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.h25
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc77
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h12
-rw-r--r--chromium/content/browser/gpu/compositor_util.cc42
-rw-r--r--chromium/content/browser/gpu/compositor_util.h7
-rw-r--r--chromium/content/browser/gpu/gpu_arc_video_service_host.cc76
-rw-r--r--chromium/content/browser/gpu/gpu_arc_video_service_host.h54
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.cc29
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.h22
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.cc224
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.h38
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc66
-rw-r--r--chromium/content/browser/gpu/gpu_internals_ui.cc51
-rw-r--r--chromium/content/browser/gpu/gpu_ipc_browsertests.cc117
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.cc245
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.h77
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.cc18
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.h19
-rw-r--r--chromium/content/browser/gpu/gpu_surface_tracker.cc55
-rw-r--r--chromium/content/browser/gpu/gpu_surface_tracker.h25
-rw-r--r--chromium/content/browser/histogram_controller.cc10
-rw-r--r--chromium/content/browser/host_zoom_map_impl.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.cc117
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.h11
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc33
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_browsertest.cc23
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.cc5
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.cc183
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.h34
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.cc63
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.h3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_unittest.cc38
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc217
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h15
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.cc1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc36
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.cc9
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc167
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata.h11
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_pending_connection.cc3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_pending_connection.h1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client.cc31
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc5
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_unittest.cc47
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_database.cc32
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_database.h11
-rw-r--r--chromium/content/browser/indexed_db/leveldb_coding_scheme.md323
-rw-r--r--chromium/content/browser/leveldb_wrapper_impl.cc143
-rw-r--r--chromium/content/browser/leveldb_wrapper_impl.h68
-rw-r--r--chromium/content/browser/loader/async_resource_handler.cc223
-rw-r--r--chromium/content/browser/loader/async_resource_handler.h11
-rw-r--r--chromium/content/browser/loader/async_resource_handler_browsertest.cc10
-rw-r--r--chromium/content/browser/loader/async_revalidation_driver.cc4
-rw-r--r--chromium/content/browser/loader/async_revalidation_driver.h10
-rw-r--r--chromium/content/browser/loader/async_revalidation_driver_unittest.cc24
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager.cc6
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager.h9
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager_browsertest.cc43
-rw-r--r--chromium/content/browser/loader/async_revalidation_manager_unittest.cc15
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.cc7
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.h2
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc19
-rw-r--r--chromium/content/browser/loader/detachable_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/detachable_resource_handler.h9
-rw-r--r--chromium/content/browser/loader/global_routing_id.h29
-rw-r--r--chromium/content/browser/loader/layered_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/layered_resource_handler.h7
-rw-r--r--chromium/content/browser/loader/mime_type_resource_handler.cc94
-rw-r--r--chromium/content/browser/loader/mime_type_resource_handler.h9
-rw-r--r--chromium/content/browser/loader/mime_type_resource_handler_unittest.cc116
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.cc11
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.h3
-rw-r--r--chromium/content/browser/loader/navigation_resource_throttle.cc26
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.cc6
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.h10
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_delegate.h5
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_factory.h7
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.cc13
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.h11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.cc11
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.h10
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_unittest.cc77
-rw-r--r--chromium/content/browser/loader/power_save_block_resource_throttle.h4
-rw-r--r--chromium/content/browser/loader/redirect_to_file_resource_handler.cc8
-rw-r--r--chromium/content/browser/loader/redirect_to_file_resource_handler.h7
-rw-r--r--chromium/content/browser/loader/resource_buffer.cc12
-rw-r--r--chromium/content/browser/loader/resource_buffer.h9
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc14
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.cc694
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.h173
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_unittest.cc553
-rw-r--r--chromium/content/browser/loader/resource_loader.cc60
-rw-r--r--chromium/content/browser/loader/resource_loader.h36
-rw-r--r--chromium/content/browser/loader/resource_loader_unittest.cc93
-rw-r--r--chromium/content/browser/loader/resource_message_filter.h3
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.cc17
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.h2
-rw-r--r--chromium/content/browser/loader/resource_scheduler.cc447
-rw-r--r--chromium/content/browser/loader/resource_scheduler.h106
-rw-r--r--chromium/content/browser/loader/resource_scheduler_unittest.cc1908
-rw-r--r--chromium/content/browser/loader/stream_resource_handler.h3
-rw-r--r--chromium/content/browser/loader/temporary_file_stream.cc15
-rw-r--r--chromium/content/browser/loader/temporary_file_stream.h5
-rw-r--r--chromium/content/browser/loader/temporary_file_stream_unittest.cc4
-rw-r--r--chromium/content/browser/loader/throttling_resource_handler.cc2
-rw-r--r--chromium/content/browser/loader/throttling_resource_handler.h2
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.cc17
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.h5
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder_unittest.cc32
-rw-r--r--chromium/content/browser/mach_broker_mac.h62
-rw-r--r--chromium/content/browser/mach_broker_mac.mm173
-rw-r--r--chromium/content/browser/mach_broker_mac_unittest.cc112
-rw-r--r--chromium/content/browser/media/OWNERS11
-rw-r--r--chromium/content/browser/media/android/OWNERS3
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.cc4
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.h2
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.cc140
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.h37
-rw-r--r--chromium/content/browser/media/android/browser_media_session_manager.cc23
-rw-r--r--chromium/content/browser/media/android/browser_media_session_manager.h2
-rw-r--r--chromium/content/browser/media/android/browser_surface_view_manager.cc86
-rw-r--r--chromium/content/browser/media/android/browser_surface_view_manager.h54
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.cc4
-rw-r--r--chromium/content/browser/media/android/media_session.h181
-rw-r--r--chromium/content/browser/media/android/media_web_contents_observer_android.cc102
-rw-r--r--chromium/content/browser/media/android/media_web_contents_observer_android.h48
-rw-r--r--chromium/content/browser/media/android/provision_fetcher_impl.cc2
-rw-r--r--chromium/content/browser/media/android/provision_fetcher_impl.h10
-rw-r--r--chromium/content/browser/media/android/url_provision_fetcher.cc5
-rw-r--r--chromium/content/browser/media/android/url_provision_fetcher.h2
-rw-r--r--chromium/content/browser/media/audible_metrics.cc3
-rw-r--r--chromium/content/browser/media/audible_metrics.h6
-rw-r--r--chromium/content/browser/media/audible_metrics_unittest.cc61
-rw-r--r--chromium/content/browser/media/audio_stream_monitor_unittest.cc2
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.cc3
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.h1
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc40
-rw-r--r--chromium/content/browser/media/capture/aura_window_capture_machine.cc171
-rw-r--r--chromium/content/browser/media/capture/aura_window_capture_machine.h61
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer.h2
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura.cc56
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura.h13
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc55
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_mac.h48
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_mac.mm189
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.cc104
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.h14
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.cc13
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.h9
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc33
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_uma_types.h3
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_unittest.cc65
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.cc28
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc4
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_muter.cc12
-rw-r--r--chromium/content/browser/media/capture/web_contents_tracker.cc6
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.cc260
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.h7
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc338
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker.cc54
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker.h33
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker_aura.cc39
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker_aura.h11
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker_mac.h62
-rw-r--r--chromium/content/browser/media/capture/window_activity_tracker_mac.mm82
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.cc43
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.h23
-rw-r--r--chromium/content/browser/media/encrypted_media_browsertest.cc20
-rw-r--r--chromium/content/browser/media/media_browsertest.cc10
-rw-r--r--chromium/content/browser/media/media_canplaytype_browsertest.cc791
-rw-r--r--chromium/content/browser/media/media_internals.cc51
-rw-r--r--chromium/content/browser/media/media_internals.h5
-rw-r--r--chromium/content/browser/media/media_internals_proxy.cc2
-rw-r--r--chromium/content/browser/media/media_internals_proxy.h2
-rw-r--r--chromium/content/browser/media/media_internals_unittest.cc12
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.cc118
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.h41
-rw-r--r--chromium/content/browser/media/midi_host.cc10
-rw-r--r--chromium/content/browser/media/midi_host.h2
-rw-r--r--chromium/content/browser/media/midi_host_unittest.cc2
-rw-r--r--chromium/content/browser/media/session/OWNERS2
-rw-r--r--chromium/content/browser/media/session/media_session.cc (renamed from chromium/content/browser/media/android/media_session.cc)145
-rw-r--r--chromium/content/browser/media/session/media_session.h212
-rw-r--r--chromium/content/browser/media/session/media_session_browsertest.cc (renamed from chromium/content/browser/media/android/media_session_browsertest.cc)380
-rw-r--r--chromium/content/browser/media/session/media_session_controller.cc109
-rw-r--r--chromium/content/browser/media/session/media_session_controller.h71
-rw-r--r--chromium/content/browser/media/session/media_session_controller_unittest.cc214
-rw-r--r--chromium/content/browser/media/session/media_session_controllers_manager.cc94
-rw-r--r--chromium/content/browser/media/session/media_session_controllers_manager.h63
-rw-r--r--chromium/content/browser/media/session/media_session_delegate.h26
-rw-r--r--chromium/content/browser/media/session/media_session_delegate_android.cc95
-rw-r--r--chromium/content/browser/media/session/media_session_delegate_android.h59
-rw-r--r--chromium/content/browser/media/session/media_session_delegate_android_browsertest.cc65
-rw-r--r--chromium/content/browser/media/session/media_session_delegate_default.cc62
-rw-r--r--chromium/content/browser/media/session/media_session_delegate_default_browsertest.cc49
-rw-r--r--chromium/content/browser/media/session/media_session_observer.h (renamed from chromium/content/browser/media/android/media_session_observer.h)11
-rw-r--r--chromium/content/browser/media/session/media_session_uma_helper.cc (renamed from chromium/content/browser/media/android/media_session_uma_helper.cc)4
-rw-r--r--chromium/content/browser/media/session/media_session_uma_helper.h (renamed from chromium/content/browser/media/android/media_session_uma_helper.h)14
-rw-r--r--chromium/content/browser/media/session/media_session_uma_helper_unittest.cc (renamed from chromium/content/browser/media/android/media_session_uma_helper_unittest.cc)36
-rw-r--r--chromium/content/browser/media/session/media_session_visibility_browsertest.cc266
-rw-r--r--chromium/content/browser/media/session/mock_media_session_observer.cc70
-rw-r--r--chromium/content/browser/media/session/mock_media_session_observer.h59
-rw-r--r--chromium/content/browser/media/webrtc/OWNERS5
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc (renamed from chromium/content/browser/media/webrtc_audio_debug_recordings_browsertest.cc)4
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_browsertest.cc (renamed from chromium/content/browser/media/webrtc_browsertest.cc)0
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc (renamed from chromium/content/browser/media/webrtc_getusermedia_browsertest.cc)7
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_identity_store.cc (renamed from chromium/content/browser/media/webrtc_identity_store.cc)6
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_identity_store.h (renamed from chromium/content/browser/media/webrtc_identity_store.h)6
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_identity_store_backend.cc (renamed from chromium/content/browser/media/webrtc_identity_store_backend.cc)11
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_identity_store_backend.h (renamed from chromium/content/browser/media/webrtc_identity_store_backend.h)11
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_identity_store_unittest.cc (renamed from chromium/content/browser/media/webrtc_identity_store_unittest.cc)10
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals.cc (renamed from chromium/content/browser/media/webrtc_internals.cc)132
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals.h (renamed from chromium/content/browser/media/webrtc_internals.h)70
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_browsertest.cc (renamed from chromium/content/browser/media/webrtc_internals_browsertest.cc)4
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_message_handler.cc (renamed from chromium/content/browser/media/webrtc_internals_message_handler.cc)4
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_message_handler.h (renamed from chromium/content/browser/media/webrtc_internals_message_handler.h)8
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_ui.cc (renamed from chromium/content/browser/media/webrtc_internals_ui.cc)4
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_ui.h (renamed from chromium/content/browser/media/webrtc_internals_ui.h)6
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_ui_observer.h (renamed from chromium/content/browser/media/webrtc_internals_ui_observer.h)6
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_internals_unittest.cc (renamed from chromium/content/browser/media/webrtc_internals_unittest.cc)214
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_ip_permissions_browsertest.cc (renamed from chromium/content/browser/media/webrtc_ip_permissions_browsertest.cc)0
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc (renamed from chromium/content/browser/media/webrtc_media_recorder_browsertest.cc)0
-rw-r--r--chromium/content/browser/media/webrtc/webrtc_webcam_browsertest.cc (renamed from chromium/content/browser/media/webrtc_webcam_browsertest.cc)0
-rw-r--r--chromium/content/browser/memory/memory_message_filter.cc7
-rw-r--r--chromium/content/browser/memory/memory_message_filter.h4
-rw-r--r--chromium/content/browser/memory/memory_pressure_controller_impl.cc (renamed from chromium/content/browser/memory/memory_pressure_controller.cc)33
-rw-r--r--chromium/content/browser/memory/memory_pressure_controller_impl.h (renamed from chromium/content/browser/memory/memory_pressure_controller.h)44
-rw-r--r--chromium/content/browser/memory/memory_pressure_controller_impl_browsertest.cc (renamed from chromium/content/browser/memory/memory_pressure_controller_browsertest.cc)16
-rw-r--r--chromium/content/browser/message_port_service.cc11
-rw-r--r--chromium/content/browser/message_port_service.h3
-rw-r--r--chromium/content/browser/mojo/OWNERS13
-rw-r--r--chromium/content/browser/mojo/constants.cc19
-rw-r--r--chromium/content/browser/mojo/constants.h15
-rw-r--r--chromium/content/browser/mojo/mojo_app_connection_impl.cc28
-rw-r--r--chromium/content/browser/mojo/mojo_app_connection_impl.h16
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.cc55
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.h11
-rw-r--r--chromium/content/browser/mojo/mojo_child_connection.cc137
-rw-r--r--chromium/content/browser/mojo/mojo_child_connection.h36
-rw-r--r--chromium/content/browser/mojo/mojo_shell_client_host.cc219
-rw-r--r--chromium/content/browser/mojo/mojo_shell_client_host.h48
-rw-r--r--chromium/content/browser/mojo/mojo_shell_context.cc269
-rw-r--r--chromium/content/browser/mojo/mojo_shell_context.h53
-rw-r--r--chromium/content/browser/mojo/renderer_capability_filter.cc22
-rw-r--r--chromium/content/browser/mojo/service_registrar_android.cc2
-rw-r--r--chromium/content/browser/mojo/service_registry_android.h56
-rw-r--r--chromium/content/browser/mojo_shell_browsertest.cc33
-rw-r--r--chromium/content/browser/navigator_connect/OWNERS1
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc266
-rw-r--r--chromium/content/browser/navigator_connect/navigator_connect_context_impl.h133
-rw-r--r--chromium/content/browser/navigator_connect/service_port_service_impl.cc132
-rw-r--r--chromium/content/browser/navigator_connect/service_port_service_impl.h85
-rw-r--r--chromium/content/browser/net/quota_policy_cookie_store.cc18
-rw-r--r--chromium/content/browser/net/quota_policy_cookie_store_unittest.cc8
-rw-r--r--chromium/content/browser/notifications/notification_database.h2
-rw-r--r--chromium/content/browser/notifications/notification_database_data.proto16
-rw-r--r--chromium/content/browser/notifications/notification_database_data_conversions.cc49
-rw-r--r--chromium/content/browser/notifications/notification_database_data_unittest.cc73
-rw-r--r--chromium/content/browser/notifications/notification_event_dispatcher_impl.cc277
-rw-r--r--chromium/content/browser/notifications/notification_event_dispatcher_impl.h12
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.cc55
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.h13
-rw-r--r--chromium/content/browser/permissions/permission_service_context.cc2
-rw-r--r--chromium/content/browser/permissions/permission_service_context.h17
-rw-r--r--chromium/content/browser/permissions/permission_service_impl.cc67
-rw-r--r--chromium/content/browser/permissions/permission_service_impl.h53
-rw-r--r--chromium/content/browser/plugin_data_remover_impl.cc85
-rw-r--r--chromium/content/browser/plugin_loader_posix.cc237
-rw-r--r--chromium/content/browser/plugin_loader_posix.h134
-rw-r--r--chromium/content/browser/plugin_loader_posix_unittest.cc426
-rw-r--r--chromium/content/browser/plugin_process_host.cc442
-rw-r--r--chromium/content/browser/plugin_process_host.h219
-rw-r--r--chromium/content/browser/plugin_process_host_mac.cc107
-rw-r--r--chromium/content/browser/plugin_service_impl.cc473
-rw-r--r--chromium/content/browser/plugin_service_impl.h93
-rw-r--r--chromium/content/browser/power_save_blocker_impl.cc4
-rw-r--r--chromium/content/browser/power_save_blocker_x11.cc67
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.cc25
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.h5
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.cc116
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.h43
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl_unittest.cc185
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters.cc39
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters.h27
-rw-r--r--chromium/content/browser/presentation/presentation_type_converters_unittest.cc9
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.cc72
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.h16
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.cc38
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.h18
-rw-r--r--chromium/content/browser/quota/mock_quota_manager_proxy.cc10
-rw-r--r--chromium/content/browser/quota/mock_quota_manager_proxy.h2
-rw-r--r--chromium/content/browser/quota/quota_backend_impl_unittest.cc1
-rw-r--r--chromium/content/browser/quota/quota_manager_unittest.cc13
-rw-r--r--chromium/content/browser/quota/quota_reservation_manager_unittest.cc1
-rw-r--r--chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc6
-rw-r--r--chromium/content/browser/quota/storage_monitor_unittest.cc2
-rw-r--r--chromium/content/browser/quota/usage_tracker_unittest.cc2
-rw-r--r--chromium/content/browser/quota_dispatcher_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/DEPS7
-rw-r--r--chromium/content/browser/renderer_host/browser_compositor_view_mac.h (renamed from chromium/content/browser/compositor/browser_compositor_view_mac.h)6
-rw-r--r--chromium/content/browser/renderer_host/browser_compositor_view_mac.mm (renamed from chromium/content/browser/compositor/browser_compositor_view_mac.mm)14
-rw-r--r--chromium/content/browser/renderer_host/clipboard_message_filter.cc4
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.cc146
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.h3
-rw-r--r--chromium/content/browser/renderer_host/compositor_resize_lock_aura.h2
-rw-r--r--chromium/content/browser/renderer_host/database_message_filter.cc9
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host.cc (renamed from chromium/content/browser/compositor/delegated_frame_host.cc)532
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host.h (renamed from chromium/content/browser/compositor/delegated_frame_host.h)69
-rw-r--r--chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc60
-rw-r--r--chromium/content/browser/renderer_host/event_with_latency_info.h55
-rw-r--r--chromium/content/browser/renderer_host/event_with_latency_info_unittest.cc109
-rw-r--r--chromium/content/browser/renderer_host/font_utils_linux.cc40
-rw-r--r--chromium/content/browser/renderer_host/gpu_message_filter.cc95
-rw-r--r--chromium/content/browser/renderer_host/gpu_message_filter.h54
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.cc54
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.h7
-rw-r--r--chromium/content/browser/renderer_host/input/composited_scrolling_browsertest.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.cc22
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.h2
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc25
-rw-r--r--chromium/content/browser/renderer_host/input/input_router.h4
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_client.h7
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.cc150
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.h41
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc5
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc109
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.cc8
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.h3
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc288
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.h110
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc547
-rw-r--r--chromium/content/browser/renderer_host/input/non_blocking_event_browsertest.cc218
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc47
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h2
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc284
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture.h2
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller.h2
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc41
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc45
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pointer_action.h15
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc3
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_browsertest.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.cc3
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc7
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.cc24
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.h3
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc98
-rw-r--r--chromium/content/browser/renderer_host/input/touch_input_browsertest.cc101
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc299
-rw-r--r--chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc78
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_android.h37
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc169
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm9
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm188
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.cc110
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.h5
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc8
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc10
-rw-r--r--chromium/content/browser/renderer_host/media/OWNERS4
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_debug_writer.cc166
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_debug_writer.h28
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_debug_writer_unittest.cc270
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.h5
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc17
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc84
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.h8
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc11
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_sync_writer.h4
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc10
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_device_enumerator.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_device_enumerator.h4
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.cc102
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.h12
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc20
-rw-r--r--chromium/content/browser/renderer_host/media/audio_sync_reader.cc22
-rw-r--r--chromium/content/browser/renderer_host/media/audio_sync_reader.h7
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc11
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.cc159
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.h26
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc22
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc14
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc24
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h13
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc67
-rw-r--r--chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc451
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h55
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc187
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.cc28
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.h13
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h3
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc80
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_client.cc108
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_client.h35
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_client_unittest.cc69
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc26
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h23
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.cc21
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.h4
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc11
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.cc184
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.h65
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc20
-rw-r--r--chromium/content/browser/renderer_host/media/webrtc_identity_service_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc20
-rw-r--r--chromium/content/browser/renderer_host/memory_benchmark_message_filter.cc41
-rw-r--r--chromium/content/browser/renderer_host/memory_benchmark_message_filter.h31
-rw-r--r--chromium/content/browser/renderer_host/native_web_keyboard_event_android.cc49
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.cc90
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.h8
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc23
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h11
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.cc430
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.h27
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc17
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc1
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc9
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h1
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.cc13
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.h1
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc386
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h1
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc12
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc15
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h1
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc5
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc15
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc21
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc31
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/quota_reservation.cc1
-rw-r--r--chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc1
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.cc134
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.h16
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.cc469
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.h52
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_factory.cc3
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_factory.h16
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.cc85
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.h40
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.cc26
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.h7
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.cc7
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.h31
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.cc181
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.h50
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc205
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_input_event_router.h66
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_owner_delegate.h4
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_unittest.cc16
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.cc425
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.h40
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.cc476
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.h64
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc915
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.cc405
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.h94
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base_observer.cc14
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base_observer.h32
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc7
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.h50
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.mm365
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm118
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mus.cc34
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mus.h13
-rw-r--r--chromium/content/browser/renderer_host/resize_lock.cc (renamed from chromium/content/browser/compositor/resize_lock.cc)5
-rw-r--r--chromium/content/browser/renderer_host/resize_lock.h (renamed from chromium/content/browser/compositor/resize_lock.h)6
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.cc63
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.h8
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm3
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_message_filter.h2
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_message_filter.mm11
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura.cc16
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc8
-rw-r--r--chromium/content/browser/renderer_host/websocket_blob_sender.cc284
-rw-r--r--chromium/content/browser/renderer_host/websocket_blob_sender.h139
-rw-r--r--chromium/content/browser/renderer_host/websocket_blob_sender_unittest.cc446
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.cc31
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.h29
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.cc206
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.h10
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper.cc2
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper_unittest.cc3
-rw-r--r--chromium/content/browser/resource_context_impl.cc10
-rw-r--r--chromium/content/browser/resources/gpu/browser_bridge.js17
-rw-r--r--chromium/content/browser/resources/gpu/info_view.html15
-rw-r--r--chromium/content/browser/resources/gpu/info_view.js19
-rw-r--r--chromium/content/browser/resources/media/OWNERS4
-rw-r--r--chromium/content/browser/resources/media/dump_creator.js24
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.html5
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.js2
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc18
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_win.cc133
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_win.h30
-rw-r--r--chromium/content/browser/security_exploit_browsertest.cc136
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.cc277
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.h36
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc199
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.cc101
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.h41
-rw-r--r--chromium/content/browser/service_worker/foreign_fetch_request_handler.cc25
-rw-r--r--chromium/content/browser/service_worker/foreign_fetch_request_handler.h5
-rw-r--r--chromium/content/browser/service_worker/link_header_support.cc311
-rw-r--r--chromium/content/browser/service_worker/link_header_support.h38
-rw-r--r--chromium/content/browser/service_worker/link_header_support_unittest.cc410
-rw-r--r--chromium/content/browser/service_worker/service_worker_browsertest.cc400
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc43
-rw-r--r--chromium/content/browser/service_worker/service_worker_client_utils.cc138
-rw-r--r--chromium/content/browser/service_worker/service_worker_client_utils.h14
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.cc84
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.h26
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_observer.h2
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.cc4
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc27
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.cc14
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.h3
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.cc73
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.h33
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc31
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.h7
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc21
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.cc15
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.h3
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.proto1
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_task_manager.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_unittest.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.h18
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host.cc428
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host.h78
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc257
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc81
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h14
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle_unittest.cc21
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.cc10
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.h5
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.cc81
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.cc3
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_unittest.cc132
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.cc264
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.h80
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.cc65
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.h12
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc11
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.cc106
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.h28
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc2
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc53
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.cc101
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.h10
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.cc34
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.h14
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.cc9
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.h6
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.cc58
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.h20
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage_unittest.cc271
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.cc48
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.h27
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc54
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.cc800
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.h225
-rw-r--r--chromium/content/browser/service_worker/service_worker_version_unittest.cc563
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc27
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.h11
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc1
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.cc17
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.h5
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance.cc3
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance.h6
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc19
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_message_filter.cc17
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_message_filter.h6
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.cc18
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.h8
-rw-r--r--chromium/content/browser/shared_worker/worker_browsertest.cc6
-rw-r--r--chromium/content/browser/site_instance_impl.cc52
-rw-r--r--chromium/content/browser/site_instance_impl.h50
-rw-r--r--chromium/content/browser/site_instance_impl_unittest.cc355
-rw-r--r--chromium/content/browser/site_per_process_browsertest.cc1853
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.cc6
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.h1
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.cc9
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.h1
-rw-r--r--chromium/content/browser/storage_partition_impl.cc73
-rw-r--r--chromium/content/browser/storage_partition_impl.h37
-rw-r--r--chromium/content/browser/storage_partition_impl_map.cc52
-rw-r--r--chromium/content/browser/streams/stream_url_request_job.cc33
-rw-r--r--chromium/content/browser/streams/stream_url_request_job.h5
-rw-r--r--chromium/content/browser/system_message_window_win.cc164
-rw-r--r--chromium/content/browser/system_message_window_win.h51
-rw-r--r--chromium/content/browser/system_message_window_win_unittest.cc45
-rw-r--r--chromium/content/browser/theme_helper_mac.mm44
-rw-r--r--chromium/content/browser/top_document_isolation_browsertest.cc571
-rw-r--r--chromium/content/browser/tracing/BUILD.gn2
-rw-r--r--chromium/content/browser/tracing/DEPS1
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_impl.cc8
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_impl.h1
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_unittest.cc38
-rw-r--r--chromium/content/browser/tracing/background_tracing_manager_impl.cc4
-rw-r--r--chromium/content/browser/tracing/battor_power_trace_provider.cc31
-rw-r--r--chromium/content/browser/tracing/battor_power_trace_provider.h31
-rw-r--r--chromium/content/browser/tracing/etw_system_event_consumer_win.cc18
-rw-r--r--chromium/content/browser/tracing/etw_system_event_consumer_win.h5
-rw-r--r--chromium/content/browser/tracing/power_tracing_agent.cc182
-rw-r--r--chromium/content/browser/tracing/power_tracing_agent.h61
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.cc47
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.h8
-rw-r--r--chromium/content/browser/tracing/tracing_controller_browsertest.cc170
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.cc494
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.h55
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc7
-rw-r--r--chromium/content/browser/tracing/tracing_ui.cc77
-rw-r--r--chromium/content/browser/tracing/tracing_ui.h1
-rw-r--r--chromium/content/browser/udev_linux.cc66
-rw-r--r--chromium/content/browser/udev_linux.h97
-rw-r--r--chromium/content/browser/utility_process_host_impl.cc67
-rw-r--r--chromium/content/browser/utility_process_host_impl.h7
-rw-r--r--chromium/content/browser/vr/android/cardboard/cardboard_vr_device.cc36
-rw-r--r--chromium/content/browser/vr/android/cardboard/cardboard_vr_device.h4
-rw-r--r--chromium/content/browser/vr/vr_device.h4
-rw-r--r--chromium/content/browser/vr/vr_device_manager.cc9
-rw-r--r--chromium/content/browser/vr/vr_device_manager.h12
-rw-r--r--chromium/content/browser/vr/vr_device_manager_unittest.cc10
-rw-r--r--chromium/content/browser/wake_lock/wake_lock_browsertest.cc8
-rw-r--r--chromium/content/browser/wake_lock/wake_lock_service_context.cc6
-rw-r--r--chromium/content/browser/wake_lock/wake_lock_service_context.h2
-rw-r--r--chromium/content/browser/wake_lock/wake_lock_service_impl.cc2
-rw-r--r--chromium/content/browser/wake_lock/wake_lock_service_impl.h6
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc8
-rw-r--r--chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc8
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.cc93
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.h14
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.cc777
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.h95
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_browsertest.cc250
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_unittest.cc106
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.cc232
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.h14
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc2
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.h5
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.mm69
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mus.cc1
-rw-r--r--chromium/content/browser/web_contents/web_drag_dest_mac.mm4
-rw-r--r--chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm76
-rw-r--r--chromium/content/browser/web_contents/web_drag_source_mac.mm8
-rw-r--r--chromium/content/browser/web_contents/web_drag_source_mac_unittest.mm22
-rw-r--r--chromium/content/browser/webui/OWNERS1
-rw-r--r--chromium/content/browser/webui/content_web_ui_controller_factory.cc2
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.cc7
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.cc62
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.h12
-rw-r--r--chromium/content/browser/webui/web_ui_impl.h1
-rw-r--r--chromium/content/browser/webui/web_ui_mojo_browsertest.cc34
-rw-r--r--chromium/content/browser/zygote_host/zygote_communication_linux.cc437
-rw-r--r--chromium/content/browser/zygote_host/zygote_communication_linux.h93
-rw-r--r--chromium/content/browser/zygote_host/zygote_handle_linux.cc22
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.cc512
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.h89
1131 files changed, 56938 insertions, 35618 deletions
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn
index 4d66f86c09f..69f627a723b 100644
--- a/chromium/content/browser/BUILD.gn
+++ b/chromium/content/browser/BUILD.gn
@@ -10,150 +10,135 @@ import("//media/media_options.gni")
source_set("browser") {
# Only the public target should depend on this. All other targets (even
# internal content ones) should depend on the public one.
- visibility = [ "//content/public/browser:browser_sources" ]
+ visibility = [
+ ":for_content_tests", # See top of //content/BUILD.gn for why.
+ "//content/public/browser:browser_sources",
+ ]
configs += [
"//build/config:precompiled_headers",
+ "//content:content_implementation",
"//content/public/common:mojo_shell_client",
+ "//third_party/WebKit/public:debug_devtools",
+ "//v8:external_startup_data",
]
defines = []
libs = []
ldflags = []
- # Shared deps. See also non-iOS deps below.
deps = [
"//base",
"//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//cc",
+ "//cc/surfaces",
+ "//components/filesystem:lib",
+ "//components/leveldb:lib",
"//components/mime_util",
+ "//components/profile_service:lib",
+ "//components/scheduler:common",
+ "//components/tracing",
+ "//components/tracing:startup_tracing",
"//components/url_formatter",
"//content:resources",
+ "//content/app/resources",
+ "//content/app/strings",
"//content/browser/background_sync:background_sync_proto",
"//content/browser/cache_storage:cache_storage_proto",
+ "//content/browser/devtools:gen_devtools_protocol_handler",
+ "//content/browser/devtools:resources",
"//content/browser/notifications:notification_proto",
"//content/browser/service_worker:service_worker_proto",
"//content/browser/speech/proto",
+ "//content/common",
"//content/public/common:common_sources",
"//content/public/common:mojo_bindings",
"//crypto",
"//device/battery",
+ "//device/bluetooth",
"//device/vibration",
+ "//gin",
"//google_apis",
+ "//gpu",
+ "//gpu/command_buffer/client:gles2_implementation",
+ "//ipc/mojo",
+ "//media",
+ "//media/midi",
"//mojo/common",
+ "//mojo/common:url_type_converters",
+ "//mojo/converters/geometry",
"//mojo/public/cpp/bindings",
+ "//mojo/public/js",
"//mojo/shell",
- "//mojo/shell/package_manager",
"//mojo/shell/public/cpp:cpp_for_chromium",
"//mojo/shell/public/interfaces",
+ "//mojo/shell/runner/common",
+ "//mojo/shell/runner/host:lib",
"//net",
"//net:extras",
"//skia",
+ "//skia/public",
"//sql",
+ "//storage/browser",
+ "//storage/common",
+
+ # TODO(brettw) bug 582206: Blink should not be used in the browser
+ # process. This is required by devtools' input_handler.cc which calls
+ # WebKeyboardEvent::setKeyIdentifierFromWindowsKeyCode
+ "//third_party/WebKit/public:blink",
"//third_party/WebKit/public:blink_headers",
+ "//third_party/WebKit/public:image_resources",
+ "//third_party/WebKit/public:resources",
+ "//third_party/angle:commit_id",
+ "//third_party/icu",
"//third_party/kasko:kasko_features",
- "//third_party/npapi",
+ "//third_party/leveldatabase",
+ "//third_party/libyuv",
"//third_party/re2",
+ "//third_party/webrtc",
+ "//third_party/webrtc/base:rtc_base",
+ "//third_party/webrtc/modules/desktop_capture:primitives",
"//third_party/zlib",
"//third_party/zlib:zip",
"//ui/accessibility",
"//ui/accessibility:ax_gen",
"//ui/base",
"//ui/base/ime",
+ "//ui/display",
"//ui/events",
"//ui/events:gesture_detection",
+ "//ui/events/blink",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/gl",
"//ui/native_theme",
"//ui/resources",
+ "//ui/shell_dialogs",
"//ui/snapshot",
+ "//ui/surface",
+ "//ui/touch_selection",
]
- if (is_ios) {
- # iOS doesn't get the normal file list and only takes these whitelisted
- # files.
- sources = [
- "browser_context.cc",
- "browser_main_loop.cc",
- "browser_main_runner.cc",
- "browser_process_sub_thread.cc",
- "browser_thread_impl.cc",
- "browser_url_handler_impl.cc",
- "cert_store_impl.cc",
- "download/download_create_info.cc",
- "notification_service_impl.cc",
- "signed_certificate_timestamp_store_impl.cc",
- "user_metrics.cc",
- "web_contents/navigation_entry_impl.cc",
- ]
- } else {
- # Normal non-iOS sources get everything.
- sources = rebase_path(content_browser_gypi_values.private_browser_sources,
- ".",
- "//content")
-
- # TODO(GYP) these generated files are listed as sources in content_browser.
- # This is a bit suspicious. The GN grit template will make a source set
- # containing the generated code so it should be sufficient to just depend
- # on the grit rule. But maybe some of these will need to be added?
- #
- # Need this annoying rebase_path call to match what happened with the
- # sources.
- sources -= rebase_path(
- [
- "$root_gen_dir/blink/grit/devtools_resources.h",
- "$root_gen_dir/blink/grit/devtools_resources_map.cc",
- "$root_gen_dir/blink/grit/devtools_resources_map.h",
- "$root_gen_dir/content/browser/tracing/grit/tracing_resources.h",
- "$root_gen_dir/ui/resources/grit/webui_resources_map.cc",
- ],
- ".")
-
- sources += [
- "mojo/mojo_shell_client_host.cc",
- "mojo/mojo_shell_client_host.h",
- "mojo/renderer_capability_filter.cc",
- ]
-
- # Non-iOS deps.
- deps += [
- "//cc",
- "//cc/surfaces",
- "//components/scheduler:common",
- "//content/app/resources",
- "//content/app/strings",
- "//content/browser/devtools:gen_devtools_protocol_handler",
- "//content/browser/devtools:resources",
- "//content/common:mojo_bindings",
- "//content/public/common:mojo_bindings",
- "//device/bluetooth",
- "//gin",
- "//mojo/common:url_type_converters",
- "//mojo/converters/geometry",
- "//mojo/public/cpp/bindings",
- "//mojo/public/js",
- "//mojo/shell/public/interfaces",
- "//skia/public",
- "//storage/browser",
- "//storage/common",
- "//third_party/WebKit/public:image_resources",
- "//third_party/WebKit/public:resources",
- "//third_party/angle:commit_id",
- "//third_party/icu",
- "//third_party/leveldatabase",
- "//third_party/libyuv",
- "//ui/events/blink",
- "//ui/resources",
- "//ui/surface",
- "//ui/touch_selection",
- ]
-
- configs += [ "//v8:external_startup_data" ]
- }
-
- configs += [
- "//content:content_implementation",
- "//third_party/WebKit/public:debug_devtools",
- ]
+ sources = rebase_path(content_browser_gypi_values.private_browser_sources,
+ ".",
+ "//content")
+
+ # TODO(GYP) these generated files are listed as sources in content_browser.
+ # This is a bit suspicious. The GN grit template will make a source set
+ # containing the generated code so it should be sufficient to just depend
+ # on the grit rule. But maybe some of these will need to be added?
+ #
+ # Need this annoying rebase_path call to match what happened with the
+ # sources.
+ sources -= rebase_path(
+ [
+ "$root_gen_dir/blink/grit/devtools_resources.h",
+ "$root_gen_dir/blink/grit/devtools_resources_map.cc",
+ "$root_gen_dir/blink/grit/devtools_resources_map.h",
+ "$root_gen_dir/content/browser/tracing/grit/tracing_resources.h",
+ "$root_gen_dir/ui/resources/grit/webui_resources_map.cc",
+ ],
+ ".")
if (toolkit_views) {
deps += [ "//ui/events" ]
@@ -176,32 +161,37 @@ source_set("browser") {
}
# TODO(GYP)
- # ['OS!="ios" and chrome_multiple_dll!=1', {
+ # [chrome_multiple_dll!=1', {
# 'dependencies': [
# '../third_party/WebKit/public/blink.gyp:blink',
# ],
# }],
- if (!is_mac && !is_ios) {
+ if (!is_mac) {
deps += [ "//sandbox" ]
}
- if (!is_android && !is_ios) {
+ if (!is_android) {
deps += [ "//content/browser/tracing:resources" ]
}
+ if ((use_udev && is_posix) || is_mac || is_win) {
+ deps += [ "//tools/battor_agent:battor_agent_lib" ]
+ sources += [
+ "tracing/power_tracing_agent.cc",
+ "tracing/power_tracing_agent.h",
+ ]
+ }
if (enable_webrtc) {
sources += rebase_path(content_browser_gypi_values.webrtc_browser_sources,
".",
"//content")
- deps += [ "//jingle:jingle_glue" ]
- if (is_linux) {
- deps += [ "//third_party/libjingle:libjingle_webrtc" ]
- }
+ deps += [
+ "//jingle:jingle_glue",
+ "//third_party/libjingle:libjingle_webrtc",
+ ]
if (is_linux || is_mac || is_win) {
sources += [
"media/capture/desktop_capture_device.cc",
"media/capture/desktop_capture_device.h",
- "media/capture/desktop_capture_device_uma_types.cc",
- "media/capture/desktop_capture_device_uma_types.h",
]
if (use_aura) {
sources += [
@@ -235,6 +225,7 @@ source_set("browser") {
"dinput8.lib",
"dwmapi.lib",
"dxguid.lib",
+ "imm32.lib",
"oleacc.lib",
"sensorsapi.lib",
"portabledeviceguids.lib",
@@ -251,20 +242,13 @@ source_set("browser") {
}
if (use_udev) {
- deps += [ "//device/udev_linux" ]
- } else {
- # Remove udev-specific sources.
- sources -= [
- "device_monitor_udev.cc",
- "device_monitor_udev.h",
+ deps += [
+ "//device/udev_linux",
+ "//media/capture",
]
+ } else {
if (is_linux) {
- # Already filtered out on non-Linux.
- sources -= [
- "gamepad/gamepad_platform_data_fetcher_linux.cc",
- "udev_linux.cc",
- "udev_linux.h",
- ]
+ sources -= [ "gamepad/gamepad_platform_data_fetcher_linux.cc" ]
}
}
@@ -305,6 +289,9 @@ source_set("browser") {
if (use_x11) {
configs += [ "//build/config/linux:x11" ]
+ if (!is_chromeos) {
+ configs += [ "//build/config/linux:xscrnsaver" ]
+ }
deps += [ "//ui/gfx/x" ]
}
@@ -338,6 +325,10 @@ source_set("browser") {
sources += rebase_path(content_browser_gypi_values.android_browser_sources,
".",
"//content")
+ sources += rebase_path(
+ content_browser_gypi_values.android_in_process_browser_sources,
+ ".",
+ "//content")
sources -= [
"browser_ipc_logging.cc",
"device_sensors/data_fetcher_shared_memory_default.cc",
@@ -345,8 +336,10 @@ source_set("browser") {
"geolocation/network_location_provider.h",
"geolocation/network_location_request.cc",
"geolocation/network_location_request.h",
+ "media/session/media_session_delegate_default.cc",
"power_usage_monitor_impl.cc",
"power_usage_monitor_impl.h",
+ "renderer_host/begin_frame_observer_proxy.cc",
"tracing/tracing_ui.cc",
"tracing/tracing_ui.h",
@@ -372,26 +365,13 @@ source_set("browser") {
"speech/speech_recognizer_impl.cc",
"speech/speech_recognizer_impl.h",
]
-
- if (!use_aura) {
- sources += rebase_path(
- content_browser_gypi_values.android_non_aura_browser_sources,
- ".",
- "//content")
- sources += rebase_path(
- content_browser_gypi_values.android_in_process_browser_sources,
- ".",
- "//content")
- sources -= [ "renderer_host/begin_frame_observer_proxy.cc" ]
- deps += [ "//ui/android" ]
- }
-
deps -= [ "//device/battery" ]
deps += [
"//content/public/android:jni",
"//media",
"//media/mojo/interfaces",
"//mojo/android:libsystem_java",
+ "//ui/android",
]
defines += [ "APPCACHE_USE_SIMPLE_CACHE" ]
libs += [ "jnigraphics" ]
@@ -409,18 +389,10 @@ source_set("browser") {
"//third_party/sudden_motion_sensor",
"//ui/accelerated_widget_mac",
]
- libs += [
- "bsm",
- "QTKit.framework",
- ]
}
if (is_chromeos) {
sources -= [ "device_sensors/data_fetcher_shared_memory_default.cc" ]
- sources += [
- "gpu/gpu_arc_video_service_host.cc",
- "gpu/gpu_arc_video_service_host.h",
- ]
deps += [
"//chromeos",
"//chromeos:power_manager_proto",
@@ -506,13 +478,6 @@ source_set("browser") {
deps += [ "//ui/compositor" ]
}
- if (!is_ios) {
- sources += [
- "compositor/surface_utils.cc",
- "compositor/surface_utils.h",
- ]
- }
-
if (enable_web_speech) {
deps += [ "//third_party/flac" ]
}
@@ -532,12 +497,8 @@ source_set("browser") {
deps += [ "//third_party/boringssl" ]
}
- if (enable_mojo_media != "none") {
- configs += [ "//media/mojo/services:enable_mojo_media_config" ]
- }
-
- if (enable_mojo_media == "browser") {
- deps += [ "//media/mojo/services:application" ]
+ if (enable_mojo_media) {
+ configs += [ "//media/mojo/services:mojo_media_config" ]
}
if (enable_webvr) {
@@ -559,3 +520,13 @@ source_set("browser") {
]
}
}
+
+# See comment at the top of //content/BUILD.gn for how this works.
+group("for_content_tests") {
+ visibility = [ "//content/test/*" ]
+ if (!is_component_build) {
+ public_deps = [
+ ":browser",
+ ]
+ }
+}
diff --git a/chromium/content/browser/DEPS b/chromium/content/browser/DEPS
index 5e33c93e2de..42e02ee046e 100644
--- a/chromium/content/browser/DEPS
+++ b/chromium/content/browser/DEPS
@@ -1,10 +1,12 @@
include_rules = [
# Allow inclusion of specific components that we depend on. We may only
# depend on components which we share with the mojo html_viewer.
- "+components/arc",
+ "+components/filesystem",
+ "+components/leveldb",
"+components/mime_util",
"+components/mus/public/interfaces",
"+components/mus/public",
+ "+components/profile_service",
"+components/scheduler/common",
"+components/tracing",
"+components/url_formatter",
@@ -16,11 +18,12 @@ include_rules = [
"+gin/v8_initializer.h",
"+media/media_features.h",
"+media/audio", # For audio input for speech input feature.
+ "+media/capture", # For Video Device monitoring in Mac.
"+media/base", # For Android JNI registration.
+ "+media/capture", # For Device Monitoring
"+media/filters", # For reporting GPU decoding UMA.
"+media/midi", # For Web MIDI API
"+media/mojo", # For mojo media services.
- "+media/capture/video", # For Video Device monitoring in Mac.
"+mojo",
"+sql",
"+ui/aura_extra",
@@ -49,6 +52,7 @@ include_rules = [
# No inclusion of WebKit from the browser, other than strictly enum/POD,
# header-only types, and some selected common code.
"-third_party/WebKit",
+ "+third_party/WebKit/public/platform/WebAddressSpace.h",
"+third_party/WebKit/public/platform/WebCircularGeofencingRegion.h",
"+third_party/WebKit/public/platform/WebCursorInfo.h",
"+third_party/WebKit/public/platform/WebDisplayMode.h",
@@ -61,9 +65,12 @@ include_rules = [
"+third_party/WebKit/public/platform/WebReferrerPolicy.h",
"+third_party/WebKit/public/platform/WebScreenInfo.h",
"+third_party/WebKit/public/platform/WebString.h",
+ "+third_party/WebKit/public/platform/modules/geolocation/geolocation.mojom.h",
"+third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h",
"+third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h",
"+third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h",
+ "+third_party/WebKit/public/platform/modules/permissions/permission.mojom.h",
+ "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h",
"+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
"+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
"+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
@@ -96,6 +103,10 @@ include_rules = [
"+third_party/WebKit/public/web/WebTreeScopeType.h",
"+third_party/WebKit/public/web/mac/WebScrollbarTheme.h",
+ # Until we define where mojo interfaces should live in blink we whitelist each
+ # one separately.
+ "+third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
+
# DO NOT ADD ANY CHROME OR COMPONENTS INCLUDES HERE!!!
# See https://sites.google.com/a/chromium.org/dev/developers/content-module
# for more information.
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
index fa767494fb4..cb40bfbb850 100644
--- a/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -287,7 +287,7 @@ HRESULT AccessibilityEventRecorderWin::AccessibleObjectFromWindowWrapper(
if (accessibility_hwnd != hwnd)
return E_FAIL;
- IAccessible* obj = manager_->GetRoot()->ToBrowserAccessibilityWin();
+ IAccessible* obj = ToBrowserAccessibilityWin(manager_->GetRoot());
obj->AddRef();
*ppv_object = obj;
return S_OK;
diff --git a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index a8bd5412df5..597631cc221 100644
--- a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -132,7 +132,6 @@ IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
const ui::AXNode* button = button_container->ChildAtIndex(0);
EXPECT_EQ(ui::AX_ROLE_BUTTON, button->data().role);
- EXPECT_TRUE(button->data().state >> ui::AX_STATE_FOCUSED & 1);
}
#if defined(OS_ANDROID)
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
index 12321df619d..24fce4d93ce 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_android.cc
@@ -127,6 +127,7 @@ void AccessibilityTreeFormatterAndroid::AddProperties(
// String attributes.
dict->SetString("name", android_node->GetText());
+ dict->SetString("role_description", android_node->GetRoleDescription());
// Int attributes.
dict->SetInteger("item_index", android_node->GetItemIndex());
@@ -171,6 +172,15 @@ base::string16 AccessibilityTreeFormatterAndroid::ToString(
dict.GetString("class", &class_value);
WriteAttribute(true, base::UTF16ToUTF8(class_value), &line);
+ std::string role_description;
+ dict.GetString("role_description", &role_description);
+ if (!role_description.empty()) {
+ WriteAttribute(
+ true,
+ StringPrintf("role_description='%s'", role_description.c_str()),
+ &line);
+ }
+
for (unsigned i = 0; i < arraysize(BOOL_ATTRIBUTES); i++) {
const char* attribute_name = BOOL_ATTRIBUTES[i];
bool value;
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
index 4ebb1c0e46d..ef954c9e26c 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
@@ -46,8 +46,7 @@ void AccessibilityTreeFormatterAuraLinux::AddProperties(
base::DictionaryValue* dict) {
dict->SetInteger("id", node.GetId());
BrowserAccessibilityAuraLinux* acc_obj =
- const_cast<BrowserAccessibility*>(&node)
- ->ToBrowserAccessibilityAuraLinux();
+ ToBrowserAccessibilityAuraLinux(const_cast<BrowserAccessibility*>(&node));
AtkObject* atk_object = acc_obj->GetAtkObject();
AtkRole role = acc_obj->atk_role();
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index 27b9c9fa1cd..6796770f2a5 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -7,6 +7,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
+#include "ui/gfx/transform.h"
namespace content {
@@ -19,13 +20,19 @@ AccessibilityTreeFormatterBlink::~AccessibilityTreeFormatterBlink() {
uint32_t AccessibilityTreeFormatterBlink::ChildCount(
const BrowserAccessibility& node) const {
- return node.InternalChildCount();
+ if (node.HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID))
+ return node.PlatformChildCount();
+ else
+ return node.InternalChildCount();
}
BrowserAccessibility* AccessibilityTreeFormatterBlink::GetChild(
const BrowserAccessibility& node,
uint32_t i) const {
- return node.InternalGetChild(i);
+ if (node.HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID))
+ return node.PlatformGetChild(i);
+ else
+ return node.InternalGetChild(i);
}
void AccessibilityTreeFormatterBlink::AddProperties(
@@ -33,12 +40,23 @@ void AccessibilityTreeFormatterBlink::AddProperties(
base::DictionaryValue* dict) {
dict->SetInteger("id", node.GetId());
- dict->SetString("role", ui::ToString(node.GetData().role));
+ dict->SetString("internalRole", ui::ToString(node.GetData().role));
- dict->SetInteger("boundsX", node.GetData().location.x());
- dict->SetInteger("boundsY", node.GetData().location.y());
- dict->SetInteger("boundsWidth", node.GetData().location.width());
- dict->SetInteger("boundsHeight", node.GetData().location.height());
+ gfx::Rect bounds = node.GetData().location;
+ dict->SetInteger("boundsX", bounds.x());
+ dict->SetInteger("boundsY", bounds.y());
+ dict->SetInteger("boundsWidth", bounds.width());
+ dict->SetInteger("boundsHeight", bounds.height());
+
+ gfx::Rect page_bounds = node.GetLocalBoundsRect();
+ dict->SetInteger("pageBoundsX", page_bounds.x());
+ dict->SetInteger("pageBoundsY", page_bounds.y());
+ dict->SetInteger("pageBoundsWidth", page_bounds.width());
+ dict->SetInteger("pageBoundsHeight", page_bounds.height());
+
+ dict->SetBoolean("transform",
+ node.GetData().transform &&
+ !node.GetData().transform->IsIdentity());
for (int state_index = ui::AX_STATE_NONE;
state_index <= ui::AX_STATE_LAST;
@@ -106,7 +124,7 @@ base::string16 AccessibilityTreeFormatterBlink::ToString(
}
base::string16 role_value;
- dict.GetString("role", &role_value);
+ dict.GetString("internalRole", &role_value);
WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
for (int state_index = ui::AX_STATE_NONE;
@@ -127,6 +145,19 @@ base::string16 AccessibilityTreeFormatterBlink::ToString(
FormatCoordinates("size", "boundsWidth", "boundsHeight", dict),
&line);
+ WriteAttribute(false,
+ FormatCoordinates("pageLocation",
+ "pageBoundsX", "pageBoundsY", dict),
+ &line);
+ WriteAttribute(false,
+ FormatCoordinates("pageSize",
+ "pageBoundsWidth", "pageBoundsHeight", dict),
+ &line);
+
+ bool transform;
+ if (dict.GetBoolean("transform", &transform) && transform)
+ WriteAttribute(false, "transform", &line);
+
for (int attr_index = ui::AX_STRING_ATTRIBUTE_NONE;
attr_index <= ui::AX_STRING_ATTRIBUTE_LAST;
++attr_index) {
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index 0721a9e991f..48b9d883167 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -41,15 +41,15 @@ scoped_ptr<base::DictionaryValue> PopulatePosition(
// based on the lower-left corner of the object. To make this easier and less
// confusing, convert it to local window coordinates using the top-left
// corner when dumping the position.
- BrowserAccessibility* root = node.manager()->GetRoot();
- BrowserAccessibilityCocoa* cocoa_root = root->ToBrowserAccessibilityCocoa();
+ BrowserAccessibility* root = node.manager()->GetRootManager()->GetRoot();
+ BrowserAccessibilityCocoa* cocoa_root = ToBrowserAccessibilityCocoa(root);
NSPoint root_position = [[cocoa_root position] pointValue];
NSSize root_size = [[cocoa_root size] sizeValue];
int root_top = -static_cast<int>(root_position.y + root_size.height);
int root_left = static_cast<int>(root_position.x);
BrowserAccessibilityCocoa* cocoa_node =
- const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(const_cast<BrowserAccessibility*>(&node));
NSPoint node_position = [[cocoa_node position] pointValue];
NSSize node_size = [[cocoa_node size] sizeValue];
@@ -221,7 +221,7 @@ void AccessibilityTreeFormatterMac::AddProperties(
base::DictionaryValue* dict) {
dict->SetInteger("id", node.GetId());
BrowserAccessibilityCocoa* cocoa_node =
- const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(const_cast<BrowserAccessibility*>(&node));
NSArray* supportedAttributes = [cocoa_node accessibilityAttributeNames];
string role = SysNSStringToUTF8(
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
index cbece3a2553..eaf4fc8f4aa 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -54,36 +54,35 @@ AccessibilityTreeFormatterWin::AccessibilityTreeFormatterWin() {
AccessibilityTreeFormatterWin::~AccessibilityTreeFormatterWin() {
}
-const char* ALL_ATTRIBUTES[] = {
- "name",
- "value",
- "states",
- "attributes",
- "role_name",
- "ia2_hypertext",
- "currentValue",
- "minimumValue",
- "maximumValue",
- "description",
- "default_action",
- "keyboard_shortcut",
- "location",
- "size",
- "index_in_parent",
- "n_relations",
- "group_level",
- "similar_items_in_group",
- "position_in_group",
- "table_rows",
- "table_columns",
- "row_index",
- "column_index",
- "n_characters",
- "caret_offset",
- "n_selections",
- "selection_start",
- "selection_end"
-};
+const char* ALL_ATTRIBUTES[] = {"name",
+ "value",
+ "states",
+ "attributes",
+ "text_attributes",
+ "role_name",
+ "ia2_hypertext",
+ "currentValue",
+ "minimumValue",
+ "maximumValue",
+ "description",
+ "default_action",
+ "keyboard_shortcut",
+ "location",
+ "size",
+ "index_in_parent",
+ "n_relations",
+ "group_level",
+ "similar_items_in_group",
+ "position_in_group",
+ "table_rows",
+ "table_columns",
+ "row_index",
+ "column_index",
+ "n_characters",
+ "caret_offset",
+ "n_selections",
+ "selection_start",
+ "selection_end"};
namespace {
@@ -157,7 +156,7 @@ void AccessibilityTreeFormatterWin::AddProperties(
const BrowserAccessibility& node, base::DictionaryValue* dict) {
dict->SetInteger("id", node.GetId());
BrowserAccessibilityWin* ax_object =
- const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(const_cast<BrowserAccessibility*>(&node));
DCHECK(ax_object);
VARIANT variant_self;
@@ -167,8 +166,13 @@ void AccessibilityTreeFormatterWin::AddProperties(
dict->SetString("role", IAccessible2RoleToString(ax_object->ia2_role()));
base::win::ScopedBstr temp_bstr;
- if (SUCCEEDED(ax_object->get_accName(variant_self, temp_bstr.Receive())))
- dict->SetString("name", base::string16(temp_bstr, temp_bstr.Length()));
+ if (SUCCEEDED(ax_object->get_accName(variant_self, temp_bstr.Receive()))) {
+ base::string16 name = base::string16(temp_bstr, temp_bstr.Length());
+
+ // Ignore a JAWS workaround where the name of a document is " ".
+ if (name != L" " || ax_object->ia2_role() != ROLE_SYSTEM_DOCUMENT)
+ dict->SetString("name", name);
+ }
temp_bstr.Reset();
if (SUCCEEDED(ax_object->get_accValue(variant_self, temp_bstr.Receive())))
@@ -185,17 +189,29 @@ void AccessibilityTreeFormatterWin::AddProperties(
IAccessibleStateToStringVector(ia_state, &state_strings);
IAccessible2StateToStringVector(ax_object->ia2_state(), &state_strings);
- base::ListValue* states = new base::ListValue;
- for (const auto& state_string : state_strings)
+ scoped_ptr<base::ListValue> states(new base::ListValue());
+ for (const base::string16& state_string : state_strings)
states->AppendString(base::UTF16ToUTF8(state_string));
- dict->Set("states", states);
+ dict->Set("states", std::move(states));
const std::vector<base::string16>& ia2_attributes =
ax_object->ia2_attributes();
- base::ListValue* attributes = new base::ListValue;
- for (const auto& ia2_attribute : ia2_attributes)
+ scoped_ptr<base::ListValue> attributes(new base::ListValue());
+ for (const base::string16& ia2_attribute : ia2_attributes)
attributes->AppendString(base::UTF16ToUTF8(ia2_attribute));
- dict->Set("attributes", attributes);
+ dict->Set("attributes", std::move(attributes));
+
+ ax_object->ComputeStylesIfNeeded();
+ const std::map<int, std::vector<base::string16>>& ia2_text_attributes =
+ ax_object->offset_to_text_attributes();
+ scoped_ptr<base::ListValue> text_attributes(new base::ListValue());
+ for (const auto& style_span : ia2_text_attributes) {
+ int start_offset = style_span.first;
+ text_attributes->AppendString("offset:" + base::IntToString(start_offset));
+ for (const base::string16& text_attribute : style_span.second)
+ text_attributes->AppendString(base::UTF16ToUTF8(text_attribute));
+ }
+ dict->Set("text_attributes", std::move(text_attributes));
dict->SetString("role_name", ax_object->role_name());
dict->SetString("ia2_hypertext", GetIA2Hypertext(*ax_object));
@@ -237,12 +253,12 @@ void AccessibilityTreeFormatterWin::AddProperties(
dict->SetString("help", base::string16(temp_bstr, temp_bstr.Length()));
temp_bstr.Reset();
- BrowserAccessibility* root = node.manager()->GetRoot();
+ BrowserAccessibility* root = node.manager()->GetRootManager()->GetRoot();
LONG left, top, width, height;
LONG root_left, root_top, root_width, root_height;
if (SUCCEEDED(ax_object->accLocation(
&left, &top, &width, &height, variant_self)) &&
- SUCCEEDED(root->ToBrowserAccessibilityWin()->accLocation(
+ SUCCEEDED(ToBrowserAccessibilityWin(root)->accLocation(
&root_left, &root_top, &root_width, &root_height, variant_self))) {
base::DictionaryValue* location = new base::DictionaryValue;
location->SetInteger("x", left - root_left);
@@ -340,7 +356,7 @@ base::string16 AccessibilityTreeFormatterWin::ToString(
break;
}
case base::Value::TYPE_INTEGER: {
- int int_value;
+ int int_value = 0;
value->GetAsInteger(&int_value);
WriteAttribute(false,
base::StringPrintf(L"%ls=%d",
@@ -351,7 +367,7 @@ base::string16 AccessibilityTreeFormatterWin::ToString(
break;
}
case base::Value::TYPE_DOUBLE: {
- double double_value;
+ double double_value = 0.0;
value->GetAsDouble(&double_value);
WriteAttribute(false,
base::StringPrintf(L"%ls=%.2f",
diff --git a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc b/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
deleted file mode 100644
index 12817d10b0c..00000000000
--- a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/accessibility/accessibility_tree_formatter.h"
-#include "content/browser/accessibility/browser_accessibility.h"
-#include "content/browser/accessibility/browser_accessibility_manager.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_paths.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "content/shell/browser/shell.h"
-#include "content/test/accessibility_browser_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class AndroidHitTestingBrowserTest : public ContentBrowserTest {
- public:
- AndroidHitTestingBrowserTest() {}
- ~AndroidHitTestingBrowserTest() override {}
-};
-
-IN_PROC_BROWSER_TEST_F(AndroidHitTestingBrowserTest,
- HitTestOutsideDocumentBoundsReturnsRoot) {
- NavigateToURL(shell(), GURL(url::kAboutBlankURL));
-
- // Load the page.
- AccessibilityNotificationWaiter waiter(
- shell(), AccessibilityModeComplete,
- ui::AX_EVENT_LOAD_COMPLETE);
- const char url_str[] =
- "data:text/html,"
- "<!doctype html>"
- "<html><head><title>Accessibility Test</title></head>"
- "<body>"
- "<a href='#'>"
- "This is some text in a link"
- "</a>"
- "</body></html>";
- GURL url(url_str);
- NavigateToURL(shell(), url);
- waiter.WaitForNotification();
-
- // Get the BrowserAccessibilityManager.
- WebContentsImpl* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- BrowserAccessibilityManager* manager =
- web_contents->GetRootBrowserAccessibilityManager();
-
- // Send a hit test request, and wait for the hover event in response.
- AccessibilityNotificationWaiter hover_waiter(
- shell(), AccessibilityModeComplete,
- ui::AX_EVENT_HOVER);
- manager->delegate()->AccessibilityHitTest(gfx::Point(-1, -1));
- hover_waiter.WaitForNotification();
-
- // Assert that the hover event was fired on the root of the tree.
- int hover_target_id = hover_waiter.event_target_id();
- BrowserAccessibility* hovered_node = manager->GetFromID(hover_target_id);
- ASSERT_TRUE(hovered_node != NULL);
- ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, hovered_node->GetRole());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility.cc b/chromium/content/browser/accessibility/browser_accessibility.cc
index 3c43e153fe6..fa606fc2bfe 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility.cc
@@ -15,9 +15,19 @@
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/common/accessibility_messages.h"
#include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace content {
+namespace {
+
+// Map from unique_id to BrowserAccessibility
+using UniqueIDMap = base::hash_map<int32_t, BrowserAccessibility*>;
+base::LazyInstance<UniqueIDMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER;
+
+}
+
#if !defined(PLATFORM_HAS_NATIVE_ACCESSIBILITY_IMPL)
// static
BrowserAccessibility* BrowserAccessibility::Create() {
@@ -27,10 +37,23 @@ BrowserAccessibility* BrowserAccessibility::Create() {
BrowserAccessibility::BrowserAccessibility()
: manager_(NULL),
- node_(NULL) {
+ node_(NULL),
+ unique_id_(ui::AXPlatformNode::GetNextUniqueId()) {
+ g_unique_id_map.Get()[unique_id_] = this;
}
BrowserAccessibility::~BrowserAccessibility() {
+ if (unique_id_)
+ g_unique_id_map.Get().erase(unique_id_);
+}
+
+// static
+BrowserAccessibility* BrowserAccessibility::GetFromUniqueID(int32_t unique_id) {
+ auto iter = g_unique_id_map.Get().find(unique_id);
+ if (iter == g_unique_id_map.Get().end())
+ return nullptr;
+
+ return iter->second;
}
void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
@@ -73,7 +96,7 @@ uint32_t BrowserAccessibility::PlatformChildCount() const {
BrowserAccessibilityManager* child_manager =
BrowserAccessibilityManager::FromID(
GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID));
- if (child_manager)
+ if (child_manager && child_manager->GetRoot()->GetParent() == this)
return 1;
return 0;
@@ -88,11 +111,14 @@ bool BrowserAccessibility::IsNative() const {
bool BrowserAccessibility::IsDescendantOf(
const BrowserAccessibility* ancestor) const {
- if (this == ancestor) {
+ if (!ancestor)
+ return false;
+
+ if (this == ancestor)
return true;
- } else if (GetParent()) {
+
+ if (GetParent())
return GetParent()->IsDescendantOf(ancestor);
- }
return false;
}
@@ -112,7 +138,7 @@ BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
BrowserAccessibilityManager* child_manager =
BrowserAccessibilityManager::FromID(
GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID));
- if (child_manager)
+ if (child_manager && child_manager->GetRoot()->GetParent() == this)
result = child_manager->GetRoot();
} else {
result = InternalGetChild(child_index);
@@ -132,6 +158,16 @@ bool BrowserAccessibility::PlatformIsChildOfLeaf() const {
return false;
}
+BrowserAccessibility* BrowserAccessibility::GetClosestPlatformObject() const {
+ BrowserAccessibility* platform_object =
+ const_cast<BrowserAccessibility*>(this);
+ while (platform_object && platform_object->PlatformIsChildOfLeaf())
+ platform_object = platform_object->InternalGetParent();
+
+ DCHECK(platform_object);
+ return platform_object;
+}
+
BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() const {
if (GetParent() && GetIndexInParent() > 0)
return GetParent()->InternalGetChild(GetIndexInParent() - 1);
@@ -154,7 +190,7 @@ BrowserAccessibility* BrowserAccessibility::PlatformDeepestFirstChild() const {
if (!PlatformChildCount())
return nullptr;
- auto deepest_child = PlatformGetChild(0);
+ BrowserAccessibility* deepest_child = PlatformGetChild(0);
while (deepest_child->PlatformChildCount())
deepest_child = deepest_child->PlatformGetChild(0);
@@ -165,7 +201,8 @@ BrowserAccessibility* BrowserAccessibility::PlatformDeepestLastChild() const {
if (!PlatformChildCount())
return nullptr;
- auto deepest_child = PlatformGetChild(PlatformChildCount() - 1);
+ BrowserAccessibility* deepest_child =
+ PlatformGetChild(PlatformChildCount() - 1);
while (deepest_child->PlatformChildCount()) {
deepest_child = deepest_child->PlatformGetChild(
deepest_child->PlatformChildCount() - 1);
@@ -174,6 +211,31 @@ BrowserAccessibility* BrowserAccessibility::PlatformDeepestLastChild() const {
return deepest_child;
}
+BrowserAccessibility* BrowserAccessibility::InternalDeepestFirstChild() const {
+ if (!InternalChildCount())
+ return nullptr;
+
+ BrowserAccessibility* deepest_child = InternalGetChild(0);
+ while (deepest_child->InternalChildCount())
+ deepest_child = deepest_child->InternalGetChild(0);
+
+ return deepest_child;
+}
+
+BrowserAccessibility* BrowserAccessibility::InternalDeepestLastChild() const {
+ if (!InternalChildCount())
+ return nullptr;
+
+ BrowserAccessibility* deepest_child =
+ InternalGetChild(InternalChildCount() - 1);
+ while (deepest_child->InternalChildCount()) {
+ deepest_child = deepest_child->InternalGetChild(
+ deepest_child->InternalChildCount() - 1);
+ }
+
+ return deepest_child;
+}
+
uint32_t BrowserAccessibility::InternalChildCount() const {
if (!node_ || !manager_)
return 0;
@@ -191,8 +253,9 @@ BrowserAccessibility* BrowserAccessibility::InternalGetChild(
}
BrowserAccessibility* BrowserAccessibility::GetParent() const {
- if (!node_ || !manager_)
- return NULL;
+ if (!instance_active())
+ return nullptr;
+
ui::AXNode* parent = node_->parent();
if (parent)
return manager_->GetFromAXNode(parent);
@@ -321,17 +384,25 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
int local_start = overlap_start - child_start;
int local_end = overlap_end - child_start;
+ // |local_end| and |local_start| may equal |child_length| when the caret is
+ // at the end of a text field.
+ DCHECK_GE(local_start, 0);
+ DCHECK_LE(local_start, child_length);
+ DCHECK_GE(local_end, 0);
+ DCHECK_LE(local_end, child_length);
- gfx::Rect child_rect = child->GetLocation();
- int text_direction = child->GetIntAttribute(
- ui::AX_ATTR_TEXT_DIRECTION);
const std::vector<int32_t>& character_offsets =
child->GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS);
+ if (static_cast<int>(character_offsets.size()) != child_length)
+ continue;
int start_pixel_offset =
local_start > 0 ? character_offsets[local_start - 1] : 0;
int end_pixel_offset =
local_end > 0 ? character_offsets[local_end - 1] : 0;
+ gfx::Rect child_rect = child->GetLocation();
+ auto text_direction = static_cast<ui::AXTextDirection>(
+ child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION));
gfx::Rect child_overlap_rect;
switch (text_direction) {
case ui::AX_TEXT_DIRECTION_NONE:
@@ -389,7 +460,10 @@ gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
base::string16 BrowserAccessibility::GetValue() const {
base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
- if (value.empty() && IsSimpleTextControl())
+ // Some screen readers like Jaws and older versions of VoiceOver require a
+ // value to be set in text fields with rich content, even though the same
+ // information is available on the children.
+ if (value.empty() && (IsSimpleTextControl() || IsRichTextControl()))
value = GetInnerText();
return value;
}
@@ -555,6 +629,10 @@ void BrowserAccessibility::Destroy() {
node_ = NULL;
manager_ = NULL;
+ if (unique_id_)
+ g_unique_id_map.Get().erase(unique_id_);
+ unique_id_ = 0;
+
NativeReleaseReference();
}
@@ -592,6 +670,72 @@ bool BrowserAccessibility::GetFloatAttribute(
return GetData().GetFloatAttribute(attribute, value);
}
+bool BrowserAccessibility::HasInheritedStringAttribute(
+ ui::AXStringAttribute attribute) const {
+ if (!instance_active())
+ return false;
+
+ if (GetData().HasStringAttribute(attribute))
+ return true;
+ return GetParent() && GetParent()->HasInheritedStringAttribute(attribute);
+}
+
+const std::string& BrowserAccessibility::GetInheritedStringAttribute(
+ ui::AXStringAttribute attribute) const {
+ if (!instance_active())
+ return base::EmptyString();
+
+ const BrowserAccessibility* current_object = this;
+ do {
+ if (current_object->GetData().HasStringAttribute(attribute))
+ return current_object->GetData().GetStringAttribute(attribute);
+ current_object = current_object->GetParent();
+ } while (current_object);
+ return base::EmptyString();
+}
+
+bool BrowserAccessibility::GetInheritedStringAttribute(
+ ui::AXStringAttribute attribute,
+ std::string* value) const {
+ if (!instance_active()) {
+ *value = std::string();
+ return false;
+ }
+
+ if (GetData().GetStringAttribute(attribute, value))
+ return true;
+ return GetParent() &&
+ GetParent()->GetData().GetStringAttribute(attribute, value);
+}
+
+base::string16 BrowserAccessibility::GetInheritedString16Attribute(
+ ui::AXStringAttribute attribute) const {
+ if (!instance_active())
+ return base::string16();
+
+ const BrowserAccessibility* current_object = this;
+ do {
+ if (current_object->GetData().HasStringAttribute(attribute))
+ return current_object->GetData().GetString16Attribute(attribute);
+ current_object = current_object->GetParent();
+ } while (current_object);
+ return base::string16();
+}
+
+bool BrowserAccessibility::GetInheritedString16Attribute(
+ ui::AXStringAttribute attribute,
+ base::string16* value) const {
+ if (!instance_active()) {
+ *value = base::string16();
+ return false;
+ }
+
+ if (GetData().GetString16Attribute(attribute, value))
+ return true;
+ return GetParent() &&
+ GetParent()->GetData().GetString16Attribute(attribute, value);
+}
+
bool BrowserAccessibility::HasIntAttribute(
ui::AXIntAttribute attribute) const {
return GetData().HasIntAttribute(attribute);
@@ -626,9 +770,8 @@ base::string16 BrowserAccessibility::GetString16Attribute(
return GetData().GetString16Attribute(attribute);
}
-bool BrowserAccessibility::GetString16Attribute(
- ui::AXStringAttribute attribute,
- base::string16* value) const {
+bool BrowserAccessibility::GetString16Attribute(ui::AXStringAttribute attribute,
+ base::string16* value) const {
return GetData().GetString16Attribute(attribute, value);
}
@@ -698,9 +841,7 @@ bool BrowserAccessibility::IsCellOrTableHeaderRole() const {
}
bool BrowserAccessibility::HasCaret() const {
- if (HasState(ui::AX_STATE_EDITABLE) &&
- !HasState(ui::AX_STATE_RICHLY_EDITABLE) &&
- HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) &&
+ if (IsSimpleTextControl() && HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) &&
HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) {
return true;
}
@@ -724,28 +865,51 @@ bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const {
if (!parent)
return false;
- BrowserAccessibility* grandparent = parent->GetParent();
- if (!grandparent)
- return false;
+ return parent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
+}
- return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
+bool BrowserAccessibility::IsClickable() const {
+ switch (GetRole()) {
+ case ui::AX_ROLE_BUTTON:
+ case ui::AX_ROLE_CHECK_BOX:
+ case ui::AX_ROLE_COLOR_WELL:
+ case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
+ case ui::AX_ROLE_IMAGE_MAP_LINK:
+ case ui::AX_ROLE_LINK:
+ case ui::AX_ROLE_LIST_BOX_OPTION:
+ case ui::AX_ROLE_MENU_BUTTON:
+ case ui::AX_ROLE_MENU_ITEM:
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ case ui::AX_ROLE_MENU_LIST_OPTION:
+ case ui::AX_ROLE_MENU_LIST_POPUP:
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ case ui::AX_ROLE_RADIO_BUTTON:
+ case ui::AX_ROLE_SWITCH:
+ case ui::AX_ROLE_TAB:
+ case ui::AX_ROLE_TOGGLE_BUTTON:
+ return true;
+ default:
+ return false;
+ }
}
bool BrowserAccessibility::IsControl() const {
switch (GetRole()) {
case ui::AX_ROLE_BUTTON:
- case ui::AX_ROLE_BUTTON_DROP_DOWN:
case ui::AX_ROLE_CHECK_BOX:
case ui::AX_ROLE_COLOR_WELL:
case ui::AX_ROLE_COMBO_BOX:
case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
case ui::AX_ROLE_LIST_BOX:
+ case ui::AX_ROLE_MENU:
case ui::AX_ROLE_MENU_BAR:
case ui::AX_ROLE_MENU_BUTTON:
case ui::AX_ROLE_MENU_ITEM:
case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
case ui::AX_ROLE_MENU_ITEM_RADIO:
- case ui::AX_ROLE_MENU:
+ case ui::AX_ROLE_MENU_LIST_OPTION:
+ case ui::AX_ROLE_MENU_LIST_POPUP:
case ui::AX_ROLE_POP_UP_BUTTON:
case ui::AX_ROLE_RADIO_BUTTON:
case ui::AX_ROLE_SCROLL_BAR:
@@ -763,14 +927,31 @@ bool BrowserAccessibility::IsControl() const {
}
}
+bool BrowserAccessibility::IsMenuRelated() const {
+ switch (GetRole()) {
+ case ui::AX_ROLE_MENU:
+ case ui::AX_ROLE_MENU_BAR:
+ case ui::AX_ROLE_MENU_BUTTON:
+ case ui::AX_ROLE_MENU_ITEM:
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ case ui::AX_ROLE_MENU_LIST_OPTION:
+ case ui::AX_ROLE_MENU_LIST_POPUP:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool BrowserAccessibility::IsSimpleTextControl() const {
// Time fields, color wells and spinner buttons might also use text fields as
// constituent parts, but they are not considered text fields as a whole.
switch (GetRole()) {
case ui::AX_ROLE_COMBO_BOX:
case ui::AX_ROLE_SEARCH_BOX:
- case ui::AX_ROLE_TEXT_FIELD:
return true;
+ case ui::AX_ROLE_TEXT_FIELD:
+ return !HasState(ui::AX_STATE_RICHLY_EDITABLE);
default:
return false;
}
@@ -842,39 +1023,49 @@ void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const
gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds)
const {
- // Walk up the parent chain. Every time we encounter a Web Area, offset
- // based on the scroll bars and then offset based on the origin of that
- // nested web area.
- BrowserAccessibility* parent = GetParent();
- bool need_to_offset_web_area =
- (GetRole() == ui::AX_ROLE_WEB_AREA ||
- GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
- while (parent) {
- if (need_to_offset_web_area &&
- parent->GetLocation().width() > 0 &&
- parent->GetLocation().height() > 0) {
- bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
- need_to_offset_web_area = false;
- }
-
- // On some platforms, we don't want to take the root scroll offsets
- // into account.
- if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
- !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
- break;
- }
-
- if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
- parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+ BrowserAccessibilityManager* manager = this->manager();
+ BrowserAccessibility* root = manager->GetRoot();
+ while (manager && root) {
+ // Apply scroll offsets.
+ if (root != this && (root->GetParent() ||
+ manager->UseRootScrollOffsetsWhenComputingBounds())) {
int sx = 0;
int sy = 0;
- if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
- parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+ if (root->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+ root->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
bounds.Offset(-sx, -sy);
}
- need_to_offset_web_area = true;
}
- parent = parent->GetParent();
+
+ // If the parent accessibility tree is in a different site instance,
+ // ask the delegate to transform our coordinates into the root
+ // coordinate space and then we're done.
+ if (manager->delegate() &&
+ root->GetParent() &&
+ root->GetParent()->manager()->delegate()) {
+ BrowserAccessibilityManager* parent_manager =
+ root->GetParent()->manager();
+ if (manager->delegate()->AccessibilityGetSiteInstance() !=
+ parent_manager->delegate()->AccessibilityGetSiteInstance()) {
+ return manager->delegate()->AccessibilityTransformToRootCoordSpace(
+ bounds);
+ }
+ }
+
+ // Otherwise, apply the transform from this frame into the coordinate
+ // space of its parent frame.
+ if (root->GetData().transform) {
+ gfx::RectF boundsf(bounds);
+ root->GetData().transform->TransformRect(&boundsf);
+ bounds = gfx::Rect(boundsf.x(), boundsf.y(),
+ boundsf.width(), boundsf.height());
+ }
+
+ if (!root->GetParent())
+ break;
+
+ manager = root->GetParent()->manager();
+ root = manager->GetRoot();
}
return bounds;
diff --git a/chromium/content/browser/accessibility/browser_accessibility.h b/chromium/content/browser/accessibility/browser_accessibility.h
index 9b1a3feb411..49120b9c396 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.h
+++ b/chromium/content/browser/accessibility/browser_accessibility.h
@@ -75,6 +75,8 @@ class CONTENT_EXPORT BrowserAccessibility {
virtual ~BrowserAccessibility();
+ static BrowserAccessibility* GetFromUniqueID(int32_t unique_id);
+
// Called only once, immediately after construction. The constructor doesn't
// take any arguments because in the Windows subclass we use a special
// function to construct a COM object.
@@ -89,6 +91,11 @@ class CONTENT_EXPORT BrowserAccessibility {
// Called when the location changed.
virtual void OnLocationChanged() {}
+ // This is called when the platform-specific attributes for a node need
+ // to be recomputed, which may involve firing native events, due to a
+ // change other than an update from OnAccessibilityEvents.
+ virtual void UpdatePlatformAttributes() {}
+
// Return true if this object is equal to or a descendant of |ancestor|.
bool IsDescendantOf(const BrowserAccessibility* ancestor) const;
@@ -116,6 +123,10 @@ class CONTENT_EXPORT BrowserAccessibility {
// platform.
bool PlatformIsChildOfLeaf() const;
+ // If this object is exposed to the platform, returns this object. Otherwise,
+ // returns the platform leaf under which this object is found.
+ BrowserAccessibility* GetClosestPlatformObject() const;
+
BrowserAccessibility* GetPreviousSibling() const;
BrowserAccessibility* GetNextSibling() const;
@@ -124,6 +135,11 @@ class CONTENT_EXPORT BrowserAccessibility {
// Returns nullptr if there are no children.
BrowserAccessibility* PlatformDeepestLastChild() const;
+ // Returns nullptr if there are no children.
+ BrowserAccessibility* InternalDeepestFirstChild() const;
+ // Returns nullptr if there are no children.
+ BrowserAccessibility* InternalDeepestLastChild() const;
+
// Returns the bounds of this object in coordinates relative to the
// top-left corner of the overall web area.
gfx::Rect GetLocalBoundsRect() const;
@@ -183,8 +199,9 @@ class CONTENT_EXPORT BrowserAccessibility {
//
BrowserAccessibilityManager* manager() const { return manager_; }
- bool instance_active() const { return node_ != NULL; }
+ bool instance_active() const { return node_ && manager_; }
ui::AXNode* node() const { return node_; }
+ int32_t unique_id() const { return unique_id_; }
// These access the internal accessibility tree, which doesn't necessarily
// reflect the accessibility tree that should be exposed on each platform.
@@ -211,17 +228,6 @@ class CONTENT_EXPORT BrowserAccessibility {
// IsNative returns false.
virtual bool IsNative() const;
-#if defined(OS_MACOSX) && __OBJC__
- const BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa() const;
- BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa();
-#elif defined(OS_WIN)
- const BrowserAccessibilityWin* ToBrowserAccessibilityWin() const;
- BrowserAccessibilityWin* ToBrowserAccessibilityWin();
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_X11)
- const BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux() const;
- BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux();
-#endif
-
// Accessing accessibility attributes:
//
// There are dozens of possible attributes for an accessibility node,
@@ -245,6 +251,17 @@ class CONTENT_EXPORT BrowserAccessibility {
float GetFloatAttribute(ui::AXFloatAttribute attr) const;
bool GetFloatAttribute(ui::AXFloatAttribute attr, float* value) const;
+ bool HasInheritedStringAttribute(ui::AXStringAttribute attribute) const;
+ const std::string& GetInheritedStringAttribute(
+ ui::AXStringAttribute attribute) const;
+ bool GetInheritedStringAttribute(ui::AXStringAttribute attribute,
+ std::string* value) const;
+
+ base::string16 GetInheritedString16Attribute(
+ ui::AXStringAttribute attribute) const;
+ bool GetInheritedString16Attribute(ui::AXStringAttribute attribute,
+ base::string16* value) const;
+
bool HasIntAttribute(ui::AXIntAttribute attribute) const;
int GetIntAttribute(ui::AXIntAttribute attribute) const;
bool GetIntAttribute(ui::AXIntAttribute attribute, int* value) const;
@@ -255,10 +272,10 @@ class CONTENT_EXPORT BrowserAccessibility {
bool GetStringAttribute(ui::AXStringAttribute attribute,
std::string* value) const;
- bool GetString16Attribute(ui::AXStringAttribute attribute,
- base::string16* value) const;
base::string16 GetString16Attribute(
ui::AXStringAttribute attribute) const;
+ bool GetString16Attribute(ui::AXStringAttribute attribute,
+ base::string16* value) const;
bool HasIntListAttribute(ui::AXIntListAttribute attribute) const;
const std::vector<int32_t>& GetIntListAttribute(
@@ -287,6 +304,8 @@ class CONTENT_EXPORT BrowserAccessibility {
bool* is_defined,
bool* is_mixed) const;
+ base::string16 GetFontFamily() const;
+ base::string16 GetLanguage() const;
virtual base::string16 GetText() const;
// Returns true if the bit corresponding to the given state enum is 1.
@@ -301,7 +320,10 @@ class CONTENT_EXPORT BrowserAccessibility {
// True if this is a web area, and its grandparent is a presentational iframe.
bool IsWebAreaForPresentationalIframe() const;
+ virtual bool IsClickable() const;
bool IsControl() const;
+ bool IsMenuRelated() const;
+ bool IsRangeControl() const;
bool IsSimpleTextControl() const;
// Indicates if this object is at the root of a rich edit text control.
bool IsRichTextControl() const;
@@ -319,6 +341,9 @@ class CONTENT_EXPORT BrowserAccessibility {
// The underlying node.
ui::AXNode* node_;
+ // A unique ID, since node IDs are frame-local.
+ int32_t unique_id_;
+
private:
// |GetInnerText| recursively includes all the text from descendants such as
// text found in any embedded object. In contrast, |GetText| might include a
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.cc b/chromium/content/browser/accessibility/browser_accessibility_android.cc
index 79a1f18a369..53df2492ce4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.cc
@@ -5,11 +5,15 @@
#include "content/browser/accessibility/browser_accessibility_android.h"
#include "base/i18n/break_iterator.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/app/strings/grit/content_strings.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#include "content/common/accessibility_messages.h"
+#include "content/public/common/content_client.h"
+#include "third_party/skia/include/core/SkColor.h"
namespace {
@@ -132,6 +136,8 @@ bool BrowserAccessibilityAndroid::IsClickable() const {
if (!PlatformIsLeaf())
return false;
+ // We are very aggressive about returning true with IsClickable on Android
+ // because there is no way to know for sure what might have a click handler.
return IsFocusable() || !GetText().empty();
}
@@ -181,7 +187,7 @@ bool BrowserAccessibilityAndroid::IsFocusable() const {
}
bool BrowserAccessibilityAndroid::IsFocused() const {
- return manager()->GetFocus(manager()->GetRoot()) == this;
+ return manager()->GetFocus() == this;
}
bool BrowserAccessibilityAndroid::IsHeading() const {
@@ -300,7 +306,10 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
class_name = "android.app.Dialog";
break;
case ui::AX_ROLE_ROOT_WEB_AREA:
- class_name = "android.webkit.WebView";
+ if (GetParent() == nullptr)
+ class_name = "android.webkit.WebView";
+ else
+ class_name = "android.view.View";
break;
case ui::AX_ROLE_MENU_ITEM:
case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
@@ -354,10 +363,11 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
// For color wells, the color is stored in separate attributes.
// Perhaps we could return color names in the future?
if (GetRole() == ui::AX_ROLE_COLOR_WELL) {
- int color = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE);
- int red = (color >> 16) & 0xFF;
- int green = (color >> 8) & 0xFF;
- int blue = color & 0xFF;
+ unsigned int color =
+ static_cast<unsigned int>(GetIntAttribute(ui::AX_ATTR_COLOR_VALUE));
+ unsigned int red = SkColorGetR(color);
+ unsigned int green = SkColorGetG(color);
+ unsigned int blue = SkColorGetB(color);
return base::UTF8ToUTF16(
base::StringPrintf("#%02X%02X%02X", red, green, blue));
}
@@ -407,6 +417,412 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
return text;
}
+base::string16 BrowserAccessibilityAndroid::GetRoleDescription() const {
+ content::ContentClient* content_client = content::GetContentClient();
+
+ // As a special case, if we have a heading level return a string like
+ // "heading level 1", etc.
+ if (GetRole() == ui::AX_ROLE_HEADING) {
+ int level = GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL);
+ if (level >= 1 && level <= 6) {
+ std::vector<base::string16> values;
+ values.push_back(base::IntToString16(level));
+ return base::ReplaceStringPlaceholders(
+ content_client->GetLocalizedString(IDS_AX_ROLE_HEADING_WITH_LEVEL),
+ values, nullptr);
+ }
+ }
+
+ int message_id = -1;
+ switch (GetRole()) {
+ case ui::AX_ROLE_ABBR:
+ // No role description.
+ break;
+ case ui::AX_ROLE_ALERT_DIALOG:
+ message_id = IDS_AX_ROLE_ALERT_DIALOG;
+ break;
+ case ui::AX_ROLE_ALERT:
+ message_id = IDS_AX_ROLE_ALERT;
+ break;
+ case ui::AX_ROLE_ANNOTATION:
+ // No role description.
+ break;
+ case ui::AX_ROLE_APPLICATION:
+ message_id = IDS_AX_ROLE_APPLICATION;
+ break;
+ case ui::AX_ROLE_ARTICLE:
+ message_id = IDS_AX_ROLE_ARTICLE;
+ break;
+ case ui::AX_ROLE_BANNER:
+ message_id = IDS_AX_ROLE_BANNER;
+ break;
+ case ui::AX_ROLE_BLOCKQUOTE:
+ message_id = IDS_AX_ROLE_BLOCKQUOTE;
+ break;
+ case ui::AX_ROLE_BUSY_INDICATOR:
+ message_id = IDS_AX_ROLE_BUSY_INDICATOR;
+ break;
+ case ui::AX_ROLE_BUTTON:
+ message_id = IDS_AX_ROLE_BUTTON;
+ break;
+ case ui::AX_ROLE_BUTTON_DROP_DOWN:
+ message_id = IDS_AX_ROLE_BUTTON_DROP_DOWN;
+ break;
+ case ui::AX_ROLE_CANVAS:
+ // No role description.
+ break;
+ case ui::AX_ROLE_CAPTION:
+ // No role description.
+ break;
+ case ui::AX_ROLE_CELL:
+ message_id = IDS_AX_ROLE_CELL;
+ break;
+ case ui::AX_ROLE_CHECK_BOX:
+ message_id = IDS_AX_ROLE_CHECK_BOX;
+ break;
+ case ui::AX_ROLE_CLIENT:
+ // No role description.
+ break;
+ case ui::AX_ROLE_COLOR_WELL:
+ message_id = IDS_AX_ROLE_COLOR_WELL;
+ break;
+ case ui::AX_ROLE_COLUMN_HEADER:
+ message_id = IDS_AX_ROLE_COLUMN_HEADER;
+ break;
+ case ui::AX_ROLE_COLUMN:
+ // No role description.
+ break;
+ case ui::AX_ROLE_COMBO_BOX:
+ message_id = IDS_AX_ROLE_COMBO_BOX;
+ break;
+ case ui::AX_ROLE_COMPLEMENTARY:
+ message_id = IDS_AX_ROLE_COMPLEMENTARY;
+ break;
+ case ui::AX_ROLE_CONTENT_INFO:
+ message_id = IDS_AX_ROLE_CONTENT_INFO;
+ break;
+ case ui::AX_ROLE_DATE:
+ message_id = IDS_AX_ROLE_DATE;
+ break;
+ case ui::AX_ROLE_DATE_TIME:
+ message_id = IDS_AX_ROLE_DATE_TIME;
+ break;
+ case ui::AX_ROLE_DEFINITION:
+ message_id = IDS_AX_ROLE_DEFINITION;
+ break;
+ case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL:
+ message_id = IDS_AX_ROLE_DEFINITION;
+ break;
+ case ui::AX_ROLE_DESCRIPTION_LIST:
+ // No role description.
+ break;
+ case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
+ // No role description.
+ break;
+ case ui::AX_ROLE_DESKTOP:
+ // No role description.
+ break;
+ case ui::AX_ROLE_DETAILS:
+ // No role description.
+ break;
+ case ui::AX_ROLE_DIALOG:
+ message_id = IDS_AX_ROLE_DIALOG;
+ break;
+ case ui::AX_ROLE_DIRECTORY:
+ message_id = IDS_AX_ROLE_DIRECTORY;
+ break;
+ case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
+ message_id = IDS_AX_ROLE_DISCLOSURE_TRIANGLE;
+ break;
+ case ui::AX_ROLE_DIV:
+ // No role description.
+ break;
+ case ui::AX_ROLE_DOCUMENT:
+ message_id = IDS_AX_ROLE_DOCUMENT;
+ break;
+ case ui::AX_ROLE_EMBEDDED_OBJECT:
+ message_id = IDS_AX_ROLE_EMBEDDED_OBJECT;
+ break;
+ case ui::AX_ROLE_FIGCAPTION:
+ // No role description.
+ break;
+ case ui::AX_ROLE_FIGURE:
+ message_id = IDS_AX_ROLE_GRAPHIC;
+ break;
+ case ui::AX_ROLE_FOOTER:
+ message_id = IDS_AX_ROLE_FOOTER;
+ break;
+ case ui::AX_ROLE_FORM:
+ // No role description.
+ break;
+ case ui::AX_ROLE_GRID:
+ message_id = IDS_AX_ROLE_TABLE;
+ break;
+ case ui::AX_ROLE_GROUP:
+ // No role description.
+ break;
+ case ui::AX_ROLE_HEADING:
+ // Note that code above this switch statement handles headings with
+ // a level, returning a string like "heading level 1", etc.
+ message_id = IDS_AX_ROLE_HEADING;
+ break;
+ case ui::AX_ROLE_IFRAME:
+ // No role description.
+ break;
+ case ui::AX_ROLE_IFRAME_PRESENTATIONAL:
+ // No role description.
+ break;
+ case ui::AX_ROLE_IGNORED:
+ // No role description.
+ break;
+ case ui::AX_ROLE_IMAGE_MAP_LINK:
+ message_id = IDS_AX_ROLE_LINK;
+ break;
+ case ui::AX_ROLE_IMAGE_MAP:
+ message_id = IDS_AX_ROLE_GRAPHIC;
+ break;
+ case ui::AX_ROLE_IMAGE:
+ message_id = IDS_AX_ROLE_GRAPHIC;
+ break;
+ case ui::AX_ROLE_INLINE_TEXT_BOX:
+ // No role description.
+ break;
+ case ui::AX_ROLE_INPUT_TIME:
+ message_id = IDS_AX_ROLE_INPUT_TIME;
+ break;
+ case ui::AX_ROLE_LABEL_TEXT:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LEGEND:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LINE_BREAK:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LINK:
+ message_id = IDS_AX_ROLE_LINK;
+ break;
+ case ui::AX_ROLE_LIST_BOX_OPTION:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LIST_BOX:
+ message_id = IDS_AX_ROLE_LIST_BOX;
+ break;
+ case ui::AX_ROLE_LIST_ITEM:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LIST_MARKER:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LIST:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LOCATION_BAR:
+ // No role description.
+ break;
+ case ui::AX_ROLE_LOG:
+ message_id = IDS_AX_ROLE_LOG;
+ break;
+ case ui::AX_ROLE_MAIN:
+ message_id = IDS_AX_ROLE_MAIN_CONTENT;
+ break;
+ case ui::AX_ROLE_MARK:
+ message_id = IDS_AX_ROLE_MARK;
+ break;
+ case ui::AX_ROLE_MARQUEE:
+ message_id = IDS_AX_ROLE_MARQUEE;
+ break;
+ case ui::AX_ROLE_MATH:
+ message_id = IDS_AX_ROLE_MATH;
+ break;
+ case ui::AX_ROLE_MENU_BAR:
+ message_id = IDS_AX_ROLE_MENU_BAR;
+ break;
+ case ui::AX_ROLE_MENU_BUTTON:
+ message_id = IDS_AX_ROLE_MENU_BUTTON;
+ break;
+ case ui::AX_ROLE_MENU_ITEM:
+ message_id = IDS_AX_ROLE_MENU_ITEM;
+ break;
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ message_id = IDS_AX_ROLE_CHECK_BOX;
+ break;
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ message_id = IDS_AX_ROLE_RADIO;
+ break;
+ case ui::AX_ROLE_MENU_LIST_OPTION:
+ // No role description.
+ break;
+ case ui::AX_ROLE_MENU_LIST_POPUP:
+ // No role description.
+ break;
+ case ui::AX_ROLE_MENU:
+ message_id = IDS_AX_ROLE_MENU;
+ break;
+ case ui::AX_ROLE_METER:
+ message_id = IDS_AX_ROLE_METER;
+ break;
+ case ui::AX_ROLE_NAVIGATION:
+ message_id = IDS_AX_ROLE_NAVIGATIONAL_LINK;
+ break;
+ case ui::AX_ROLE_NOTE:
+ message_id = IDS_AX_ROLE_NOTE;
+ break;
+ case ui::AX_ROLE_OUTLINE:
+ message_id = IDS_AX_ROLE_OUTLINE;
+ break;
+ case ui::AX_ROLE_PANE:
+ // No role description.
+ break;
+ case ui::AX_ROLE_PARAGRAPH:
+ // No role description.
+ break;
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ message_id = IDS_AX_ROLE_POP_UP_BUTTON;
+ break;
+ case ui::AX_ROLE_PRE:
+ // No role description.
+ break;
+ case ui::AX_ROLE_PRESENTATIONAL:
+ // No role description.
+ break;
+ case ui::AX_ROLE_PROGRESS_INDICATOR:
+ message_id = IDS_AX_ROLE_PROGRESS_INDICATOR;
+ break;
+ case ui::AX_ROLE_RADIO_BUTTON:
+ message_id = IDS_AX_ROLE_RADIO;
+ break;
+ case ui::AX_ROLE_RADIO_GROUP:
+ message_id = IDS_AX_ROLE_RADIO_GROUP;
+ break;
+ case ui::AX_ROLE_REGION:
+ message_id = IDS_AX_ROLE_REGION;
+ break;
+ case ui::AX_ROLE_ROOT_WEB_AREA:
+ // No role description.
+ break;
+ case ui::AX_ROLE_ROW_HEADER:
+ message_id = IDS_AX_ROLE_ROW_HEADER;
+ break;
+ case ui::AX_ROLE_ROW:
+ // No role description.
+ break;
+ case ui::AX_ROLE_RUBY:
+ // No role description.
+ break;
+ case ui::AX_ROLE_RULER:
+ message_id = IDS_AX_ROLE_RULER;
+ break;
+ case ui::AX_ROLE_SVG_ROOT:
+ message_id = IDS_AX_ROLE_GRAPHIC;
+ break;
+ case ui::AX_ROLE_SCROLL_AREA:
+ // No role description.
+ break;
+ case ui::AX_ROLE_SCROLL_BAR:
+ message_id = IDS_AX_ROLE_SCROLL_BAR;
+ break;
+ case ui::AX_ROLE_SEAMLESS_WEB_AREA:
+ // No role description.
+ break;
+ case ui::AX_ROLE_SEARCH:
+ message_id = IDS_AX_ROLE_SEARCH;
+ break;
+ case ui::AX_ROLE_SEARCH_BOX:
+ message_id = IDS_AX_ROLE_SEARCH_BOX;
+ break;
+ case ui::AX_ROLE_SLIDER:
+ message_id = IDS_AX_ROLE_SLIDER;
+ break;
+ case ui::AX_ROLE_SLIDER_THUMB:
+ // No role description.
+ break;
+ case ui::AX_ROLE_SPIN_BUTTON_PART:
+ // No role description.
+ break;
+ case ui::AX_ROLE_SPIN_BUTTON:
+ message_id = IDS_AX_ROLE_SPIN_BUTTON;
+ break;
+ case ui::AX_ROLE_SPLITTER:
+ message_id = IDS_AX_ROLE_SPLITTER;
+ break;
+ case ui::AX_ROLE_STATIC_TEXT:
+ // No role description.
+ break;
+ case ui::AX_ROLE_STATUS:
+ message_id = IDS_AX_ROLE_STATUS;
+ break;
+ case ui::AX_ROLE_SWITCH:
+ message_id = IDS_AX_ROLE_SWITCH;
+ break;
+ case ui::AX_ROLE_TAB_GROUP:
+ // No role description.
+ break;
+ case ui::AX_ROLE_TAB_LIST:
+ message_id = IDS_AX_ROLE_TAB_LIST;
+ break;
+ case ui::AX_ROLE_TAB_PANEL:
+ message_id = IDS_AX_ROLE_TAB_PANEL;
+ break;
+ case ui::AX_ROLE_TAB:
+ message_id = IDS_AX_ROLE_TAB;
+ break;
+ case ui::AX_ROLE_TABLE_HEADER_CONTAINER:
+ // No role description.
+ break;
+ case ui::AX_ROLE_TABLE:
+ message_id = IDS_AX_ROLE_TABLE;
+ break;
+ case ui::AX_ROLE_TEXT_FIELD:
+ // No role description.
+ break;
+ case ui::AX_ROLE_TIME:
+ message_id = IDS_AX_ROLE_TIME;
+ break;
+ case ui::AX_ROLE_TIMER:
+ message_id = IDS_AX_ROLE_TIMER;
+ break;
+ case ui::AX_ROLE_TITLE_BAR:
+ // No role description.
+ break;
+ case ui::AX_ROLE_TOGGLE_BUTTON:
+ message_id = IDS_AX_ROLE_TOGGLE_BUTTON;
+ break;
+ case ui::AX_ROLE_TOOLBAR:
+ message_id = IDS_AX_ROLE_TOOLBAR;
+ break;
+ case ui::AX_ROLE_TREE_GRID:
+ message_id = IDS_AX_ROLE_TREE_GRID;
+ break;
+ case ui::AX_ROLE_TREE_ITEM:
+ message_id = IDS_AX_ROLE_TREE_ITEM;
+ break;
+ case ui::AX_ROLE_TREE:
+ message_id = IDS_AX_ROLE_TREE;
+ break;
+ case ui::AX_ROLE_UNKNOWN:
+ // No role description.
+ break;
+ case ui::AX_ROLE_TOOLTIP:
+ message_id = IDS_AX_ROLE_TOOLTIP;
+ break;
+ case ui::AX_ROLE_WEB_AREA:
+ // No role description.
+ break;
+ case ui::AX_ROLE_WEB_VIEW:
+ // No role description.
+ break;
+ case ui::AX_ROLE_WINDOW:
+ // No role description.
+ break;
+ }
+
+ if (message_id != -1)
+ return content_client->GetLocalizedString(message_id);
+
+ return base::string16();
+}
+
int BrowserAccessibilityAndroid::GetItemIndex() const {
int index = 0;
switch (GetRole()) {
@@ -526,13 +942,13 @@ bool BrowserAccessibilityAndroid::Scroll(int direction) const {
// Figure out the bounding box of the visible portion of this scrollable
// view so we know how much to scroll by.
gfx::Rect bounds;
- if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+ if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA && !GetParent()) {
// If this is the root web area, use the bounds of the view to determine
// how big one page is.
if (!manager()->delegate())
return false;
bounds = manager()->delegate()->AccessibilityGetViewBounds();
- } else if (GetRole() == ui::AX_ROLE_WEB_AREA) {
+ } else if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA && GetParent()) {
// If this is a web area inside of an iframe, try to use the bounds of
// the containing element.
BrowserAccessibility* parent = GetParent();
@@ -924,9 +1340,8 @@ bool BrowserAccessibilityAndroid::HasOnlyTextAndImageChildren() const {
}
bool BrowserAccessibilityAndroid::IsIframe() const {
- base::string16 html_tag = GetString16Attribute(
- ui::AX_ATTR_HTML_TAG);
- return html_tag == base::ASCIIToUTF16("iframe");
+ return (GetRole() == ui::AX_ROLE_IFRAME ||
+ GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL);
}
void BrowserAccessibilityAndroid::OnDataChanged() {
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.h b/chromium/content/browser/accessibility/browser_accessibility_android.h
index 66055538087..56a5b63ea67 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.h
@@ -25,7 +25,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
bool IsCheckable() const;
bool IsChecked() const;
- bool IsClickable() const;
+ bool IsClickable() const override;
bool IsCollection() const;
bool IsCollectionItem() const;
bool IsContentInvalid() const;
@@ -52,6 +52,8 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
const char* GetClassName() const;
base::string16 GetText() const override;
+ base::string16 GetRoleDescription() const;
+
int GetItemIndex() const;
int GetItemCount() const;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc b/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
index 880839e047a..231a3dd7cd4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
@@ -23,6 +23,18 @@ static BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
return atk_object->m_object;
}
+const BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+ const BrowserAccessibility* obj) {
+ DCHECK(!obj || obj->IsNative());
+ return static_cast<const BrowserAccessibilityAuraLinux*>(obj);
+}
+
+BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+ BrowserAccessibility* obj) {
+ DCHECK(!obj || obj->IsNative());
+ return static_cast<BrowserAccessibilityAuraLinux*>(obj);
+}
+
//
// AtkAction interface.
//
@@ -140,7 +152,7 @@ static AtkObject* browser_accessibility_accessible_at_point(
return NULL;
AtkObject* atk_result =
- result->ToBrowserAccessibilityAuraLinux()->GetAtkObject();
+ ToBrowserAccessibilityAuraLinux(result)->GetAtkObject();
g_object_ref(atk_result);
return atk_result;
}
@@ -177,7 +189,7 @@ static gboolean browser_accessibility_grab_focus(AtkComponent* atk_component) {
if (!obj)
return false;
- obj->manager()->SetFocus(obj, true);
+ obj->manager()->SetFocus(*obj);
return true;
}
@@ -474,7 +486,7 @@ static AtkObject* browser_accessibility_get_parent(AtkObject* atk_object) {
if (!obj)
return NULL;
if (obj->GetParent())
- return obj->GetParent()->ToBrowserAccessibilityAuraLinux()->GetAtkObject();
+ return ToBrowserAccessibilityAuraLinux(obj->GetParent())->GetAtkObject();
BrowserAccessibilityManagerAuraLinux* manager =
static_cast<BrowserAccessibilityManagerAuraLinux*>(obj->manager());
@@ -500,9 +512,8 @@ static AtkObject* browser_accessibility_ref_child(AtkObject* atk_object,
if (index < 0 || index >= static_cast<gint>(obj->PlatformChildCount()))
return NULL;
- AtkObject* result = obj->InternalGetChild(index)
- ->ToBrowserAccessibilityAuraLinux()
- ->GetAtkObject();
+ AtkObject* result = ToBrowserAccessibilityAuraLinux(
+ obj->InternalGetChild(index))->GetAtkObject();
g_object_ref(result);
return result;
}
@@ -539,7 +550,7 @@ static AtkStateSet* browser_accessibility_ref_state_set(AtkObject* atk_object) {
if (state & (1 << ui::AX_STATE_FOCUSABLE))
atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE);
- if (obj->manager()->GetFocus(NULL) == obj)
+ if (obj->manager()->GetFocus() == obj)
atk_state_set_add_state(state_set, ATK_STATE_FOCUSED);
if (state & (1 << ui::AX_STATE_ENABLED))
atk_state_set_add_state(state_set, ATK_STATE_ENABLED);
@@ -735,16 +746,6 @@ BrowserAccessibility* BrowserAccessibility::Create() {
return new BrowserAccessibilityAuraLinux();
}
-const BrowserAccessibilityAuraLinux*
-BrowserAccessibility::ToBrowserAccessibilityAuraLinux() const {
- return static_cast<const BrowserAccessibilityAuraLinux*>(this);
-}
-
-BrowserAccessibilityAuraLinux*
-BrowserAccessibility::ToBrowserAccessibilityAuraLinux() {
- return static_cast<BrowserAccessibilityAuraLinux*>(this);
-}
-
BrowserAccessibilityAuraLinux::BrowserAccessibilityAuraLinux()
: atk_object_(NULL) {
}
@@ -782,7 +783,7 @@ void BrowserAccessibilityAuraLinux::OnDataChanged() {
if (this->GetParent()) {
atk_object_set_parent(
atk_object_,
- this->GetParent()->ToBrowserAccessibilityAuraLinux()->GetAtkObject());
+ ToBrowserAccessibilityAuraLinux(this->GetParent())->GetAtkObject());
}
}
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_auralinux.h b/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
index 43a9c3f16b0..773e79fbd31 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/common/content_export.h"
namespace content {
@@ -88,6 +89,12 @@ class BrowserAccessibilityAuraLinux : public BrowserAccessibility {
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinux);
};
+CONTENT_EXPORT const BrowserAccessibilityAuraLinux*
+ToBrowserAccessibilityAuraLinux(const BrowserAccessibility* obj);
+
+CONTENT_EXPORT BrowserAccessibilityAuraLinux* ToBrowserAccessibilityAuraLinux(
+ BrowserAccessibility* obj);
+
} // namespace content
#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_AURALINUX_H_
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
index 6c5a3e6f0c1..992373453e6 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -22,8 +22,8 @@
}
// This creates a cocoa browser accessibility object around
-// the cross platform BrowserAccessibility object, which can't be null.
-- (id)initWithObject:(content::BrowserAccessibility*)accessibility;
+// the cross platform BrowserAccessibility object, which can't be nullptr.
+- (instancetype)initWithObject:(content::BrowserAccessibility*)accessibility;
// Clear this object's pointer to the wrapped BrowserAccessibility object
// because the wrapped object has been deleted, but this object may
@@ -39,7 +39,7 @@
// Convenience method to determine if this object should expose its
// accessible name in AXValue (as opposed to AXTitle/AXDescription).
-- (bool)shouldExposeNameInAXValue;
+- (BOOL)shouldExposeNameInAXValue;
// Convenience method to get the BrowserAccessibilityDelegate from
// the manager.
@@ -48,6 +48,9 @@
// Get the BrowserAccessibility that this object wraps.
- (content::BrowserAccessibility*)browserAccessibility;
+// Determines if this object is alive, i.e. it hasn't been detached.
+- (BOOL)instanceActive;
+
// Convert the local objet's origin to a global point.
- (NSPoint)pointInScreen:(NSPoint)origin
size:(NSSize)size;
@@ -61,16 +64,16 @@
// Returns the requested text range from this object's value attribute.
- (NSString*)valueForRange:(NSRange)range;
-// Internally-used method.
+// Internally-used property.
@property(nonatomic, readonly) NSPoint origin;
-// Children is an array of BrowserAccessibility objects, representing
-// the accessibility children of this object.
@property(nonatomic, readonly) NSString* accessKey;
@property(nonatomic, readonly) NSNumber* ariaAtomic;
@property(nonatomic, readonly) NSNumber* ariaBusy;
@property(nonatomic, readonly) NSString* ariaLive;
+@property(nonatomic, readonly) NSNumber* ariaPosInSet;
@property(nonatomic, readonly) NSString* ariaRelevant;
+@property(nonatomic, readonly) NSNumber* ariaSetSize;
@property(nonatomic, readonly) NSArray* children;
@property(nonatomic, readonly) NSArray* columns;
@property(nonatomic, readonly) NSArray* columnHeaders;
@@ -80,15 +83,24 @@
@property(nonatomic, readonly) id disclosedByRow;
@property(nonatomic, readonly) NSNumber* disclosureLevel;
@property(nonatomic, readonly) id disclosedRows;
+@property(nonatomic, readonly) NSString* dropEffects;
@property(nonatomic, readonly) NSNumber* enabled;
+// Returns a text marker that points to the last character in the document that
+// can be selected with Voiceover.
+@property(nonatomic, readonly) id endTextMarker;
+@property(nonatomic, readonly) NSNumber* expanded;
@property(nonatomic, readonly) NSNumber* focused;
+@property(nonatomic, readonly) NSNumber* grabbed;
+@property(nonatomic, readonly) id header;
@property(nonatomic, readonly) NSString* help;
// isIgnored returns whether or not the accessibility object
// should be ignored by the accessibility hierarchy.
@property(nonatomic, readonly, getter=isIgnored) BOOL ignored;
// Index of a row, column, or tree item.
@property(nonatomic, readonly) NSNumber* index;
+@property(nonatomic, readonly) NSNumber* insertionPointLineNumber;
@property(nonatomic, readonly) NSString* invalid;
+@property(nonatomic, readonly) NSNumber* isMultiSelectable;
@property(nonatomic, readonly) NSString* placeholderValue;
@property(nonatomic, readonly) NSNumber* loaded;
@property(nonatomic, readonly) NSNumber* loadingProgress;
@@ -106,9 +118,17 @@
@property(nonatomic, readonly) NSArray* rowHeaders;
@property(nonatomic, readonly) NSValue* rowIndexRange;
@property(nonatomic, readonly) NSArray* rows;
+// The object is selected as a whole.
+@property(nonatomic, readonly) NSNumber* selected;
@property(nonatomic, readonly) NSArray* selectedChildren;
-// The size of this object.
+@property(nonatomic, readonly) NSString* selectedText;
+@property(nonatomic, readonly) NSValue* selectedTextRange;
+@property(nonatomic, readonly) id selectedTextMarkerRange;
@property(nonatomic, readonly) NSValue* size;
+@property(nonatomic, readonly) NSString* sortDirection;
+// Returns a text marker that points to the first character in the document that
+// can be selected with Voiceover.
+@property(nonatomic, readonly) id startTextMarker;
// A string indicating the subrole of this object as far as accessibility
// is concerned.
@property(nonatomic, readonly) NSString* subrole;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
index 78c8c0150fb..1ae72bd2e30 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -10,22 +10,21 @@
#include <map>
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/strings/string16.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/app/strings/grit/content_strings.h"
+#include "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
#include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
#include "content/public/common/content_client.h"
+#include "third_party/skia/include/core/SkColor.h"
#import "ui/accessibility/platform/ax_platform_node_mac.h"
-// See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5,
-// 10.6, and 10.7. It allows accessibility clients to observe events posted on
-// this object.
-extern "C" void NSAccessibilityUnregisterUniqueIdForUIElement(id element);
-
-using ui::AXNodeData;
+using content::AXTreeIDRegistry;
using content::AccessibilityMatchPredicate;
using content::BrowserAccessibility;
using content::BrowserAccessibilityDelegate;
@@ -33,13 +32,186 @@ using content::BrowserAccessibilityManager;
using content::BrowserAccessibilityManagerMac;
using content::ContentClient;
using content::OneShotAccessibilityTreeSearch;
-typedef ui::AXStringAttribute StringAttribute;
+using ui::AXNodeData;
+using StringAttribute = ui::AXStringAttribute;
+using AXTextMarkerRef = CFTypeRef;
+using AXTextMarkerRangeRef = CFTypeRef;
namespace {
+// Private WebKit accessibility attributes.
+NSString* const NSAccessibilityARIAAtomicAttribute = @"AXARIAAtomic";
+NSString* const NSAccessibilityARIABusyAttribute = @"AXARIABusy";
+NSString* const NSAccessibilityARIALiveAttribute = @"AXARIALive";
+NSString* const NSAccessibilityARIAPosInSetAttribute = @"AXARIAPosInSet";
+NSString* const NSAccessibilityARIARelevantAttribute = @"AXARIARelevant";
+NSString* const NSAccessibilityARIASetSizeAttribute = @"AXARIASetSize";
+NSString* const NSAccessibilityAccessKeyAttribute = @"AXAccessKey";
+NSString* const NSAccessibilityDropEffectsAttribute = @"AXDropEffects";
+NSString* const NSAccessibilityGrabbedAttribute = @"AXGrabbed";
+NSString* const NSAccessibilityInvalidAttribute = @"AXInvalid";
+NSString* const NSAccessibilityIsMultiSelectableAttribute =
+ @"AXIsMultiSelectable";
+NSString* const NSAccessibilityLoadingProgressAttribute = @"AXLoadingProgress";
+NSString* const NSAccessibilityRequiredAttribute = @"AXRequired";
+NSString* const
+ NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute =
+ @"AXUIElementCountForSearchPredicate";
+NSString* const
+ NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute =
+ @"AXUIElementsForSearchPredicate";
+NSString* const NSAccessibilityVisitedAttribute = @"AXVisited";
+
+// Private attributes for text markers.
+NSString* const NSAccessibilityStartTextMarkerAttribute = @"AXStartTextMarker";
+NSString* const NSAccessibilityEndTextMarkerAttribute = @"AXEndTextMarker";
+NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
+ @"AXSelectedTextMarkerRange";
+NSString* const NSAccessibilityTextMarkerIsValidParameterizedAttribute =
+ @"AXTextMarkerIsValid";
+NSString* const NSAccessibilityIndexForTextMarkerParameterizedAttribute =
+ @"AXIndexForTextMarker";
+NSString* const NSAccessibilityTextMarkerForIndexParameterizedAttribute =
+ @"AXTextMarkerForIndex";
+NSString* const NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute =
+ @"AXEndTextMarkerForBounds";
+NSString* const NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute =
+ @"AXStartTextMarkerForBounds";
+NSString* const
+ NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute =
+ @"AXLineTextMarkerRangeForTextMarker";
+NSString* const NSAccessibilitySelectTextWithCriteriaParameterizedAttribute =
+ @"AXSelectTextWithCriteria";
+
+// Actions.
+NSString* const NSAccessibilityScrollToVisibleAction = @"AXScrollToVisible";
+
+// A mapping from an accessibility attribute to its method name.
+NSDictionary* attributeToMethodNameMap = nil;
+
+struct AXTextMarkerData {
+ AXTreeIDRegistry::AXTreeID tree_id;
+ int32_t node_id;
+ int offset;
+};
+
// VoiceOver uses -1 to mean "no limit" for AXResultsLimit.
const int kAXResultsLimitNoLimit = -1;
+extern "C" {
+
+// See http://openradar.appspot.com/9896491. This SPI has been tested on 10.5,
+// 10.6, and 10.7. It allows accessibility clients to observe events posted on
+// this object.
+void NSAccessibilityUnregisterUniqueIdForUIElement(id element);
+
+// The following are private accessibility APIs required for cursor navigation
+// and text selection. VoiceOver started relying on them in Mac OS X 10.11.
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
+
+AXTextMarkerRef AXTextMarkerCreate(CFAllocatorRef allocator,
+ const UInt8* bytes,
+ CFIndex length);
+
+const UInt8* AXTextMarkerGetBytePtr(AXTextMarkerRef text_marker);
+
+AXTextMarkerRangeRef AXTextMarkerRangeCreate(CFAllocatorRef allocator,
+ AXTextMarkerRef start_marker,
+ AXTextMarkerRef end_marker);
+
+AXTextMarkerRef AXTextMarkerRangeCopyStartMarker(
+ AXTextMarkerRangeRef text_marker_range);
+
+AXTextMarkerRef AXTextMarkerRangeCopyEndMarker(
+ AXTextMarkerRangeRef text_marker_range);
+
+#endif // MAC_OS_X_VERSION_10_11
+
+} // extern "C"
+
+id CreateTextMarker(const BrowserAccessibility& object, int offset) {
+ AXTextMarkerData marker_data;
+ marker_data.tree_id = object.manager() ? object.manager()->ax_tree_id() : -1;
+ marker_data.node_id = object.GetId();
+ marker_data.offset = offset;
+ return (id)base::mac::CFTypeRefToNSObjectAutorelease(AXTextMarkerCreate(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&marker_data),
+ sizeof(marker_data)));
+}
+
+id CreateTextMarkerRange(const BrowserAccessibility& start_object,
+ int start_offset,
+ const BrowserAccessibility& end_object,
+ int end_offset) {
+ id start_marker = CreateTextMarker(start_object, start_offset);
+ id end_marker = CreateTextMarker(end_object, end_offset);
+ return (id)base::mac::CFTypeRefToNSObjectAutorelease(
+ AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker));
+}
+
+bool GetTextMarkerData(AXTextMarkerRef text_marker,
+ BrowserAccessibility** object,
+ int* offset) {
+ DCHECK(text_marker);
+ DCHECK(object && offset);
+ auto marker_data = reinterpret_cast<const AXTextMarkerData*>(
+ AXTextMarkerGetBytePtr(text_marker));
+ if (!marker_data)
+ return false;
+
+ const BrowserAccessibilityManager* manager =
+ BrowserAccessibilityManager::FromID(marker_data->tree_id);
+ if (!manager)
+ return false;
+
+ *object = manager->GetFromID(marker_data->node_id);
+ if (!*object)
+ return false;
+
+ *offset = marker_data->offset;
+ if (*offset < 0)
+ return false;
+
+ return true;
+}
+
+bool GetTextMarkerRange(AXTextMarkerRangeRef marker_range,
+ BrowserAccessibility** start_object,
+ int* start_offset,
+ BrowserAccessibility** end_object,
+ int* end_offset) {
+ DCHECK(marker_range);
+ DCHECK(start_object && start_offset);
+ DCHECK(end_object && end_offset);
+
+ base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(
+ AXTextMarkerRangeCopyStartMarker(marker_range));
+ base::ScopedCFTypeRef<AXTextMarkerRef> end_marker(
+ AXTextMarkerRangeCopyEndMarker(marker_range));
+ if (!start_marker.get() || !end_marker.get())
+ return false;
+
+ return GetTextMarkerData(start_marker.get(), start_object, start_offset) &&
+ GetTextMarkerData(end_marker.get(), end_object, end_offset);
+}
+
+NSString* GetTextForTextMarkerRange(AXTextMarkerRangeRef marker_range) {
+ BrowserAccessibility* start_object;
+ BrowserAccessibility* end_object;
+ int start_offset, end_offset;
+ if (!GetTextMarkerRange(marker_range, &start_object, &start_offset,
+ &end_object, &end_offset)) {
+ return nil;
+ }
+ DCHECK(start_object && end_object);
+ DCHECK_GE(start_offset, 0);
+ DCHECK_GE(end_offset, 0);
+
+ return base::SysUTF16ToNSString(BrowserAccessibilityManager::GetTextForRange(
+ *start_object, start_offset, *end_object, end_offset));
+}
+
// Returns an autoreleased copy of the AXNodeData's attribute.
NSString* NSStringForStringAttribute(
BrowserAccessibility* browserAccessibility,
@@ -54,9 +226,6 @@ bool GetState(BrowserAccessibility* accessibility, ui::AXState state) {
return ((accessibility->GetState() >> state) & 1);
}
-// A mapping from an accessibility attribute to its method name.
-NSDictionary* attributeToMethodNameMap = nil;
-
// Given a search key provided to AXUIElementCountForSearchPredicate or
// AXUIElementsForSearchPredicate, return a predicate that can be added
// to OneShotAccessibilityTreeSearch.
@@ -65,39 +234,19 @@ AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) {
return [](BrowserAccessibility* start, BrowserAccessibility* current) {
return true;
};
- } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"] ||
- [searchKey isEqualToString:@"AXBlockquoteSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- // TODO(dmazzoni): implement the "same level" part.
- return current->GetRole() == ui::AX_ROLE_BLOCKQUOTE;
- };
+ } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"]) {
+ // TODO(dmazzoni): implement the "same level" part.
+ return content::AccessibilityBlockquotePredicate;
+ } else if ([searchKey isEqualToString:@"AXBlockquoteSearchKey"]) {
+ return content::AccessibilityBlockquotePredicate;
} else if ([searchKey isEqualToString:@"AXBoldFontSearchKey"]) {
- // TODO(dmazzoni): implement this.
- return nullptr;
+ return content::AccessibilityTextStyleBoldPredicate;
} else if ([searchKey isEqualToString:@"AXButtonSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_BUTTON ||
- current->GetRole() == ui::AX_ROLE_MENU_BUTTON ||
- current->GetRole() == ui::AX_ROLE_POP_UP_BUTTON ||
- current->GetRole() == ui::AX_ROLE_SWITCH ||
- current->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON);
- };
+ return content::AccessibilityButtonPredicate;
} else if ([searchKey isEqualToString:@"AXCheckBoxSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_CHECK_BOX ||
- current->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX);
- };
+ return content::AccessibilityCheckboxPredicate;
} else if ([searchKey isEqualToString:@"AXControlSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- if (current->IsControl())
- return true;
- if (current->HasState(ui::AX_STATE_FOCUSABLE) &&
- current->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK &&
- current->GetRole() != ui::AX_ROLE_LINK) {
- return true;
- }
- return false;
- };
+ return content::AccessibilityControlPredicate;
} else if ([searchKey isEqualToString:@"AXDifferentTypeSearchKey"]) {
return [](BrowserAccessibility* start, BrowserAccessibility* current) {
return current->GetRole() != start->GetRole();
@@ -109,102 +258,48 @@ AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) {
// TODO(dmazzoni): implement this.
return nullptr;
} else if ([searchKey isEqualToString:@"AXFrameSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- if (current->IsWebAreaForPresentationalIframe())
- return false;
- if (!current->GetParent())
- return false;
- return (current->GetRole() == ui::AX_ROLE_WEB_AREA ||
- current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
- };
+ return content::AccessibilityFramePredicate;
} else if ([searchKey isEqualToString:@"AXGraphicSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_IMAGE;
- };
+ return content::AccessibilityGraphicPredicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel1SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1);
- };
+ return content::AccessibilityH1Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel2SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2);
- };
+ return content::AccessibilityH2Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel3SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3);
- };
+ return content::AccessibilityH3Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel4SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4);
- };
+ return content::AccessibilityH4Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel5SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5);
- };
+ return content::AccessibilityH5Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingLevel6SearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6);
- };
+ return content::AccessibilityH6Predicate;
} else if ([searchKey isEqualToString:@"AXHeadingSameLevelSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_HEADING &&
- start->GetRole() == ui::AX_ROLE_HEADING &&
- (current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) ==
- start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)));
- };
+ return content::AccessibilityHeadingSameLevelPredicate;
} else if ([searchKey isEqualToString:@"AXHeadingSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_HEADING;
- };
+ return content::AccessibilityHeadingPredicate;
} else if ([searchKey isEqualToString:@"AXHighlightedSearchKey"]) {
// TODO(dmazzoni): implement this.
return nullptr;
} else if ([searchKey isEqualToString:@"AXItalicFontSearchKey"]) {
- // TODO(dmazzoni): implement this.
- return nullptr;
+ return content::AccessibilityTextStyleItalicPredicate;
} else if ([searchKey isEqualToString:@"AXLandmarkSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_APPLICATION ||
- current->GetRole() == ui::AX_ROLE_BANNER ||
- current->GetRole() == ui::AX_ROLE_COMPLEMENTARY ||
- current->GetRole() == ui::AX_ROLE_CONTENT_INFO ||
- current->GetRole() == ui::AX_ROLE_FORM ||
- current->GetRole() == ui::AX_ROLE_MAIN ||
- current->GetRole() == ui::AX_ROLE_NAVIGATION ||
- current->GetRole() == ui::AX_ROLE_SEARCH);
- };
+ return content::AccessibilityLandmarkPredicate;
} else if ([searchKey isEqualToString:@"AXLinkSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_LINK;
- };
+ return content::AccessibilityLinkPredicate;
} else if ([searchKey isEqualToString:@"AXListSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_LIST;
- };
+ return content::AccessibilityListPredicate;
} else if ([searchKey isEqualToString:@"AXLiveRegionSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS);
- };
+ return content::AccessibilityLiveRegionPredicate;
} else if ([searchKey isEqualToString:@"AXMisspelledWordSearchKey"]) {
// TODO(dmazzoni): implement this.
return nullptr;
} else if ([searchKey isEqualToString:@"AXOutlineSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_TREE;
- };
+ return content::AccessibilityTreePredicate;
} else if ([searchKey isEqualToString:@"AXPlainTextSearchKey"]) {
// TODO(dmazzoni): implement this.
return nullptr;
} else if ([searchKey isEqualToString:@"AXRadioGroupSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_RADIO_GROUP;
- };
+ return content::AccessibilityRadioGroupPredicate;
} else if ([searchKey isEqualToString:@"AXSameTypeSearchKey"]) {
return [](BrowserAccessibility* start, BrowserAccessibility* current) {
return current->GetRole() == start->GetRole();
@@ -217,33 +312,18 @@ AccessibilityMatchPredicate PredicateForSearchKey(NSString* searchKey) {
// TODO(dmazzoni): implement this.
return nullptr;
} else if ([searchKey isEqualToString:@"AXTableSameLevelSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- // TODO(dmazzoni): implement the "same level" part.
- return current->GetRole() == ui::AX_ROLE_GRID ||
- current->GetRole() == ui::AX_ROLE_TABLE;
- };
+ // TODO(dmazzoni): implement the "same level" part.
+ return content::AccessibilityTablePredicate;
} else if ([searchKey isEqualToString:@"AXTableSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->GetRole() == ui::AX_ROLE_GRID ||
- current->GetRole() == ui::AX_ROLE_TABLE;
- };
+ return content::AccessibilityTablePredicate;
} else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return current->IsSimpleTextControl() || current->IsRichTextControl();
- };
+ return content::AccessibilityTextfieldPredicate;
} else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) {
- // TODO(dmazzoni): implement this.
- return nullptr;
+ return content::AccessibilityTextStyleUnderlinePredicate;
} else if ([searchKey isEqualToString:@"AXUnvisitedLinkSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_LINK &&
- !current->HasState(ui::AX_STATE_VISITED));
- };
+ return content::AccessibilityUnvisitedLinkPredicate;
} else if ([searchKey isEqualToString:@"AXVisitedLinkSearchKey"]) {
- return [](BrowserAccessibility* start, BrowserAccessibility* current) {
- return (current->GetRole() == ui::AX_ROLE_LINK &&
- current->HasState(ui::AX_STATE_VISITED));
- };
+ return content::AccessibilityVisitedLinkPredicate;
}
return nullptr;
@@ -330,7 +410,7 @@ bool InitializeAccessibilityTreeSearch(
return true;
}
-} // namespace
+} // namespace
@implementation BrowserAccessibilityCocoa
@@ -339,67 +419,78 @@ bool InitializeAccessibilityTreeSearch(
NSString* attribute;
NSString* methodName;
} attributeToMethodNameContainer[] = {
- { NSAccessibilityChildrenAttribute, @"children" },
- { NSAccessibilityColumnsAttribute, @"columns" },
- { NSAccessibilityColumnHeaderUIElementsAttribute, @"columnHeaders" },
- { NSAccessibilityColumnIndexRangeAttribute, @"columnIndexRange" },
- { NSAccessibilityContentsAttribute, @"contents" },
- { NSAccessibilityDescriptionAttribute, @"description" },
- { NSAccessibilityDisclosingAttribute, @"disclosing" },
- { NSAccessibilityDisclosedByRowAttribute, @"disclosedByRow" },
- { NSAccessibilityDisclosureLevelAttribute, @"disclosureLevel" },
- { NSAccessibilityDisclosedRowsAttribute, @"disclosedRows" },
- { NSAccessibilityEnabledAttribute, @"enabled" },
- { NSAccessibilityExpandedAttribute, @"expanded" },
- { NSAccessibilityFocusedAttribute, @"focused" },
- { NSAccessibilityHeaderAttribute, @"header" },
- { NSAccessibilityHelpAttribute, @"help" },
- { NSAccessibilityIndexAttribute, @"index" },
- { NSAccessibilityLinkedUIElementsAttribute, @"linkedUIElements" },
- { NSAccessibilityMaxValueAttribute, @"maxValue" },
- { NSAccessibilityMinValueAttribute, @"minValue" },
- { NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters" },
- { NSAccessibilityOrientationAttribute, @"orientation" },
- { NSAccessibilityParentAttribute, @"parent" },
- { NSAccessibilityPlaceholderValueAttribute, @"placeholderValue" },
- { NSAccessibilityPositionAttribute, @"position" },
- { NSAccessibilityRoleAttribute, @"role" },
- { NSAccessibilityRoleDescriptionAttribute, @"roleDescription" },
- { NSAccessibilityRowHeaderUIElementsAttribute, @"rowHeaders" },
- { NSAccessibilityRowIndexRangeAttribute, @"rowIndexRange" },
- { NSAccessibilityRowsAttribute, @"rows" },
- // TODO(aboxhall): expose NSAccessibilityServesAsTitleForUIElementsAttribute
- { NSAccessibilitySelectedChildrenAttribute, @"selectedChildren" },
- { NSAccessibilitySizeAttribute, @"size" },
- { NSAccessibilitySubroleAttribute, @"subrole" },
- { NSAccessibilityTabsAttribute, @"tabs" },
- { NSAccessibilityTitleAttribute, @"title" },
- { NSAccessibilityTitleUIElementAttribute, @"titleUIElement" },
- { NSAccessibilityTopLevelUIElementAttribute, @"window" },
- { NSAccessibilityURLAttribute, @"url" },
- { NSAccessibilityValueAttribute, @"value" },
- { NSAccessibilityValueDescriptionAttribute, @"valueDescription" },
- { NSAccessibilityVisibleCharacterRangeAttribute, @"visibleCharacterRange" },
- { NSAccessibilityVisibleCellsAttribute, @"visibleCells" },
- { NSAccessibilityVisibleChildrenAttribute, @"visibleChildren" },
- { NSAccessibilityVisibleColumnsAttribute, @"visibleColumns" },
- { NSAccessibilityVisibleRowsAttribute, @"visibleRows" },
- { NSAccessibilityWindowAttribute, @"window" },
- { @"AXAccessKey", @"accessKey" },
- { @"AXARIAAtomic", @"ariaAtomic" },
- { @"AXARIABusy", @"ariaBusy" },
- { @"AXARIALive", @"ariaLive" },
- { @"AXARIASetSize", @"ariaSetSize" },
- { @"AXARIAPosInSet", @"ariaPosInSet" },
- { @"AXARIARelevant", @"ariaRelevant" },
- { @"AXDropEffects", @"dropeffect" },
- { @"AXGrabbed", @"grabbed" },
- { @"AXInvalid", @"invalid" },
- { @"AXLoaded", @"loaded" },
- { @"AXLoadingProgress", @"loadingProgress" },
- { @"AXRequired", @"required" },
- { @"AXSortDirection", @"sortDirection" },
- { @"AXVisited", @"visited" },
+ {NSAccessibilityARIAAtomicAttribute, @"ariaAtomic"},
+ {NSAccessibilityARIABusyAttribute, @"ariaBusy"},
+ {NSAccessibilityARIALiveAttribute, @"ariaLive"},
+ {NSAccessibilityARIAPosInSetAttribute, @"ariaPosInSet"},
+ {NSAccessibilityARIARelevantAttribute, @"ariaRelevant"},
+ {NSAccessibilityARIASetSizeAttribute, @"ariaSetSize"},
+ {NSAccessibilityAccessKeyAttribute, @"accessKey"},
+ {NSAccessibilityChildrenAttribute, @"children"},
+ {NSAccessibilityColumnsAttribute, @"columns"},
+ {NSAccessibilityColumnHeaderUIElementsAttribute, @"columnHeaders"},
+ {NSAccessibilityColumnIndexRangeAttribute, @"columnIndexRange"},
+ {NSAccessibilityContentsAttribute, @"contents"},
+ {NSAccessibilityDescriptionAttribute, @"description"},
+ {NSAccessibilityDisclosingAttribute, @"disclosing"},
+ {NSAccessibilityDisclosedByRowAttribute, @"disclosedByRow"},
+ {NSAccessibilityDisclosureLevelAttribute, @"disclosureLevel"},
+ {NSAccessibilityDisclosedRowsAttribute, @"disclosedRows"},
+ {NSAccessibilityDropEffectsAttribute, @"dropEffects"},
+ {NSAccessibilityEnabledAttribute, @"enabled"},
+ {NSAccessibilityEndTextMarkerAttribute, @"endTextMarker"},
+ {NSAccessibilityExpandedAttribute, @"expanded"},
+ {NSAccessibilityFocusedAttribute, @"focused"},
+ {NSAccessibilityGrabbedAttribute, @"grabbed"},
+ {NSAccessibilityHeaderAttribute, @"header"},
+ {NSAccessibilityHelpAttribute, @"help"},
+ {NSAccessibilityIndexAttribute, @"index"},
+ {NSAccessibilityInsertionPointLineNumberAttribute,
+ @"insertionPointLineNumber"},
+ {NSAccessibilityInvalidAttribute, @"invalid"},
+ {NSAccessibilityIsMultiSelectableAttribute, @"isMultiSelectable"},
+ {NSAccessibilityLinkedUIElementsAttribute, @"linkedUIElements"},
+ {NSAccessibilityLoadingProgressAttribute, @"loadingProgress"},
+ {NSAccessibilityMaxValueAttribute, @"maxValue"},
+ {NSAccessibilityMinValueAttribute, @"minValue"},
+ {NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters"},
+ {NSAccessibilityOrientationAttribute, @"orientation"},
+ {NSAccessibilityParentAttribute, @"parent"},
+ {NSAccessibilityPlaceholderValueAttribute, @"placeholderValue"},
+ {NSAccessibilityPositionAttribute, @"position"},
+ {NSAccessibilityRequiredAttribute, @"required"},
+ {NSAccessibilityRoleAttribute, @"role"},
+ {NSAccessibilityRoleDescriptionAttribute, @"roleDescription"},
+ {NSAccessibilityRowHeaderUIElementsAttribute, @"rowHeaders"},
+ {NSAccessibilityRowIndexRangeAttribute, @"rowIndexRange"},
+ {NSAccessibilityRowsAttribute, @"rows"},
+ // TODO(aboxhall): expose
+ // NSAccessibilityServesAsTitleForUIElementsAttribute
+ {NSAccessibilityStartTextMarkerAttribute, @"startTextMarker"},
+ {NSAccessibilitySelectedAttribute, @"selected"},
+ {NSAccessibilitySelectedChildrenAttribute, @"selectedChildren"},
+ {NSAccessibilitySelectedTextAttribute, @"selectedText"},
+ {NSAccessibilitySelectedTextRangeAttribute, @"selectedTextRange"},
+ {NSAccessibilitySelectedTextMarkerRangeAttribute,
+ @"selectedTextMarkerRange"},
+ {NSAccessibilitySizeAttribute, @"size"},
+ {NSAccessibilitySortDirectionAttribute, @"sortDirection"},
+ {NSAccessibilitySubroleAttribute, @"subrole"},
+ {NSAccessibilityTabsAttribute, @"tabs"},
+ {NSAccessibilityTitleAttribute, @"title"},
+ {NSAccessibilityTitleUIElementAttribute, @"titleUIElement"},
+ {NSAccessibilityTopLevelUIElementAttribute, @"window"},
+ {NSAccessibilityURLAttribute, @"url"},
+ {NSAccessibilityValueAttribute, @"value"},
+ {NSAccessibilityValueDescriptionAttribute, @"valueDescription"},
+ {NSAccessibilityVisibleCharacterRangeAttribute, @"visibleCharacterRange"},
+ {NSAccessibilityVisibleCellsAttribute, @"visibleCells"},
+ {NSAccessibilityVisibleChildrenAttribute, @"visibleChildren"},
+ {NSAccessibilityVisibleColumnsAttribute, @"visibleColumns"},
+ {NSAccessibilityVisibleRowsAttribute, @"visibleRows"},
+ {NSAccessibilityVisitedAttribute, @"visited"},
+ {NSAccessibilityWindowAttribute, @"window"},
+ {@"AXLoaded", @"loaded"},
};
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
@@ -413,51 +504,64 @@ bool InitializeAccessibilityTreeSearch(
dict = nil;
}
-- (id)initWithObject:(BrowserAccessibility*)accessibility {
+- (instancetype)initWithObject:(BrowserAccessibility*)accessibility {
if ((self = [super init]))
browserAccessibility_ = accessibility;
return self;
}
- (void)detach {
- if (browserAccessibility_) {
+ if (browserAccessibility_)
NSAccessibilityUnregisterUniqueIdForUIElement(self);
- browserAccessibility_ = NULL;
- }
+ browserAccessibility_ = nullptr;
}
- (NSString*)accessKey {
+ if (![self instanceActive])
+ return nil;
return NSStringForStringAttribute(
browserAccessibility_, ui::AX_ATTR_ACCESS_KEY);
}
- (NSNumber*)ariaAtomic {
+ if (![self instanceActive])
+ return nil;
bool boolValue = browserAccessibility_->GetBoolAttribute(
ui::AX_ATTR_LIVE_ATOMIC);
return [NSNumber numberWithBool:boolValue];
}
- (NSNumber*)ariaBusy {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_BUSY)];
}
- (NSString*)ariaLive {
+ if (![self instanceActive])
+ return nil;
return NSStringForStringAttribute(
browserAccessibility_, ui::AX_ATTR_LIVE_STATUS);
}
-- (NSString*)ariaRelevant {
- return NSStringForStringAttribute(
- browserAccessibility_, ui::AX_ATTR_LIVE_RELEVANT);
-}
-
- (NSNumber*)ariaPosInSet {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithInt:
browserAccessibility_->GetIntAttribute(ui::AX_ATTR_POS_IN_SET)];
}
+- (NSString*)ariaRelevant {
+ if (![self instanceActive])
+ return nil;
+ return NSStringForStringAttribute(browserAccessibility_,
+ ui::AX_ATTR_LIVE_RELEVANT);
+}
+
- (NSNumber*)ariaSetSize {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithInt:
browserAccessibility_->GetIntAttribute(ui::AX_ATTR_SET_SIZE)];
}
@@ -465,13 +569,15 @@ bool InitializeAccessibilityTreeSearch(
// Returns an array of BrowserAccessibilityCocoa objects, representing the
// accessibility children of this object.
- (NSArray*)children {
+ if (![self instanceActive])
+ return nil;
if (!children_) {
uint32_t childCount = browserAccessibility_->PlatformChildCount();
children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
for (uint32_t index = 0; index < childCount; ++index) {
BrowserAccessibilityCocoa* child =
- browserAccessibility_->PlatformGetChild(index)->
- ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(
+ browserAccessibility_->PlatformGetChild(index));
if ([child isIgnored])
[children_ addObjectsFromArray:[child children]];
else
@@ -491,7 +597,7 @@ bool InitializeAccessibilityTreeSearch(
// a DCHECK in the future.
if (child) {
BrowserAccessibilityCocoa* child_cocoa =
- child->ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(child);
[children_ addObject:child_cocoa];
}
}
@@ -500,15 +606,19 @@ bool InitializeAccessibilityTreeSearch(
}
- (void)childrenChanged {
+ if (![self instanceActive])
+ return;
if (![self isIgnored]) {
children_.reset();
} else {
- [browserAccessibility_->GetParent()->ToBrowserAccessibilityCocoa()
- childrenChanged];
+ [ToBrowserAccessibilityCocoa(browserAccessibility_->GetParent())
+ childrenChanged];
}
}
- (NSArray*)columnHeaders {
+ if (![self instanceActive])
+ return nil;
if ([self internalRole] != ui::AX_ROLE_TABLE &&
[self internalRole] != ui::AX_ROLE_GRID) {
return nil;
@@ -522,12 +632,14 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* cell =
browserAccessibility_->manager()->GetFromID(id);
if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER)
- [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(cell)];
}
return ret;
}
- (NSValue*)columnIndexRange {
+ if (![self instanceActive])
+ return nil;
if (!browserAccessibility_->IsCellOrTableHeaderRole())
return nil;
@@ -543,6 +655,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSArray*)columns {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
for (BrowserAccessibilityCocoa* child in [self children]) {
if ([[child role] isEqualToString:NSAccessibilityColumnRole])
@@ -552,6 +666,9 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSString*)description {
+ if (![self instanceActive])
+ return nil;
+
// Mac OS X wants static text exposed in AXValue.
if ([self shouldExposeNameInAXValue])
return @"";
@@ -562,14 +679,18 @@ bool InitializeAccessibilityTreeSearch(
browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS);
ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
browserAccessibility_->GetIntAttribute(ui::AX_ATTR_NAME_FROM));
+ std::string name = browserAccessibility_->GetStringAttribute(
+ ui::AX_ATTR_NAME);
+
+ // VoiceOver ignores titleUIElement on non-control AX nodes, so this special
+ // case expressly returns a nonempty text name for these nodes.
if (nameFrom == ui::AX_NAME_FROM_RELATED_ELEMENT &&
labelledby_ids.size() == 1 &&
- browserAccessibility_->manager()->GetFromID(labelledby_ids[0])) {
- return @"";
+ browserAccessibility_->manager()->GetFromID(labelledby_ids[0]) &&
+ !browserAccessibility_->IsControl()) {
+ return base::SysUTF8ToNSString(name);
}
- std::string name = browserAccessibility_->GetStringAttribute(
- ui::AX_ATTR_NAME);
if (!name.empty()) {
// On Mac OS X, the accessible name of an object is exposed as its
// title if it comes from visible text, and as its description
@@ -620,6 +741,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSNumber*)disclosing {
+ if (![self instanceActive])
+ return nil;
if ([self internalRole] == ui::AX_ROLE_TREE_ITEM) {
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
@@ -629,12 +752,17 @@ bool InitializeAccessibilityTreeSearch(
}
- (id)disclosedByRow {
+ if (![self instanceActive])
+ return nil;
+
// The row that contains this row.
// It should be the same as the first parent that is a treeitem.
return nil;
}
- (NSNumber*)disclosureLevel {
+ if (![self instanceActive])
+ return nil;
ui::AXRole role = [self internalRole];
if (role == ui::AX_ROLE_ROW ||
role == ui::AX_ROLE_TREE_ITEM) {
@@ -650,36 +778,78 @@ bool InitializeAccessibilityTreeSearch(
}
- (id)disclosedRows {
+ if (![self instanceActive])
+ return nil;
+
// The rows that are considered inside this row.
return nil;
}
-- (NSString*)dropeffect {
- std::string dropEffect;
- if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffect))
- return base::SysUTF8ToNSString(dropEffect);
+- (NSString*)dropEffects {
+ if (![self instanceActive])
+ return nil;
+
+ std::string dropEffects;
+ if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffects))
+ return base::SysUTF8ToNSString(dropEffects);
return nil;
}
- (NSNumber*)enabled {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_ENABLED)];
}
+// Returns a text marker that points to the last character in the document that
+// can be selected with VoiceOver.
+- (id)endTextMarker {
+ if (![self instanceActive])
+ return nil;
+
+ const BrowserAccessibility* root =
+ browserAccessibility_->manager()->GetRoot();
+ if (!root)
+ return nil;
+
+ const BrowserAccessibility* last_text_object =
+ root->InternalDeepestLastChild();
+ if (last_text_object && !last_text_object->IsTextOnlyObject()) {
+ last_text_object =
+ BrowserAccessibilityManager::PreviousTextOnlyObject(last_text_object);
+ }
+ while (last_text_object) {
+ last_text_object =
+ BrowserAccessibilityManager::PreviousTextOnlyObject(last_text_object);
+ }
+ if (!last_text_object)
+ return nil;
+
+ return CreateTextMarker(*last_text_object,
+ last_text_object->GetText().length());
+}
+
- (NSNumber*)expanded {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
}
- (NSNumber*)focused {
+ if (![self instanceActive])
+ return nil;
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
NSNumber* ret = [NSNumber numberWithBool:
- manager->GetFocus(NULL) == browserAccessibility_];
+ manager->GetFocus() == browserAccessibility_];
return ret;
}
- (NSNumber*)grabbed {
+ if (![self instanceActive])
+ return nil;
std::string grabbed;
if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed) &&
grabbed == "true")
@@ -689,6 +859,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (id)header {
+ if (![self instanceActive])
+ return nil;
int headerElementId = -1;
if ([self internalRole] == ui::AX_ROLE_TABLE ||
[self internalRole] == ui::AX_ROLE_GRID) {
@@ -706,17 +878,21 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* headerObject =
browserAccessibility_->manager()->GetFromID(headerElementId);
if (headerObject)
- return headerObject->ToBrowserAccessibilityCocoa();
+ return ToBrowserAccessibilityCocoa(headerObject);
}
return nil;
}
- (NSString*)help {
+ if (![self instanceActive])
+ return nil;
return NSStringForStringAttribute(
browserAccessibility_, ui::AX_ATTR_DESCRIPTION);
}
- (NSNumber*)index {
+ if (![self instanceActive])
+ return nil;
if ([self internalRole] == ui::AX_ROLE_COLUMN) {
int columnIndex = browserAccessibility_->GetIntAttribute(
ui::AX_ATTR_TABLE_COLUMN_INDEX);
@@ -730,13 +906,43 @@ bool InitializeAccessibilityTreeSearch(
return nil;
}
+- (NSNumber*)insertionPointLineNumber {
+ if (![self instanceActive])
+ return nil;
+
+ // TODO(nektar): Deprecate sel_start and sel_end attributes.
+ int selStart, selEnd;
+ if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+ &selStart) ||
+ !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+ &selEnd)) {
+ return nil;
+ }
+
+ if (selStart > selEnd)
+ std::swap(selStart, selEnd);
+
+ const std::vector<int32_t>& line_breaks =
+ browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
+ for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
+ if (line_breaks[i] > selStart)
+ return [NSNumber numberWithInt:i];
+ }
+
+ return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+}
+
// Returns whether or not this node should be ignored in the
// accessibility tree.
- (BOOL)isIgnored {
+ if (![self instanceActive])
+ return YES;
return [[self role] isEqualToString:NSAccessibilityUnknownRole];
}
- (NSString*)invalid {
+ if (![self instanceActive])
+ return nil;
int invalidState;
if (!browserAccessibility_->GetIntAttribute(
ui::AX_ATTR_INVALID_STATE, &invalidState))
@@ -768,7 +974,16 @@ bool InitializeAccessibilityTreeSearch(
return @"false";
}
+- (NSNumber*)isMultiSelectable {
+ if (![self instanceActive])
+ return nil;
+ return [NSNumber numberWithBool:GetState(browserAccessibility_,
+ ui::AX_STATE_MULTISELECTABLE)];
+}
+
- (NSString*)placeholderValue {
+ if (![self instanceActive])
+ return nil;
ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
browserAccessibility_->GetIntAttribute(ui::AX_ATTR_NAME_FROM));
if (nameFrom == ui::AX_NAME_FROM_PLACEHOLDER) {
@@ -787,6 +1002,7 @@ bool InitializeAccessibilityTreeSearch(
browserAccessibility_, ui::AX_ATTR_PLACEHOLDER);
}
+// private
- (void)addLinkedUIElementsFromAttribute:(ui::AXIntListAttribute)attribute
addTo:(NSMutableArray*)outArray {
const std::vector<int32_t>& attributeValues =
@@ -795,10 +1011,11 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* element =
browserAccessibility_->manager()->GetFromID(attributeValues[i]);
if (element)
- [outArray addObject:element->ToBrowserAccessibilityCocoa()];
+ [outArray addObject:ToBrowserAccessibilityCocoa(element)];
}
}
+// private
- (NSArray*)linkedUIElements {
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
[self addLinkedUIElementsFromAttribute:ui::AX_ATTR_CONTROLS_IDS addTo:ret];
@@ -809,28 +1026,38 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSNumber*)loaded {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:YES];
}
- (NSNumber*)loadingProgress {
+ if (![self instanceActive])
+ return nil;
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
float floatValue = manager->GetTreeData().loading_progress;
return [NSNumber numberWithFloat:floatValue];
}
- (NSNumber*)maxValue {
+ if (![self instanceActive])
+ return nil;
float floatValue = browserAccessibility_->GetFloatAttribute(
ui::AX_ATTR_MAX_VALUE_FOR_RANGE);
return [NSNumber numberWithFloat:floatValue];
}
- (NSNumber*)minValue {
+ if (![self instanceActive])
+ return nil;
float floatValue = browserAccessibility_->GetFloatAttribute(
ui::AX_ATTR_MIN_VALUE_FOR_RANGE);
return [NSNumber numberWithFloat:floatValue];
}
- (NSString*)orientation {
+ if (![self instanceActive])
+ return nil;
if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL))
return NSAccessibilityVerticalOrientationValue;
else if (GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL))
@@ -840,23 +1067,29 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSNumber*)numberOfCharacters {
+ if (![self instanceActive])
+ return nil;
base::string16 value = browserAccessibility_->GetValue();
- return [NSNumber numberWithInt:value.size()];
+ return [NSNumber numberWithUnsignedInt:value.size()];
}
// The origin of this accessibility object in the page's document.
// This is relative to webkit's top-left origin, not Cocoa's
// bottom-left origin.
- (NSPoint)origin {
+ if (![self instanceActive])
+ return NSMakePoint(0, 0);
gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
return NSMakePoint(bounds.x(), bounds.y());
}
- (id)parent {
+ if (![self instanceActive])
+ return nil;
// A nil parent means we're the root.
if (browserAccessibility_->GetParent()) {
return NSAccessibilityUnignoredAncestor(
- browserAccessibility_->GetParent()->ToBrowserAccessibilityCocoa());
+ ToBrowserAccessibilityCocoa(browserAccessibility_->GetParent()));
} else {
// Hook back up to RenderWidgetHostViewCocoa.
BrowserAccessibilityManagerMac* manager =
@@ -867,6 +1100,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSValue*)position {
+ if (![self instanceActive])
+ return nil;
NSPoint origin = [self origin];
NSSize size = [[self size] sizeValue];
NSPoint pointInScreen = [self pointInScreen:origin size:size];
@@ -874,17 +1109,21 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSNumber*)required {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_REQUIRED)];
}
// Returns an enum indicating the role from browserAccessibility_.
+// internal
- (ui::AXRole)internalRole {
return static_cast<ui::AXRole>(browserAccessibility_->GetRole());
}
// Returns true if this should expose its accessible name in AXValue.
-- (bool)shouldExposeNameInAXValue {
+// internal
+- (BOOL)shouldExposeNameInAXValue {
switch ([self internalRole]) {
case ui::AX_ROLE_LIST_BOX_OPTION:
case ui::AX_ROLE_LIST_MARKER:
@@ -896,19 +1135,24 @@ bool InitializeAccessibilityTreeSearch(
}
}
+// internal
- (content::BrowserAccessibilityDelegate*)delegate {
- return browserAccessibility_->manager() ?
- browserAccessibility_->manager()->delegate() :
- nil;
+ return [self instanceActive] ? browserAccessibility_->manager()->delegate()
+ : nil;
}
- (content::BrowserAccessibility*)browserAccessibility {
return browserAccessibility_;
}
+- (BOOL)instanceActive {
+ return browserAccessibility_ && browserAccessibility_->instance_active();
+}
+
+// internal
- (NSPoint)pointInScreen:(NSPoint)origin
size:(NSSize)size {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return NSZeroPoint;
// Get the delegate for the topmost BrowserAccessibilityManager, because
@@ -926,7 +1170,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns a string indicating the NSAccessibility role of this object.
- (NSString*)role {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
ui::AXRole role = [self internalRole];
@@ -963,6 +1207,8 @@ bool InitializeAccessibilityTreeSearch(
// Returns a string indicating the role description of this object.
- (NSString*)roleDescription {
+ if (![self instanceActive])
+ return nil;
NSString* role = [self role];
ContentClient* content_client = content::GetContentClient();
@@ -1013,13 +1259,13 @@ bool InitializeAccessibilityTreeSearch(
IDS_AX_ROLE_COMPLEMENTARY));
case ui::AX_ROLE_CONTENT_INFO:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
- IDS_AX_ROLE_ADDRESS));
+ IDS_AX_ROLE_CONTENT_INFO));
case ui::AX_ROLE_DESCRIPTION_LIST:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_DESCRIPTION_LIST));
case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
- IDS_AX_ROLE_DESCRIPTION_DETAIL));
+ IDS_AX_ROLE_DEFINITION));
case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_DESCRIPTION_TERM));
@@ -1071,6 +1317,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSArray*)rowHeaders {
+ if (![self instanceActive])
+ return nil;
if ([self internalRole] != ui::AX_ROLE_TABLE &&
[self internalRole] != ui::AX_ROLE_GRID) {
return nil;
@@ -1084,12 +1332,14 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* cell =
browserAccessibility_->manager()->GetFromID(id);
if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER)
- [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(cell)];
}
return ret;
}
- (NSValue*)rowIndexRange {
+ if (![self instanceActive])
+ return nil;
if (!browserAccessibility_->IsCellOrTableHeaderRole())
return nil;
@@ -1105,6 +1355,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSArray*)rows {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
if ([self internalRole] == ui::AX_ROLE_TABLE||
@@ -1122,24 +1374,35 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* rowElement =
browserAccessibility_->manager()->GetFromID(id);
if (rowElement)
- [ret addObject:rowElement->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(rowElement)];
}
}
return ret;
}
+- (NSNumber*)selected {
+ if (![self instanceActive])
+ return nil;
+ // TODO(nektar): Implement.
+ return [NSNumber numberWithBool:NO];
+}
+
- (NSArray*)selectedChildren {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
- BrowserAccessibility* focusedChild = manager->GetFocus(browserAccessibility_);
+ BrowserAccessibility* focusedChild = manager->GetFocus();
+ if (!focusedChild->IsDescendantOf(browserAccessibility_))
+ focusedChild = nullptr;
// If it's not multiselectable, try to skip iterating over the
// children.
if (!GetState(browserAccessibility_, ui::AX_STATE_MULTISELECTABLE)) {
// First try the focused child.
if (focusedChild && focusedChild != browserAccessibility_) {
- [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(focusedChild)];
return ret;
}
@@ -1150,7 +1413,7 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* activeDescendant =
manager->GetFromID(activeDescendantId);
if (activeDescendant) {
- [ret addObject:activeDescendant->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(activeDescendant)];
return ret;
}
}
@@ -1164,49 +1427,149 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* child =
browserAccessibility_->PlatformGetChild(index);
if (child->HasState(ui::AX_STATE_SELECTED))
- [ret addObject:child->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(child)];
}
// And if nothing's selected but one has focus, use the focused one.
if ([ret count] == 0 &&
focusedChild &&
focusedChild != browserAccessibility_) {
- [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(focusedChild)];
}
return ret;
}
-// Returns the size of this object.
+- (NSString*)selectedText {
+ if (![self instanceActive])
+ return nil;
+
+ // TODO(nektar): Deprecate sel_start and sel_end attributes.
+ int selStart, selEnd;
+ if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+ &selStart) ||
+ !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+ &selEnd)) {
+ return nil;
+ }
+
+ if (selStart > selEnd)
+ std::swap(selStart, selEnd);
+
+ int selLength = selEnd - selStart;
+ base::string16 value = browserAccessibility_->GetValue();
+ return base::SysUTF16ToNSString(value.substr(selStart, selLength));
+}
+
+- (NSValue*)selectedTextRange {
+ if (![self instanceActive])
+ return nil;
+
+ // TODO(nektar): Deprecate sel_start and sel_end attributes.
+ int selStart, selEnd;
+ if (!browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
+ &selStart) ||
+ !browserAccessibility_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END,
+ &selEnd)) {
+ return nil;
+ }
+
+ if (selStart > selEnd)
+ std::swap(selStart, selEnd);
+
+ int selLength = selEnd - selStart;
+ return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
+}
+
+- (id)selectedTextMarkerRange {
+ if (![self instanceActive])
+ return nil;
+
+ BrowserAccessibilityManager* manager = browserAccessibility_->manager();
+ if (!manager)
+ return nil;
+
+ int32_t anchorId = manager->GetTreeData().sel_anchor_object_id;
+ const BrowserAccessibility* anchorObject = manager->GetFromID(anchorId);
+ if (!anchorObject)
+ return nil;
+
+ int32_t focusId = manager->GetTreeData().sel_focus_object_id;
+ const BrowserAccessibility* focusObject = manager->GetFromID(focusId);
+ if (!focusObject)
+ return nil;
+
+ int anchorOffset = manager->GetTreeData().sel_anchor_offset;
+ int focusOffset = manager->GetTreeData().sel_focus_offset;
+ if (anchorOffset < 0 || focusOffset < 0)
+ return nil;
+
+ return CreateTextMarkerRange(*anchorObject, anchorOffset, *focusObject,
+ focusOffset);
+}
+
- (NSValue*)size {
+ if (![self instanceActive])
+ return nil;
gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
}
- (NSString*)sortDirection {
+ if (![self instanceActive])
+ return nil;
int sortDirection;
if (!browserAccessibility_->GetIntAttribute(
ui::AX_ATTR_SORT_DIRECTION, &sortDirection))
- return @"";
+ return nil;
switch (sortDirection) {
case ui::AX_SORT_DIRECTION_UNSORTED:
- return @"";
+ return nil;
case ui::AX_SORT_DIRECTION_ASCENDING:
- return @"AXSortDirectionAscending";
+ return NSAccessibilityAscendingSortDirectionValue;
case ui::AX_SORT_DIRECTION_DESCENDING:
- return @"AXSortDirectionDescending";
+ return NSAccessibilityDescendingSortDirectionValue;
case ui::AX_SORT_DIRECTION_OTHER:
- return @"AXSortDirectionUnknown";
+ return NSAccessibilityUnknownSortDirectionValue;
default:
NOTREACHED();
}
- return @"";
+ return nil;
+}
+
+// Returns a text marker that points to the first character in the document that
+// can be selected with VoiceOver.
+- (id)startTextMarker {
+ if (![self instanceActive])
+ return nil;
+
+ const BrowserAccessibility* root =
+ browserAccessibility_->manager()->GetRoot();
+ if (!root)
+ return nil;
+
+ const BrowserAccessibility* first_text_object =
+ root->InternalDeepestFirstChild();
+ if (first_text_object && !first_text_object->IsTextOnlyObject()) {
+ first_text_object =
+ BrowserAccessibilityManager::NextTextOnlyObject(first_text_object);
+ }
+ while (first_text_object) {
+ first_text_object =
+ BrowserAccessibilityManager::NextTextOnlyObject(first_text_object);
+ }
+ if (!first_text_object)
+ return nil;
+
+ return CreateTextMarker(*first_text_object, 0);
}
// Returns a subrole based upon the role.
- (NSString*) subrole {
+ if (![self instanceActive])
+ return nil;
ui::AXRole browserAccessibilityRole = [self internalRole];
if (browserAccessibilityRole == ui::AX_ROLE_TEXT_FIELD &&
GetState(browserAccessibility_, ui::AX_STATE_PROTECTED)) {
@@ -1224,6 +1587,8 @@ bool InitializeAccessibilityTreeSearch(
// Returns all tabs in this subtree.
- (NSArray*)tabs {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* tabSubtree = [[[NSMutableArray alloc] init] autorelease];
if ([self internalRole] == ui::AX_ROLE_TAB)
@@ -1239,6 +1604,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSString*)title {
+ if (![self instanceActive])
+ return nil;
// Mac OS X wants static text exposed in AXValue.
if ([self shouldExposeNameInAXValue])
return @"";
@@ -1269,6 +1636,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (id)titleUIElement {
+ if (![self instanceActive])
+ return nil;
std::vector<int32_t> labelledby_ids =
browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS);
ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
@@ -1278,13 +1647,15 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* titleElement =
browserAccessibility_->manager()->GetFromID(labelledby_ids[0]);
if (titleElement)
- return titleElement->ToBrowserAccessibilityCocoa();
+ return ToBrowserAccessibilityCocoa(titleElement);
}
return nil;
}
- (NSURL*)url {
+ if (![self instanceActive])
+ return nil;
std::string url;
if ([[self role] isEqualToString:@"AXWebArea"])
url = browserAccessibility_->manager()->GetTreeData().url;
@@ -1298,6 +1669,8 @@ bool InitializeAccessibilityTreeSearch(
}
- (id)value {
+ if (![self instanceActive])
+ return nil;
NSString* role = [self role];
if ([self shouldExposeNameInAXValue]) {
return NSStringForStringAttribute(
@@ -1347,11 +1720,11 @@ bool InitializeAccessibilityTreeSearch(
return [NSNumber numberWithFloat:floatValue];
}
} else if ([role isEqualToString:NSAccessibilityColorWellRole]) {
- int color = browserAccessibility_->GetIntAttribute(
- ui::AX_ATTR_COLOR_VALUE);
- int red = (color >> 16) & 0xFF;
- int green = (color >> 8) & 0xFF;
- int blue = color & 0xFF;
+ unsigned int color = static_cast<unsigned int>(
+ browserAccessibility_->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE));
+ unsigned int red = SkColorGetR(color);
+ unsigned int green = SkColorGetG(color);
+ unsigned int blue = SkColorGetB(color);
// This string matches the one returned by a native Mac color well.
return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1",
red / 255., green / 255., blue / 255.];
@@ -1361,17 +1734,23 @@ bool InitializeAccessibilityTreeSearch(
}
- (NSString*)valueDescription {
+ if (![self instanceActive])
+ return nil;
if (browserAccessibility_)
return base::SysUTF16ToNSString(browserAccessibility_->GetValue());
return nil;
}
- (NSValue*)visibleCharacterRange {
+ if (![self instanceActive])
+ return nil;
base::string16 value = browserAccessibility_->GetValue();
return [NSValue valueWithRange:NSMakeRange(0, value.size())];
}
- (NSArray*)visibleCells {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
const std::vector<int32_t>& uniqueCellIds =
browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS);
@@ -1380,38 +1759,45 @@ bool InitializeAccessibilityTreeSearch(
BrowserAccessibility* cell =
browserAccessibility_->manager()->GetFromID(id);
if (cell)
- [ret addObject:cell->ToBrowserAccessibilityCocoa()];
+ [ret addObject:ToBrowserAccessibilityCocoa(cell)];
}
return ret;
}
- (NSArray*)visibleChildren {
+ if (![self instanceActive])
+ return nil;
NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
uint32_t childCount = browserAccessibility_->PlatformChildCount();
for (uint32_t index = 0; index < childCount; ++index) {
- BrowserAccessibilityCocoa* child =
- browserAccessibility_->PlatformGetChild(index)->
- ToBrowserAccessibilityCocoa();
+ BrowserAccessibilityCocoa* child = ToBrowserAccessibilityCocoa(
+ browserAccessibility_->PlatformGetChild(index));
[ret addObject:child];
}
return ret;
}
- (NSArray*)visibleColumns {
+ if (![self instanceActive])
+ return nil;
return [self columns];
}
- (NSArray*)visibleRows {
+ if (![self instanceActive])
+ return nil;
return [self rows];
}
- (NSNumber*)visited {
+ if (![self instanceActive])
+ return nil;
return [NSNumber numberWithBool:
GetState(browserAccessibility_, ui::AX_STATE_VISITED)];
}
- (id)window {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
BrowserAccessibilityManagerMac* manager =
@@ -1433,7 +1819,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns the requested text range from this object's value attribute.
- (NSString*)valueForRange:(NSRange)range {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
base::string16 value = browserAccessibility_->GetValue();
@@ -1446,7 +1832,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns the accessibility value for the given attribute. If the value isn't
// supported this will return nil.
- (id)accessibilityAttributeValue:(NSString*)attribute {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
SEL selector =
@@ -1454,41 +1840,15 @@ bool InitializeAccessibilityTreeSearch(
if (selector)
return [self performSelector:selector];
- // TODO(dtseng): refactor remaining attributes.
- int selStart, selEnd;
- if (browserAccessibility_->GetIntAttribute(
- ui::AX_ATTR_TEXT_SEL_START, &selStart) &&
- browserAccessibility_->
- GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &selEnd)) {
- if (selStart > selEnd)
- std::swap(selStart, selEnd);
- int selLength = selEnd - selStart;
- if ([attribute isEqualToString:
- NSAccessibilityInsertionPointLineNumberAttribute]) {
- const std::vector<int32_t>& line_breaks =
- browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
- for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
- if (line_breaks[i] > selStart)
- return [NSNumber numberWithInt:i];
- }
- return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
- }
- if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
- base::string16 value = browserAccessibility_->GetValue();
- return base::SysUTF16ToNSString(value.substr(selStart, selLength));
- }
- if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
- return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
- }
- }
return nil;
}
// Returns the accessibility value for the given attribute and parameter. If the
// value isn't supported this will return nil.
+// TODO(nektar): Implement all unimplemented attributes, e.g. text markers.
- (id)accessibilityAttributeValue:(NSString*)attribute
forParameter:(id)parameter {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
const std::vector<int32_t>& line_breaks =
@@ -1577,7 +1937,7 @@ bool InitializeAccessibilityTreeSearch(
continue;
}
if (colIndex == column)
- return cell->ToBrowserAccessibilityCocoa();
+ return ToBrowserAccessibilityCocoa(cell);
if (colIndex > column)
break;
}
@@ -1585,6 +1945,96 @@ bool InitializeAccessibilityTreeSearch(
return nil;
}
+ if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
+ BrowserAccessibility* object;
+ int offset;
+ if (GetTextMarkerData(parameter, &object, &offset))
+ return ToBrowserAccessibilityCocoa(object);
+
+ return nil;
+ }
+
+ if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
+ return CreateTextMarkerRange(*browserAccessibility_, 0,
+ *browserAccessibility_,
+ browserAccessibility_->GetText().length());
+ }
+
+ if ([attribute isEqualToString:@"AXStringForTextMarkerRange"])
+ return GetTextForTextMarkerRange(parameter);
+
+ if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"]) {
+ NSString* text = GetTextForTextMarkerRange(parameter);
+ return [[[NSAttributedString alloc] initWithString:text] autorelease];
+ }
+
+ if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
+ BrowserAccessibility* object;
+ int offset;
+ if (!GetTextMarkerData(parameter, &object, &offset))
+ return nil;
+
+ DCHECK(object);
+ if ((object->IsSimpleTextControl() || object->IsTextOnlyObject()) &&
+ offset < static_cast<int>(object->GetText().length())) {
+ ++offset;
+ } else {
+ do {
+ object = BrowserAccessibilityManager::NextTextOnlyObject(object);
+ } while (
+ object &&
+ !(object->IsTextOnlyObject() && object->GetText().length() == 0));
+ if (!object)
+ return nil;
+
+ offset = 0;
+ }
+
+ return CreateTextMarker(*object, offset);
+ }
+
+ if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
+ BrowserAccessibility* object;
+ int offset;
+ if (!GetTextMarkerData(parameter, &object, &offset))
+ return nil;
+
+ DCHECK(object);
+ if ((object->IsSimpleTextControl() || object->IsTextOnlyObject()) &&
+ offset > 0) {
+ --offset;
+ } else {
+ do {
+ object = BrowserAccessibilityManager::PreviousTextOnlyObject(object);
+ } while (
+ object &&
+ !(object->IsTextOnlyObject() && object->GetText().length() == 0));
+ if (!object)
+ return nil;
+
+ offset = object->GetText().length() - 1;
+ }
+
+ return CreateTextMarker(*object, offset);
+ }
+
+ if ([attribute
+ isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
+ BrowserAccessibility* object;
+ int offset;
+ if (!GetTextMarkerData(parameter, &object, &offset))
+ return nil;
+
+ DCHECK(object);
+ offset = object->GetWordStartBoundary(offset, ui::BACKWARDS_DIRECTION);
+ return CreateTextMarker(*object, offset);
+ }
+
+ if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
+ NSString* text = GetTextForTextMarkerRange(parameter);
+ return [NSNumber numberWithInt:[text length]];
+ }
+
if ([attribute isEqualToString:
NSAccessibilityBoundsForRangeParameterizedAttribute]) {
if ([self internalRole] != ui::AX_ROLE_STATIC_TEXT)
@@ -1599,6 +2049,7 @@ bool InitializeAccessibilityTreeSearch(
pointInScreen.x, pointInScreen.y, rect.width(), rect.height());
return [NSValue valueWithRect:nsrect];
}
+
if ([attribute isEqualToString:@"AXUIElementCountForSearchPredicate"]) {
OneShotAccessibilityTreeSearch search(browserAccessibility_);
if (InitializeAccessibilityTreeSearch(&search, parameter))
@@ -1613,63 +2064,90 @@ bool InitializeAccessibilityTreeSearch(
NSMutableArray* result = [NSMutableArray arrayWithCapacity:count];
for (size_t i = 0; i < count; ++i) {
BrowserAccessibility* match = search.GetMatchAtIndex(i);
- [result addObject:match->ToBrowserAccessibilityCocoa()];
+ [result addObject:ToBrowserAccessibilityCocoa(match)];
}
return result;
}
return nil;
}
- // TODO(dtseng): support the following attributes.
- if ([attribute isEqualTo:
- NSAccessibilityRangeForPositionParameterizedAttribute] ||
- [attribute isEqualTo:
- NSAccessibilityRangeForIndexParameterizedAttribute] ||
- [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] ||
- [attribute isEqualTo:
- NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
- return nil;
- }
return nil;
}
// Returns an array of parameterized attributes names that this object will
// respond to.
- (NSArray*)accessibilityParameterizedAttributeNames {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
// General attributes.
- NSMutableArray* ret = [NSMutableArray arrayWithObjects:
- @"AXUIElementCountForSearchPredicate",
- @"AXUIElementsForSearchPredicate",
- nil];
+ NSMutableArray* ret = [NSMutableArray
+ arrayWithObjects:
+ @"AXUIElementForTextMarker", @"AXTextMarkerRangeForUIElement",
+ @"AXLineForTextMarker", @"AXTextMarkerRangeForLine",
+ @"AXStringForTextMarkerRange", @"AXTextMarkerForPosition",
+ @"AXBoundsForTextMarkerRange",
+ @"AXAttributedStringForTextMarkerRange",
+ @"AXTextMarkerRangeForUnorderedTextMarkers",
+ @"AXNextTextMarkerForTextMarker",
+ @"AXPreviousTextMarkerForTextMarker",
+ @"AXLeftWordTextMarkerRangeForTextMarker",
+ @"AXRightWordTextMarkerRangeForTextMarker",
+ @"AXLeftLineTextMarkerRangeForTextMarker",
+ @"AXRightLineTextMarkerRangeForTextMarker",
+ @"AXSentenceTextMarkerRangeForTextMarker",
+ @"AXParagraphTextMarkerRangeForTextMarker",
+ @"AXNextWordEndTextMarkerForTextMarker",
+ @"AXPreviousWordStartTextMarkerForTextMarker",
+ @"AXNextLineEndTextMarkerForTextMarker",
+ @"AXPreviousLineStartTextMarkerForTextMarker",
+ @"AXNextSentenceEndTextMarkerForTextMarker",
+ @"AXPreviousSentenceStartTextMarkerForTextMarker",
+ @"AXNextParagraphEndTextMarkerForTextMarker",
+ @"AXPreviousParagraphStartTextMarkerForTextMarker",
+ @"AXStyleTextMarkerRangeForTextMarker", @"AXLengthForTextMarkerRange",
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute,
+ NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
+ NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute,
+ NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute,
+ NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute,
+ NSAccessibilitySelectTextWithCriteriaParameterizedAttribute, nil];
if ([[self role] isEqualToString:NSAccessibilityTableRole] ||
[[self role] isEqualToString:NSAccessibilityGridRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityCellForColumnAndRowParameterizedAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityCellForColumnAndRowParameterizedAttribute
+ ]];
}
if (browserAccessibility_->HasState(ui::AX_STATE_EDITABLE)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityLineForIndexParameterizedAttribute,
- NSAccessibilityRangeForLineParameterizedAttribute,
- NSAccessibilityStringForRangeParameterizedAttribute,
- NSAccessibilityRangeForPositionParameterizedAttribute,
- NSAccessibilityRangeForIndexParameterizedAttribute,
- NSAccessibilityBoundsForRangeParameterizedAttribute,
- NSAccessibilityRTFForRangeParameterizedAttribute,
- NSAccessibilityAttributedStringForRangeParameterizedAttribute,
- NSAccessibilityStyleRangeForIndexParameterizedAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+ NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute
+ ]];
}
if ([self internalRole] == ui::AX_ROLE_STATIC_TEXT) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityBoundsForRangeParameterizedAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityBoundsForRangeParameterizedAttribute
+ ]];
+ }
+
+ if ([self internalRole] == ui::AX_ROLE_ROOT_WEB_AREA ||
+ [self internalRole] == ui::AX_ROLE_WEB_AREA) {
+ [ret addObjectsFromArray: @[
+ NSAccessibilityTextMarkerIsValidParameterizedAttribute,
+ NSAccessibilityIndexForTextMarkerParameterizedAttribute,
+ NSAccessibilityTextMarkerForIndexParameterizedAttribute]];
}
return ret;
@@ -1677,20 +2155,27 @@ bool InitializeAccessibilityTreeSearch(
// Returns an array of action names that this object will respond to.
- (NSArray*)accessibilityActionNames {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
- NSMutableArray* ret =
- [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction];
- NSString* role = [self role];
- // TODO(dtseng): this should only get set when there's a default action.
- if (![role isEqualToString:NSAccessibilityStaticTextRole] &&
- ![role isEqualToString:NSAccessibilityTextFieldRole] &&
- ![role isEqualToString:NSAccessibilityTextAreaRole]) {
- [ret addObject:NSAccessibilityPressAction];
+ NSMutableArray* actions = [NSMutableArray
+ arrayWithObjects:NSAccessibilityShowMenuAction,
+ NSAccessibilityScrollToVisibleAction, nil];
+
+ // VoiceOver expects the "press" action to be first.
+ if (browserAccessibility_->IsClickable())
+ [actions insertObject:NSAccessibilityPressAction atIndex:0];
+
+ if (browserAccessibility_->IsMenuRelated())
+ [actions addObject:NSAccessibilityCancelAction];
+
+ if ([self internalRole] == ui::AX_ROLE_SLIDER) {
+ [actions addObjectsFromArray:@[
+ NSAccessibilityIncrementAction, NSAccessibilityDecrementAction
+ ]];
}
- return ret;
+ return actions;
}
// Returns a sub-array of values for the given attribute value, starting at
@@ -1702,7 +2187,7 @@ bool InitializeAccessibilityTreeSearch(
- (NSArray*)accessibilityArrayAttributeValues:(NSString*)attribute
index:(NSUInteger)index
maxCount:(NSUInteger)maxCount {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
NSArray* fullArray = [self accessibilityAttributeValue:attribute];
@@ -1722,7 +2207,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns the count of the specified accessibility array attribute.
- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return 0;
NSArray* fullArray = [self accessibilityAttributeValue:attribute];
@@ -1731,83 +2216,78 @@ bool InitializeAccessibilityTreeSearch(
// Returns the list of accessibility attributes that this object supports.
- (NSArray*)accessibilityAttributeNames {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
// General attributes.
- NSMutableArray* ret = [NSMutableArray arrayWithObjects:
- NSAccessibilityChildrenAttribute,
- NSAccessibilityDescriptionAttribute,
- NSAccessibilityEnabledAttribute,
- NSAccessibilityFocusedAttribute,
- NSAccessibilityHelpAttribute,
- NSAccessibilityLinkedUIElementsAttribute,
- NSAccessibilityParentAttribute,
- NSAccessibilityPositionAttribute,
- NSAccessibilityRoleAttribute,
- NSAccessibilityRoleDescriptionAttribute,
- NSAccessibilitySizeAttribute,
- NSAccessibilitySubroleAttribute,
- NSAccessibilityTitleAttribute,
- NSAccessibilityTopLevelUIElementAttribute,
- NSAccessibilityValueAttribute,
- NSAccessibilityWindowAttribute,
- @"AXAccessKey",
- @"AXInvalid",
- @"AXVisited",
- nil];
+ NSMutableArray* ret = [NSMutableArray
+ arrayWithObjects:NSAccessibilityAccessKeyAttribute,
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityEndTextMarkerAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityInvalidAttribute,
+ NSAccessibilityLinkedUIElementsAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilitySelectedTextMarkerRangeAttribute,
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityStartTextMarkerAttribute,
+ NSAccessibilitySubroleAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityTitleUIElementAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityVisitedAttribute,
+ NSAccessibilityWindowAttribute, nil];
// Specific role attributes.
NSString* role = [self role];
NSString* subrole = [self subrole];
if ([role isEqualToString:NSAccessibilityTableRole] ||
[role isEqualToString:NSAccessibilityGridRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityColumnsAttribute,
- NSAccessibilityVisibleColumnsAttribute,
- NSAccessibilityRowsAttribute,
- NSAccessibilityVisibleRowsAttribute,
- NSAccessibilityVisibleCellsAttribute,
- NSAccessibilityHeaderAttribute,
- NSAccessibilityColumnHeaderUIElementsAttribute,
- NSAccessibilityRowHeaderUIElementsAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityColumnsAttribute, NSAccessibilityVisibleColumnsAttribute,
+ NSAccessibilityRowsAttribute, NSAccessibilityVisibleRowsAttribute,
+ NSAccessibilityVisibleCellsAttribute, NSAccessibilityHeaderAttribute,
+ NSAccessibilityColumnHeaderUIElementsAttribute,
+ NSAccessibilityRowHeaderUIElementsAttribute
+ ]];
} else if ([role isEqualToString:NSAccessibilityColumnRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityIndexAttribute,
- NSAccessibilityHeaderAttribute,
- NSAccessibilityRowsAttribute,
- NSAccessibilityVisibleRowsAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityIndexAttribute, NSAccessibilityHeaderAttribute,
+ NSAccessibilityRowsAttribute, NSAccessibilityVisibleRowsAttribute
+ ]];
} else if ([role isEqualToString:NSAccessibilityCellRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityColumnIndexRangeAttribute,
- NSAccessibilityRowIndexRangeAttribute,
- @"AXSortDirection",
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityColumnIndexRangeAttribute,
+ NSAccessibilityRowIndexRangeAttribute, @"AXSortDirection"
+ ]];
} else if ([role isEqualToString:@"AXWebArea"]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXLoaded",
- @"AXLoadingProgress",
- nil]];
+ [ret addObjectsFromArray:@[
+ @"AXLoaded", NSAccessibilityLoadingProgressAttribute
+ ]];
} else if ([role isEqualToString:NSAccessibilityTabGroupRole]) {
[ret addObject:NSAccessibilityTabsAttribute];
} else if ([role isEqualToString:NSAccessibilityProgressIndicatorRole] ||
[role isEqualToString:NSAccessibilitySliderRole] ||
[role isEqualToString:NSAccessibilityIncrementorRole] ||
[role isEqualToString:NSAccessibilityScrollBarRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityMaxValueAttribute,
- NSAccessibilityMinValueAttribute,
- NSAccessibilityValueDescriptionAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityMaxValueAttribute, NSAccessibilityMinValueAttribute,
+ NSAccessibilityValueDescriptionAttribute
+ ]];
} else if ([subrole isEqualToString:NSAccessibilityOutlineRowSubrole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityDisclosingAttribute,
- NSAccessibilityDisclosedByRowAttribute,
- NSAccessibilityDisclosureLevelAttribute,
- NSAccessibilityDisclosedRowsAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityDisclosingAttribute,
+ NSAccessibilityDisclosedByRowAttribute,
+ NSAccessibilityDisclosureLevelAttribute,
+ NSAccessibilityDisclosedRowsAttribute
+ ]];
} else if ([role isEqualToString:NSAccessibilityRowRole]) {
if (browserAccessibility_->GetParent()) {
base::string16 parentRole;
@@ -1815,126 +2295,99 @@ bool InitializeAccessibilityTreeSearch(
"role", &parentRole);
const base::string16 treegridRole(base::ASCIIToUTF16("treegrid"));
if (parentRole == treegridRole) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityDisclosingAttribute,
- NSAccessibilityDisclosedByRowAttribute,
- NSAccessibilityDisclosureLevelAttribute,
- NSAccessibilityDisclosedRowsAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityDisclosingAttribute,
+ NSAccessibilityDisclosedByRowAttribute,
+ NSAccessibilityDisclosureLevelAttribute,
+ NSAccessibilityDisclosedRowsAttribute
+ ]];
} else {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityIndexAttribute,
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityIndexAttribute ]];
}
}
} else if ([role isEqualToString:NSAccessibilityListRole]) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilitySelectedChildrenAttribute,
- NSAccessibilityVisibleChildrenAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilitySelectedChildrenAttribute,
+ NSAccessibilityVisibleChildrenAttribute
+ ]];
}
// Caret navigation and text selection attributes.
if (browserAccessibility_->HasState(ui::AX_STATE_EDITABLE)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityInsertionPointLineNumberAttribute,
- NSAccessibilityNumberOfCharactersAttribute,
- NSAccessibilitySelectedTextAttribute,
- NSAccessibilitySelectedTextRangeAttribute,
- NSAccessibilityVisibleCharacterRangeAttribute,
- nil]];
+ [ret addObjectsFromArray:@[
+ NSAccessibilityInsertionPointLineNumberAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute
+ ]];
}
// Add the url attribute only if it has a valid url.
if ([self url] != nil) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityURLAttribute,
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityURLAttribute ]];
}
// Position in set and Set size
if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_POS_IN_SET)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIAPosInSet",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIAPosInSetAttribute ]];
}
if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_SET_SIZE)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIASetSize",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIASetSizeAttribute ]];
}
// Live regions.
if (browserAccessibility_->HasStringAttribute(
ui::AX_ATTR_LIVE_STATUS)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIALive",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIALiveAttribute ]];
}
if (browserAccessibility_->HasStringAttribute(
ui::AX_ATTR_LIVE_RELEVANT)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIARelevant",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIARelevantAttribute ]];
}
if (browserAccessibility_->HasBoolAttribute(
ui::AX_ATTR_LIVE_ATOMIC)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIAAtomic",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIAAtomicAttribute ]];
}
if (browserAccessibility_->HasBoolAttribute(
ui::AX_ATTR_LIVE_BUSY)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXARIABusy",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityARIABusyAttribute ]];
}
std::string dropEffect;
if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffect)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXDropEffects",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityDropEffectsAttribute ]];
}
std::string grabbed;
if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXGrabbed",
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityGrabbedAttribute ]];
}
// Add expanded attribute only if it has expanded or collapsed state.
if (GetState(browserAccessibility_, ui::AX_STATE_EXPANDED) ||
GetState(browserAccessibility_, ui::AX_STATE_COLLAPSED)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityExpandedAttribute,
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityExpandedAttribute ]];
}
if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL)
|| GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityOrientationAttribute, nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityOrientationAttribute ]];
}
if (browserAccessibility_->HasStringAttribute(ui::AX_ATTR_PLACEHOLDER)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityPlaceholderValueAttribute, nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityPlaceholderValueAttribute ]];
}
if (GetState(browserAccessibility_, ui::AX_STATE_REQUIRED)) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- @"AXRequired", nil]];
+ [ret addObjectsFromArray:@[ @"AXRequired" ]];
}
// Title UI Element.
if (browserAccessibility_->HasIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS) &&
browserAccessibility_->GetIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS)
.size() > 0) {
- [ret addObjectsFromArray:[NSArray arrayWithObjects:
- NSAccessibilityTitleUIElementAttribute,
- nil]];
+ [ret addObjectsFromArray:@[ NSAccessibilityTitleUIElementAttribute ]];
}
// TODO(aboxhall): expose NSAccessibilityServesAsTitleForUIElementsAttribute
// for elements which are referred to by labelledby or are labels
@@ -1944,7 +2397,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns the index of the child in this objects array of children.
- (NSUInteger)accessibilityGetIndexOf:(id)child {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return 0;
NSUInteger index = 0;
@@ -1959,7 +2412,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns whether or not the specified attribute can be set by the
// accessibility API via |accessibilitySetValue:forAttribute:|.
- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return NO;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -1985,7 +2438,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns whether or not this object should be ignored in the accessibility
// tree.
- (BOOL)accessibilityIsIgnored {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return YES;
return [self isIgnored];
@@ -1994,7 +2447,7 @@ bool InitializeAccessibilityTreeSearch(
// Performs the given accessibility action on the webkit accessibility object
// that backs this object.
- (void)accessibilityPerformAction:(NSString*)action {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return;
// TODO(dmazzoni): Support more actions.
@@ -2009,7 +2462,7 @@ bool InitializeAccessibilityTreeSearch(
// Returns the description of the given action.
- (NSString*)accessibilityActionDescription:(NSString*)action {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
return NSAccessibilityActionDescription(action);
@@ -2019,12 +2472,14 @@ bool InitializeAccessibilityTreeSearch(
// This class does not support this.
- (BOOL)accessibilitySetOverrideValue:(id)value
forAttribute:(NSString*)attribute {
+ if (![self instanceActive])
+ return NO;
return NO;
}
// Sets the value for an accessibility attribute via the accessibility API.
- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -2032,7 +2487,7 @@ bool InitializeAccessibilityTreeSearch(
NSNumber* focusedNumber = value;
BOOL focused = [focusedNumber intValue];
if (focused)
- manager->SetFocus(browserAccessibility_, true);
+ manager->SetFocus(*browserAccessibility_);
}
if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
NSRange range = [(NSValue*)value rangeValue];
@@ -2047,7 +2502,7 @@ bool InitializeAccessibilityTreeSearch(
// or one of its children, so this will never return nil unless this
// object is invalid.
- (id)accessibilityHitTest:(NSPoint)point {
- if (!browserAccessibility_)
+ if (![self instanceActive])
return nil;
BrowserAccessibilityCocoa* hit = self;
@@ -2079,7 +2534,7 @@ bool InitializeAccessibilityTreeSearch(
- (NSUInteger)hash {
// Potentially called during dealloc.
- if (!browserAccessibility_)
+ if (![self instanceActive])
return [super hash];
return browserAccessibility_->GetId();
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac.h b/chromium/content/browser/accessibility/browser_accessibility_mac.h
index aed8fd49e08..d5160243274 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac.h
@@ -11,11 +11,19 @@
#include "base/macros.h"
#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/common/content_export.h"
@class BrowserAccessibilityCocoa;
namespace content {
+#if __OBJC__
+CONTENT_EXPORT const BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+ const BrowserAccessibility* obj);
+CONTENT_EXPORT BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+ BrowserAccessibility* obj);
+#endif
+
class BrowserAccessibilityMac : public BrowserAccessibility {
public:
// BrowserAccessibility overrides.
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_mac.mm
index da1f55e9673..34475bdc309 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac.mm
@@ -64,13 +64,17 @@ void BrowserAccessibilityMac::RecreateNativeObject() {
}
const BrowserAccessibilityCocoa*
-BrowserAccessibility::ToBrowserAccessibilityCocoa() const {
- return static_cast<const BrowserAccessibilityMac*>(this)->native_view();
+ToBrowserAccessibilityCocoa(const BrowserAccessibility* obj) {
+ DCHECK(obj);
+ DCHECK(obj->IsNative());
+ return static_cast<const BrowserAccessibilityMac*>(obj)->native_view();
}
-BrowserAccessibilityCocoa* BrowserAccessibility::ToBrowserAccessibilityCocoa() {
- return static_cast<BrowserAccessibilityMac*>(this)->
- native_view();
+BrowserAccessibilityCocoa* ToBrowserAccessibilityCocoa(
+ BrowserAccessibility* obj) {
+ DCHECK(obj);
+ DCHECK(obj->IsNative());
+ return static_cast<BrowserAccessibilityMac*>(obj)->native_view();
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
index c85957fab59..0b2511dc09d 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -8,6 +8,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_cocoa.h"
+#include "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,7 +54,7 @@ class BrowserAccessibilityTest : public ui::CocoaTest {
nil,
MakeAXTreeUpdate(root, child1, child2),
NULL));
- accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa()
+ accessibility_.reset([ToBrowserAccessibilityCocoa(manager_->GetRoot())
retain]);
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.cc b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
index 8979f10f0f0..f95f5085c33 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
@@ -43,6 +43,10 @@ using AXTreeIDMap =
base::hash_map<AXTreeIDRegistry::AXTreeID, BrowserAccessibilityManager*>;
base::LazyInstance<AXTreeIDMap> g_ax_tree_id_map = LAZY_INSTANCE_INITIALIZER;
+// A function to call when focus changes, for testing only.
+base::LazyInstance<base::Closure> g_focus_change_callback_for_testing =
+ LAZY_INSTANCE_INITIALIZER;
+
ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node1,
const ui::AXNodeData& node2 /* = ui::AXNodeData() */,
@@ -87,11 +91,7 @@ ui::AXTreeUpdate MakeAXTreeUpdate(
}
BrowserAccessibility* BrowserAccessibilityFactory::Create() {
-#if defined(OS_ANDROID) && defined(USE_AURA)
- return nullptr;
-#else
return BrowserAccessibility::Create();
-#endif
}
BrowserAccessibilityFindInPageInfo::BrowserAccessibilityFindInPageInfo()
@@ -127,9 +127,11 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
: delegate_(delegate),
factory_(factory),
tree_(new ui::AXSerializableTree()),
- focus_(NULL),
user_is_navigating_away_(false),
osk_state_(OSK_ALLOWED),
+ last_focused_node_(nullptr),
+ last_focused_manager_(nullptr),
+ connected_to_parent_tree_node_(false),
ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
parent_node_id_from_parent_tree_(0) {
tree_->SetDelegate(this);
@@ -142,9 +144,10 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
: delegate_(delegate),
factory_(factory),
tree_(new ui::AXSerializableTree()),
- focus_(NULL),
user_is_navigating_away_(false),
osk_state_(OSK_ALLOWED),
+ last_focused_node_(nullptr),
+ last_focused_manager_(nullptr),
ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
parent_node_id_from_parent_tree_(0) {
tree_->SetDelegate(this);
@@ -166,9 +169,6 @@ void BrowserAccessibilityManager::Initialize(
LOG(FATAL) << tree_->error();
}
}
-
- if (!focus_)
- SetFocus(tree_->root(), false);
}
// static
@@ -182,6 +182,49 @@ BrowserAccessibilityManager::GetEmptyDocument() {
return update;
}
+void BrowserAccessibilityManager::FireFocusEventsIfNeeded() {
+ BrowserAccessibility* focus = GetFocus();
+
+ // Don't fire focus events if the window itself doesn't have focus.
+ // Bypass this check if a global focus listener was set up for testing
+ // so that the test passes whether the window is active or not.
+ if (g_focus_change_callback_for_testing.Get().is_null()) {
+ if (delegate_ && !delegate_->AccessibilityViewHasFocus())
+ focus = nullptr;
+
+ if (!CanFireEvents())
+ focus = nullptr;
+ }
+
+ // Don't allow the document to be focused if it has no children and
+ // hasn't finished loading yet. Wait for at least a tiny bit of content,
+ // or for the document to actually finish loading.
+ if (focus &&
+ focus == focus->manager()->GetRoot() &&
+ focus->PlatformChildCount() == 0 &&
+ !focus->HasState(ui::AX_STATE_BUSY) &&
+ !focus->manager()->GetTreeData().loaded) {
+ focus = nullptr;
+ }
+
+ if (focus && focus != last_focused_node_)
+ FireFocusEvent(focus);
+
+ last_focused_node_ = focus;
+ last_focused_manager_ = focus ? focus->manager() : nullptr;
+}
+
+bool BrowserAccessibilityManager::CanFireEvents() {
+ return true;
+}
+
+void BrowserAccessibilityManager::FireFocusEvent(BrowserAccessibility* node) {
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node);
+
+ if (!g_focus_change_callback_for_testing.Get().is_null())
+ g_focus_change_callback_for_testing.Get().Run();
+}
+
BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
// tree_ can be null during destruction.
if (!tree_)
@@ -247,13 +290,15 @@ const ui::AXTreeData& BrowserAccessibilityManager::GetTreeData() {
}
void BrowserAccessibilityManager::OnWindowFocused() {
- if (focus_)
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
+ if (this == GetRootManager())
+ FireFocusEventsIfNeeded();
}
void BrowserAccessibilityManager::OnWindowBlurred() {
- if (focus_)
- NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
+ if (this == GetRootManager()) {
+ last_focused_node_ = nullptr;
+ last_focused_manager_ = nullptr;
+ }
}
void BrowserAccessibilityManager::UserIsNavigatingAway() {
@@ -273,11 +318,12 @@ void BrowserAccessibilityManager::NavigationFailed() {
}
void BrowserAccessibilityManager::GotMouseDown() {
- if (!focus_)
+ BrowserAccessibility* focus = GetFocus();
+ if (!focus)
return;
osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, focus);
}
bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
@@ -286,8 +332,6 @@ bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
void BrowserAccessibilityManager::OnAccessibilityEvents(
const std::vector<AXEventNotificationDetails>& details) {
- bool should_send_initial_focus = false;
-
// Process all changes to the accessibility tree first.
for (uint32_t index = 0; index < details.size(); ++index) {
const AXEventNotificationDetails& detail = details[index];
@@ -300,18 +344,31 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
}
return;
}
+ }
- // Set focus to the root if it's not anywhere else.
- if (!focus_) {
- SetFocus(tree_->root(), false);
- should_send_initial_focus = true;
+ // If the root's parent is in another accessibility tree but it wasn't
+ // previously connected, post the proper notifications on the parent.
+ BrowserAccessibility* parent = GetParentNodeFromParentTree();
+ if (parent) {
+ if (!connected_to_parent_tree_node_) {
+ parent->OnDataChanged();
+ parent->UpdatePlatformAttributes();
+ parent->manager()->NotifyAccessibilityEvent(
+ ui::AX_EVENT_CHILDREN_CHANGED, parent);
+ connected_to_parent_tree_node_ = true;
}
+ } else {
+ connected_to_parent_tree_node_ = false;
}
- if (should_send_initial_focus && NativeViewHasFocus())
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
+ // Based on the changes to the tree, first fire focus events if needed.
+ // Screen readers might not do the right thing if they're not aware of what
+ // has focus, so always try that first. Nothing will be fired if the window
+ // itself isn't focused or if focus hasn't changed.
+ GetRootManager()->FireFocusEventsIfNeeded();
- // Now iterate over the events again and fire the events.
+ // Now iterate over the events again and fire the events other than focus
+ // events.
for (uint32_t index = 0; index < details.size(); index++) {
const AXEventNotificationDetails& detail = details[index];
@@ -324,19 +381,22 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
ui::AXEvent event_type = detail.event_type;
if (event_type == ui::AX_EVENT_FOCUS ||
event_type == ui::AX_EVENT_BLUR) {
- SetFocus(node, false);
-
if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
osk_state_ = OSK_ALLOWED;
- // Don't send a native focus event if the window itself doesn't
- // have focus.
- if (!NativeViewHasFocus())
+ bool is_menu_list_option =
+ node->data().role == ui::AX_ROLE_MENU_LIST_OPTION;
+
+ // Skip all focus events other than ones on menu list options;
+ // we've already handled them, above. Menu list options are a weird
+ // exception because the menu list itself has focus but we need to fire
+ // focus events on the individual options.
+ if (!is_menu_list_option)
continue;
}
- // Send the event event to the operating system.
+ // Fire the native event.
NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
}
}
@@ -349,7 +409,16 @@ void BrowserAccessibilityManager::OnLocationChanges(
continue;
ui::AXNode* node = obj->node();
node->SetLocation(params[i].new_location);
- obj->OnLocationChanged();
+ }
+ SendLocationChangeEvents(params);
+}
+
+void BrowserAccessibilityManager::SendLocationChangeEvents(
+ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
+ for (size_t i = 0; i < params.size(); ++i) {
+ BrowserAccessibility* obj = GetFromID(params[i].id);
+ if (obj)
+ obj->OnLocationChanged();
}
}
@@ -367,6 +436,22 @@ void BrowserAccessibilityManager::OnFindInPageResult(
ActivateFindInPageResult(request_id);
}
+void BrowserAccessibilityManager::OnChildFrameHitTestResult(
+ const gfx::Point& point,
+ int hit_obj_id) {
+ BrowserAccessibility* obj = GetFromID(hit_obj_id);
+ if (!obj || !obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID))
+ return;
+
+ BrowserAccessibilityManager* child_manager =
+ BrowserAccessibilityManager::FromID(
+ obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID));
+ if (!child_manager || !child_manager->delegate())
+ return;
+
+ return child_manager->delegate()->AccessibilityHitTest(point);
+}
+
void BrowserAccessibilityManager::ActivateFindInPageResult(
int request_id) {
find_in_page_info_.active_request_id = request_id;
@@ -391,20 +476,19 @@ void BrowserAccessibilityManager::ActivateFindInPageResult(
}
BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
- BrowserAccessibility* root) {
- BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
- if (!node)
+ BrowserAccessibility* focus) {
+ if (!focus)
return NULL;
int active_descendant_id;
- if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
- &active_descendant_id)) {
+ if (focus->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
+ &active_descendant_id)) {
BrowserAccessibility* active_descendant =
- node->manager()->GetFromID(active_descendant_id);
+ focus->manager()->GetFromID(active_descendant_id);
if (active_descendant)
return active_descendant;
}
- return node;
+ return focus;
}
bool BrowserAccessibilityManager::NativeViewHasFocus() {
@@ -414,39 +498,55 @@ bool BrowserAccessibilityManager::NativeViewHasFocus() {
return false;
}
-BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
- BrowserAccessibility* root) {
- if (!focus_)
- return nullptr;
+BrowserAccessibility* BrowserAccessibilityManager::GetFocus() {
+ BrowserAccessibilityManager* root_manager = GetRootManager();
+ if (!root_manager)
+ root_manager = this;
+ int32_t focused_tree_id = root_manager->GetTreeData().focused_tree_id;
- if (root && !focus_->IsDescendantOf(root->node()))
- return nullptr;
+ BrowserAccessibilityManager* focused_manager = nullptr;
+ if (focused_tree_id)
+ focused_manager =BrowserAccessibilityManager::FromID(focused_tree_id);
+ if (!focused_manager)
+ focused_manager = root_manager;
+
+ return focused_manager->GetFocusFromThisOrDescendantFrame();
+}
+
+BrowserAccessibility*
+BrowserAccessibilityManager::GetFocusFromThisOrDescendantFrame() {
+ int32_t focus_id = GetTreeData().focus_id;
+ BrowserAccessibility* obj = GetFromID(focus_id);
+ if (!obj)
+ return GetRoot();
- BrowserAccessibility* obj = GetFromAXNode(focus_);
- DCHECK(obj);
if (obj->HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) {
BrowserAccessibilityManager* child_manager =
BrowserAccessibilityManager::FromID(
obj->GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID));
if (child_manager)
- return child_manager->GetFocus(child_manager->GetRoot());
+ return child_manager->GetFocusFromThisOrDescendantFrame();
}
return obj;
}
-void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
- if (focus_ != node)
- focus_ = node;
+void BrowserAccessibilityManager::SetFocus(const BrowserAccessibility& node) {
+ if (delegate_)
+ delegate_->AccessibilitySetFocus(node.GetId());
+}
- if (notify && node && delegate_)
- delegate_->AccessibilitySetFocus(node->id());
+void BrowserAccessibilityManager::SetFocusLocallyForTesting(
+ BrowserAccessibility* node) {
+ ui::AXTreeData data = GetTreeData();
+ data.focus_id = node->GetId();
+ tree_->UpdateData(data);
}
-void BrowserAccessibilityManager::SetFocus(
- BrowserAccessibility* obj, bool notify) {
- if (obj->node())
- SetFocus(obj->node(), notify);
+// static
+void BrowserAccessibilityManager::SetFocusChangeCallbackForTesting(
+ const base::Closure& callback) {
+ g_focus_change_callback_for_testing.Get() = callback;
}
void BrowserAccessibilityManager::DoDefaultAction(
@@ -500,33 +600,35 @@ gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
return gfx::Rect();
}
+// static
BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
- BrowserAccessibility* node) const {
- if (!node)
+ const BrowserAccessibility* object) {
+ if (!object)
return nullptr;
- if (node->PlatformChildCount())
- return node->PlatformGetChild(0);
+ if (object->PlatformChildCount())
+ return object->PlatformGetChild(0);
- while (node) {
- const auto sibling = node->GetNextSibling();
+ while (object) {
+ BrowserAccessibility* sibling = object->GetNextSibling();
if (sibling)
return sibling;
- node = node->GetParent();
+ object = object->GetParent();
}
return nullptr;
}
+// static
BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
- BrowserAccessibility* node) const {
- if (!node)
+ const BrowserAccessibility* object) {
+ if (!object)
return nullptr;
- const auto sibling = node->GetPreviousSibling();
+ BrowserAccessibility* sibling = object->GetPreviousSibling();
if (!sibling)
- return node->GetParent();
+ return object->GetParent();
if (sibling->PlatformChildCount())
return sibling->PlatformDeepestLastChild();
@@ -534,36 +636,168 @@ BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
return sibling;
}
+// static
BrowserAccessibility* BrowserAccessibilityManager::PreviousTextOnlyObject(
- BrowserAccessibility* node) const {
- BrowserAccessibility* previous_node = PreviousInTreeOrder(node);
- while (previous_node && !previous_node->IsTextOnlyObject())
- previous_node = PreviousInTreeOrder(previous_node);
+ const BrowserAccessibility* object) {
+ BrowserAccessibility* previous_object = PreviousInTreeOrder(object);
+ while (previous_object && !previous_object->IsTextOnlyObject())
+ previous_object = PreviousInTreeOrder(previous_object);
- return previous_node;
+ return previous_object;
}
+// static
BrowserAccessibility* BrowserAccessibilityManager::NextTextOnlyObject(
- BrowserAccessibility* node) const {
- BrowserAccessibility* next_node = NextInTreeOrder(node);
- while (next_node && !next_node->IsTextOnlyObject())
- next_node = NextInTreeOrder(next_node);
+ const BrowserAccessibility* object) {
+ BrowserAccessibility* next_object = NextInTreeOrder(object);
+ while (next_object && !next_object->IsTextOnlyObject())
+ next_object = NextInTreeOrder(next_object);
+
+ return next_object;
+}
+
+// static
+bool BrowserAccessibilityManager::FindIndicesInCommonParent(
+ const BrowserAccessibility& object1,
+ const BrowserAccessibility& object2,
+ BrowserAccessibility** common_parent,
+ int* child_index1,
+ int* child_index2) {
+ DCHECK(common_parent && child_index1 && child_index2);
+ auto ancestor1 = const_cast<BrowserAccessibility*>(&object1);
+ auto ancestor2 = const_cast<BrowserAccessibility*>(&object2);
+ do {
+ *child_index1 = ancestor1->GetIndexInParent();
+ ancestor1 = ancestor1->GetParent();
+ } while (
+ ancestor1 &&
+ // |BrowserAccessibility::IsAncestorOf| returns true if objects are equal.
+ (ancestor1 == ancestor2 || !ancestor2->IsDescendantOf(ancestor1)));
+
+ if (!ancestor1) {
+ *common_parent = nullptr;
+ *child_index1 = -1;
+ *child_index2 = -1;
+ return false;
+ }
+
+ do {
+ *child_index2 = ancestor2->GetIndexInParent();
+ ancestor2 = ancestor2->GetParent();
+ } while (ancestor1 != ancestor2);
+
+ *common_parent = ancestor1;
+ return true;
+}
+
+// static
+base::string16 BrowserAccessibilityManager::GetTextForRange(
+ const BrowserAccessibility& start_object,
+ int start_offset,
+ const BrowserAccessibility& end_object,
+ int end_offset) {
+ DCHECK_GE(start_offset, 0);
+ DCHECK_GE(end_offset, 0);
+
+ if (&start_object == &end_object && start_object.IsSimpleTextControl()) {
+ if (start_offset > end_offset)
+ std::swap(start_offset, end_offset);
+
+ if (start_offset >= static_cast<int>(start_object.GetValue().length()) ||
+ end_offset > static_cast<int>(start_object.GetValue().length())) {
+ return base::string16();
+ }
+
+ return start_object.GetValue().substr(start_offset,
+ end_offset - start_offset);
+ }
+
+ int child_index1 = -1;
+ int child_index2 = -1;
+ if (&start_object != &end_object) {
+ BrowserAccessibility* common_parent;
+ if (!FindIndicesInCommonParent(start_object, end_object, &common_parent,
+ &child_index1, &child_index2)) {
+ return base::string16();
+ }
- return next_node;
+ DCHECK(common_parent);
+ DCHECK_GE(child_index1, 0);
+ DCHECK_GE(child_index2, 0);
+ // If the child indices are equal, one object is a descendant of the other.
+ DCHECK(child_index1 != child_index2 ||
+ start_object.IsDescendantOf(&end_object) ||
+ end_object.IsDescendantOf(&start_object));
+ }
+
+ const BrowserAccessibility* start_text_object = nullptr;
+ const BrowserAccessibility* end_text_object = nullptr;
+ if (child_index1 <= child_index2 ||
+ end_object.IsDescendantOf(&start_object)) {
+ start_text_object = &start_object;
+ end_text_object = &end_object;
+ } else if (child_index1 > child_index2 ||
+ start_object.IsDescendantOf(&end_object)) {
+ start_text_object = &end_object;
+ end_text_object = &start_object;
+ }
+
+ if (!start_text_object->PlatformIsLeaf())
+ start_text_object = start_text_object->PlatformDeepestFirstChild();
+ if (!end_text_object->PlatformIsLeaf())
+ end_text_object = end_text_object->PlatformDeepestLastChild();
+
+ if (!start_text_object->IsTextOnlyObject())
+ start_text_object = NextTextOnlyObject(start_text_object);
+ if (!end_text_object->IsTextOnlyObject())
+ end_text_object = PreviousTextOnlyObject(end_text_object);
+
+ if (!start_text_object || !end_text_object)
+ return base::string16();
+
+ // Be a little permissive with the start and end offsets.
+ if (start_text_object == end_text_object) {
+ if (start_offset > end_offset)
+ std::swap(start_offset, end_offset);
+
+ if (start_offset <
+ static_cast<int>(start_text_object->GetText().length()) &&
+ end_offset <= static_cast<int>(end_text_object->GetText().length())) {
+ return start_text_object->GetText().substr(start_offset,
+ end_offset - start_offset);
+ }
+ return start_text_object->GetText();
+ }
+
+ base::string16 text;
+ if (start_offset < static_cast<int>(start_text_object->GetText().length()))
+ text += start_text_object->GetText().substr(start_offset);
+ else
+ text += start_text_object->GetText();
+ start_text_object = NextTextOnlyObject(start_text_object);
+ while (start_text_object && start_text_object != end_text_object) {
+ text += start_text_object->GetText();
+ start_text_object = NextTextOnlyObject(start_text_object);
+ }
+ if (end_offset <= static_cast<int>(end_text_object->GetText().length()))
+ text += end_text_object->GetText().substr(0, end_offset);
+ else
+ text += end_text_object->GetText();
+
+ return text;
}
+void BrowserAccessibilityManager::OnNodeDataWillChange(
+ ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) {}
+
void BrowserAccessibilityManager::OnTreeDataChanged(ui::AXTree* tree) {
}
void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXTree* tree,
ui::AXNode* node) {
DCHECK(node);
- if (node == focus_ && tree_) {
- if (node != tree_->root())
- SetFocus(tree_->root(), false);
- else
- focus_ = NULL;
- }
if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
return;
GetFromAXNode(node)->Destroy();
@@ -604,26 +838,34 @@ void BrowserAccessibilityManager::OnAtomicUpdateFinished(
ax_tree_id_changed = true;
}
- if (ax_tree_id_changed || root_changed) {
- BrowserAccessibility* parent = GetParentNodeFromParentTree();
- if (parent) {
- parent->OnDataChanged();
- parent->manager()->NotifyAccessibilityEvent(
- ui::AX_EVENT_CHILDREN_CHANGED, parent);
- }
+ // Whenever the tree ID or the root of this tree changes we may need to
+ // fire an event on our parent node in the parent tree to ensure that
+ // we're properly connected.
+ if (ax_tree_id_changed || root_changed)
+ connected_to_parent_tree_node_ = false;
+
+ // When the root changes and this is the root manager, we may need to
+ // fire a new focus event.
+ if (root_changed && last_focused_manager_ == this) {
+ last_focused_node_ = nullptr;
+ last_focused_manager_ = nullptr;
}
}
+BrowserAccessibilityManager* BrowserAccessibilityManager::GetRootManager() {
+ BrowserAccessibility* parent = GetParentNodeFromParentTree();
+ if (!parent)
+ return this;
+
+ return parent->manager()->GetRootManager();
+}
+
BrowserAccessibilityDelegate*
BrowserAccessibilityManager::GetDelegateFromRootManager() {
- if (!GetRoot())
- return nullptr;
- int parent_tree_id = GetTreeData().parent_tree_id;
- BrowserAccessibilityManager* parent_manager =
- BrowserAccessibilityManager::FromID(parent_tree_id);
- if (parent_manager)
- return parent_manager->GetDelegateFromRootManager();
- return delegate();
+ BrowserAccessibilityManager* root_manager = GetRootManager();
+ if (root_manager)
+ return root_manager->delegate();
+ return nullptr;
}
ui::AXTreeUpdate
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.h b/chromium/content/browser/accessibility/browser_accessibility_manager.h
index 01dcf37a083..6d5a42f720e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.h
@@ -9,6 +9,7 @@
#include <vector>
+#include "base/callback_forward.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
@@ -35,6 +36,8 @@ class BrowserAccessibilityManagerWin;
class BrowserAccessibilityManagerAuraLinux;
#endif
+class SiteInstance;
+
// For testing.
CONTENT_EXPORT ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node,
@@ -79,6 +82,9 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate {
virtual gfx::Rect AccessibilityGetViewBounds() const = 0;
virtual gfx::Point AccessibilityOriginInScreen(
const gfx::Rect& bounds) const = 0;
+ virtual gfx::Rect AccessibilityTransformToRootCoordSpace(
+ const gfx::Rect& bounds) = 0;
+ virtual SiteInstance* AccessibilityGetSiteInstance() = 0;
virtual void AccessibilityHitTest(
const gfx::Point& point) = 0;
virtual void AccessibilitySetAccessibilityFocus(int acc_obj_id) = 0;
@@ -138,6 +144,18 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
virtual void NotifyAccessibilityEvent(
ui::AXEvent event_type, BrowserAccessibility* node) { }
+ // Checks whether focus has changed since the last time it was checked,
+ // taking into account whether the window has focus and which frame within
+ // the frame tree has focus. If focus has changed, calls FireFocusEvent.
+ void FireFocusEventsIfNeeded();
+
+ // Return whether or not we are currently able to fire events.
+ virtual bool CanFireEvents();
+
+ // Fire a focus event. Virtual so that some platforms can customize it,
+ // like firing a focus event on the root first, on Windows.
+ virtual void FireFocusEvent(BrowserAccessibility* node);
+
// Return a pointer to the root of the tree, does not make a new reference.
BrowserAccessibility* GetRoot();
@@ -172,11 +190,16 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// occurred in the tab.
void GotMouseDown();
- // Update the focused node to |node|, which may be null.
- // If |notify| is true, send a message to the renderer to set focus
- // to this node.
- void SetFocus(ui::AXNode* node, bool notify);
- void SetFocus(BrowserAccessibility* node, bool notify);
+ // Send a message to the renderer to set focus to this node.
+ void SetFocus(const BrowserAccessibility& node);
+
+ // Pretend that the given node has focus, for testing only. Doesn't
+ // communicate with the renderer and doesn't fire any events.
+ void SetFocusLocallyForTesting(BrowserAccessibility* node);
+
+ // For testing only, register a function to be called when focus changes
+ // in any BrowserAccessibilityManager.
+ static void SetFocusChangeCallbackForTesting(const base::Closure& callback);
// Tell the renderer to do the default action for this node.
void DoDefaultAction(const BrowserAccessibility& node);
@@ -213,12 +236,12 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
void ActivateFindInPageResult(int request_id, int match_index);
// Called when the renderer process has notified us of about tree changes.
- void OnAccessibilityEvents(
+ virtual void OnAccessibilityEvents(
const std::vector<AXEventNotificationDetails>& details);
// Called when the renderer process updates the location of accessibility
- // objects.
- virtual void OnLocationChanges(
+ // objects. Calls SendLocationChangeEvents(), which can be overridden.
+ void OnLocationChanges(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
// Called when a new find in page result is received. We hold on to this
@@ -227,6 +250,11 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
int request_id, int match_index, int start_id, int start_offset,
int end_id, int end_offset);
+ // Called in response to a hit test, when the object hit has a child frame
+ // (like an iframe element or browser plugin), and we need to do another
+ // hit test recursively.
+ void OnChildFrameHitTestResult(const gfx::Point& point, int hit_obj_id);
+
// This is called when the user has committed to a find in page query,
// e.g. by pressing enter or tapping on the next / previous result buttons.
// If a match has already been received for this request id,
@@ -248,13 +276,16 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
ToBrowserAccessibilityManagerAuraLinux();
#endif
- // Return the object that has focus, if it's a descendant of the
- // given root (inclusive). Does not make a new reference.
- virtual BrowserAccessibility* GetFocus(BrowserAccessibility* root);
+ // Return the object that has focus, starting at the top of the frame tree.
+ virtual BrowserAccessibility* GetFocus();
- // Return the descentant of the given root that has focus, or that object's
- // active descendant if it has one.
- BrowserAccessibility* GetActiveDescendantFocus(BrowserAccessibility* root);
+ // Return the object that has focus, only considering this frame and
+ // descendants.
+ BrowserAccessibility* GetFocusFromThisOrDescendantFrame();
+
+ // Given a focused node |focus|, returns a descendant of that node if it
+ // has an active descendant, otherwise returns |focus|.
+ BrowserAccessibility* GetActiveDescendantFocus(BrowserAccessibility* focus);
// Returns true if native focus is anywhere in this WebContents or not.
bool NativeViewHasFocus();
@@ -264,13 +295,41 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
virtual bool UseRootScrollOffsetsWhenComputingBounds();
// Walk the tree.
- BrowserAccessibility* NextInTreeOrder(BrowserAccessibility* node) const;
- BrowserAccessibility* PreviousInTreeOrder(BrowserAccessibility* node) const;
- BrowserAccessibility* NextTextOnlyObject(BrowserAccessibility* node) const;
- BrowserAccessibility* PreviousTextOnlyObject(
- BrowserAccessibility* node) const;
+ static BrowserAccessibility* NextInTreeOrder(
+ const BrowserAccessibility* object);
+ static BrowserAccessibility* PreviousInTreeOrder(
+ const BrowserAccessibility* object);
+ static BrowserAccessibility* NextTextOnlyObject(
+ const BrowserAccessibility* object);
+ static BrowserAccessibility* PreviousTextOnlyObject(
+ const BrowserAccessibility* object);
+
+ // If the two objects provided have a common ancestor returns both the
+ // common ancestor and the child indices of the two subtrees in which the
+ // objects are located.
+ // Returns false if a common ancestor cannot be found.
+ static bool FindIndicesInCommonParent(const BrowserAccessibility& object1,
+ const BrowserAccessibility& object2,
+ BrowserAccessibility** common_parent,
+ int* child_index1,
+ int* child_index2);
+
+ // Returns all the text found between the given start and end locations.
+ // If start and end offsets are greater than the text's length, returns all
+ // the text until text length.
+ static base::string16 GetTextForRange(
+ const BrowserAccessibility& start_object,
+ int start_offset,
+ const BrowserAccessibility& end_object,
+ int end_offset);
+
+ // Accessors.
+ AXTreeIDRegistry::AXTreeID ax_tree_id() const { return ax_tree_id_; }
// AXTreeDelegate implementation.
+ void OnNodeDataWillChange(ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) override;
void OnTreeDataChanged(ui::AXTree* tree) override;
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
@@ -287,8 +346,11 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
}
// If this BrowserAccessibilityManager is a child frame or guest frame,
- // return the BrowserAccessibilityDelegate from the highest ancestor frame
+ // return the BrowserAccessibilityManager from the highest ancestor frame
// in the frame tree.
+ BrowserAccessibilityManager* GetRootManager();
+
+ // Returns the BrowserAccessibilityDelegate from |GetRootManager|, above.
BrowserAccessibilityDelegate* GetDelegateFromRootManager();
// Get a snapshot of the current tree as an AXTreeUpdate.
@@ -304,6 +366,12 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory);
+ // Send platform-specific notifications to each of these objects that
+ // their location has changed. This is called by OnLocationChanges
+ // after it's updated the internal data structure.
+ virtual void SendLocationChangeEvents(
+ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
+
private:
// The following states keep track of whether or not the
// on-screen keyboard is allowed to be shown.
@@ -337,9 +405,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// The underlying tree of accessibility objects.
scoped_ptr<ui::AXSerializableTree> tree_;
- // The node that currently has focus.
- ui::AXNode* focus_;
-
// A mapping from a node id to its wrapper of type BrowserAccessibility.
base::hash_map<int32_t, BrowserAccessibility*> id_wrapper_map_;
@@ -351,6 +416,21 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
BrowserAccessibilityFindInPageInfo find_in_page_info_;
+ // These are only used by the root BrowserAccessibilityManager of a
+ // frame tree. Stores the last focused node and last focused manager so
+ // that when focus might have changed we can figure out whether we need
+ // to fire a focus event.
+ //
+ // NOTE: these pointers are not cleared, so they should never be
+ // dereferenced, only used for comparison.
+ BrowserAccessibility* last_focused_node_;
+ BrowserAccessibilityManager* last_focused_manager_;
+
+ // True if the root's parent is in another accessibility tree and that
+ // parent's child is the root. Ensures that the parent node is notified
+ // once when this subtree is first connected.
+ bool connected_to_parent_tree_node_;
+
// The global ID of this accessibility tree.
AXTreeIDRegistry::AXTreeID ax_tree_id_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
index 42c2042c5c4..abfdcf7b558 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/accessibility/browser_accessibility_android.h"
+#include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
#include "content/common/accessibility_messages.h"
#include "jni/BrowserAccessibilityManager_jni.h"
#include "ui/accessibility/ax_text_utils.h"
@@ -22,32 +23,99 @@
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
+namespace content {
+
namespace {
-enum AndroidHtmlElementType {
- HTML_ELEMENT_TYPE_SECTION,
- HTML_ELEMENT_TYPE_LIST,
- HTML_ELEMENT_TYPE_CONTROL,
- HTML_ELEMENT_TYPE_ANY
-};
+using SearchKeyToPredicateMap =
+ base::hash_map<base::string16, AccessibilityMatchPredicate>;
+base::LazyInstance<SearchKeyToPredicateMap> g_search_key_to_predicate_map =
+ LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::string16> g_all_search_keys =
+ LAZY_INSTANCE_INITIALIZER;
+
+bool SectionPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ switch (node->GetRole()) {
+ case ui::AX_ROLE_ARTICLE:
+ case ui::AX_ROLE_APPLICATION:
+ case ui::AX_ROLE_BANNER:
+ case ui::AX_ROLE_COMPLEMENTARY:
+ case ui::AX_ROLE_CONTENT_INFO:
+ case ui::AX_ROLE_HEADING:
+ case ui::AX_ROLE_MAIN:
+ case ui::AX_ROLE_NAVIGATION:
+ case ui::AX_ROLE_SEARCH:
+ case ui::AX_ROLE_REGION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void AddToPredicateMap(const char* search_key_ascii,
+ AccessibilityMatchPredicate predicate) {
+ base::string16 search_key_utf16 = base::ASCIIToUTF16(search_key_ascii);
+ g_search_key_to_predicate_map.Get()[search_key_utf16] = predicate;
+ if (!g_all_search_keys.Get().empty())
+ g_all_search_keys.Get() += base::ASCIIToUTF16(",");
+ g_all_search_keys.Get() += search_key_utf16;
+}
// These are special unofficial strings sent from TalkBack/BrailleBack
// to jump to certain categories of web elements.
-AndroidHtmlElementType HtmlElementTypeFromString(base::string16 element_type) {
- if (element_type == base::ASCIIToUTF16("SECTION"))
- return HTML_ELEMENT_TYPE_SECTION;
- else if (element_type == base::ASCIIToUTF16("LIST"))
- return HTML_ELEMENT_TYPE_LIST;
- else if (element_type == base::ASCIIToUTF16("CONTROL"))
- return HTML_ELEMENT_TYPE_CONTROL;
- else
- return HTML_ELEMENT_TYPE_ANY;
+void InitSearchKeyToPredicateMapIfNeeded() {
+ if (!g_search_key_to_predicate_map.Get().empty())
+ return;
+
+ AddToPredicateMap("ARTICLE", AccessibilityArticlePredicate);
+ AddToPredicateMap("BUTTON", AccessibilityButtonPredicate);
+ AddToPredicateMap("CHECKBOX", AccessibilityCheckboxPredicate);
+ AddToPredicateMap("COMBOBOX", AccessibilityComboboxPredicate);
+ AddToPredicateMap("CONTROL", AccessibilityControlPredicate);
+ AddToPredicateMap("FOCUSABLE", AccessibilityFocusablePredicate);
+ AddToPredicateMap("FRAME", AccessibilityFramePredicate);
+ AddToPredicateMap("GRAPHIC", AccessibilityGraphicPredicate);
+ AddToPredicateMap("H1", AccessibilityH1Predicate);
+ AddToPredicateMap("H2", AccessibilityH2Predicate);
+ AddToPredicateMap("H3", AccessibilityH3Predicate);
+ AddToPredicateMap("H4", AccessibilityH4Predicate);
+ AddToPredicateMap("H5", AccessibilityH5Predicate);
+ AddToPredicateMap("H6", AccessibilityH6Predicate);
+ AddToPredicateMap("HEADING", AccessibilityHeadingPredicate);
+ AddToPredicateMap("LANDMARK", AccessibilityLandmarkPredicate);
+ AddToPredicateMap("LINK", AccessibilityLinkPredicate);
+ AddToPredicateMap("LIST", AccessibilityListPredicate);
+ AddToPredicateMap("LIST_ITEM", AccessibilityListItemPredicate);
+ AddToPredicateMap("MAIN", AccessibilityMainPredicate);
+ AddToPredicateMap("MEDIA", AccessibilityMediaPredicate);
+ AddToPredicateMap("RADIO", AccessibilityRadioButtonPredicate);
+ AddToPredicateMap("SECTION", SectionPredicate);
+ AddToPredicateMap("TABLE", AccessibilityTablePredicate);
+ AddToPredicateMap("TEXT_FIELD", AccessibilityTextfieldPredicate);
+ AddToPredicateMap("UNVISITED_LINK", AccessibilityUnvisitedLinkPredicate);
+ AddToPredicateMap("VISITED_LINK", AccessibilityVisitedLinkPredicate);
+}
+
+AccessibilityMatchPredicate PredicateForSearchKey(
+ const base::string16& element_type) {
+ InitSearchKeyToPredicateMapIfNeeded();
+ const auto& iter = g_search_key_to_predicate_map.Get().find(element_type);
+ if (iter != g_search_key_to_predicate_map.Get().end())
+ return iter->second;
+
+ // If we don't recognize the selector, return any element that's clickable.
+ // We mark all focusable nodes and leaf nodes as clickable because it's
+ // impossible to know whether a web node has a click handler or not, so
+ // to be safe we have to allow accessibility services to click on nearly
+ // anything that could possibly respond to a click.
+ return [](BrowserAccessibility* start, BrowserAccessibility* node) {
+ return static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable();
+ };
}
} // anonymous namespace
-namespace content {
-
namespace aria_strings {
const char kAriaLivePolite[] = "polite";
const char kAriaLiveAssertive[] = "assertive";
@@ -80,11 +148,12 @@ BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
if (obj.is_null())
return;
- Java_BrowserAccessibilityManager_onNativeObjectDestroyed(env, obj.obj());
+ Java_BrowserAccessibilityManager_onNativeObjectDestroyed(
+ env, obj.obj(),reinterpret_cast<intptr_t>(this));
}
// static
@@ -116,7 +185,7 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
ui::AXEvent event_type,
BrowserAccessibility* node) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
if (obj.is_null())
return;
@@ -129,7 +198,8 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
if (event_type == ui::AX_EVENT_TREE_CHANGED)
return;
- // Layout changes are handled in OnLocationChanges.
+ // Layout changes are handled in OnLocationChanges and
+ // SendLocationChangeEvents.
if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE)
return;
@@ -142,28 +212,38 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
// the Android system that the accessibility hierarchy rooted at this
// node has changed.
Java_BrowserAccessibilityManager_handleContentChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
+
+ // Ignore load complete events on iframes.
+ if (event_type == ui::AX_EVENT_LOAD_COMPLETE &&
+ node->manager() != GetRootManager()) {
+ return;
+ }
switch (event_type) {
case ui::AX_EVENT_LOAD_COMPLETE:
Java_BrowserAccessibilityManager_handlePageLoaded(
- env, obj.obj(), focus_->id());
+ env, obj.obj(), GetFocus()->unique_id());
break;
case ui::AX_EVENT_FOCUS:
Java_BrowserAccessibilityManager_handleFocusChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
break;
case ui::AX_EVENT_CHECKED_STATE_CHANGED:
Java_BrowserAccessibilityManager_handleCheckStateChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
+ break;
+ case ui::AX_EVENT_CLICKED:
+ Java_BrowserAccessibilityManager_handleClicked(env, obj.obj(),
+ node->unique_id());
break;
case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
Java_BrowserAccessibilityManager_handleScrollPositionChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
break;
case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
Java_BrowserAccessibilityManager_handleScrolledToAnchor(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
break;
case ui::AX_EVENT_ALERT:
// An alert is a special case of live region. Fall through to the
@@ -179,16 +259,16 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
}
case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
Java_BrowserAccessibilityManager_handleTextSelectionChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
break;
case ui::AX_EVENT_TEXT_CHANGED:
case ui::AX_EVENT_VALUE_CHANGED:
- if (android_node->IsEditableText() && GetFocus(GetRoot()) == node) {
+ if (android_node->IsEditableText() && GetFocus() == node) {
Java_BrowserAccessibilityManager_handleEditableTextChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
} else if (android_node->IsSlider()) {
Java_BrowserAccessibilityManager_handleSliderChanged(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
}
break;
default:
@@ -198,15 +278,15 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
}
}
-void BrowserAccessibilityManagerAndroid::OnLocationChanges(
+void BrowserAccessibilityManagerAndroid::SendLocationChangeEvents(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
// Android is not very efficient at handling notifications, and location
// changes in particular are frequent and not time-critical. If a lot of
// nodes changed location, just send a single notification after a short
// delay (to batch them), rather than lots of individual notifications.
if (params.size() > 3) {
+ ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_BrowserAccessibilityManager_sendDelayedWindowContentChangedEvent(
@@ -214,14 +294,22 @@ void BrowserAccessibilityManagerAndroid::OnLocationChanges(
return;
}
- BrowserAccessibilityManager::OnLocationChanges(params);
+ BrowserAccessibilityManager::SendLocationChangeEvents(params);
+}
+
+base::android::ScopedJavaLocalRef<jstring>
+BrowserAccessibilityManagerAndroid::GetSupportedHtmlElementTypes(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& obj) {
+ InitSearchKeyToPredicateMapIfNeeded();
+ return base::android::ConvertUTF16ToJavaString(env, g_all_search_keys.Get());
}
jint BrowserAccessibilityManagerAndroid::GetRootId(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
if (GetRoot())
- return static_cast<jint>(GetRoot()->GetId());
+ return static_cast<jint>(GetRoot()->unique_id());
else
return -1;
}
@@ -230,7 +318,7 @@ jboolean BrowserAccessibilityManagerAndroid::IsNodeValid(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- return GetFromID(id) != NULL;
+ return GetFromUniqueID(id) != NULL;
}
void BrowserAccessibilityManagerAndroid::HitTest(
@@ -246,8 +334,7 @@ jboolean BrowserAccessibilityManagerAndroid::IsEditableText(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -258,8 +345,7 @@ jint BrowserAccessibilityManagerAndroid::GetEditableTextSelectionStart(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -270,8 +356,7 @@ jint BrowserAccessibilityManagerAndroid::GetEditableTextSelectionEnd(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -283,18 +368,17 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& info,
jint id) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
if (node->GetParent()) {
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoParent(
- env, obj, info, node->GetParent()->GetId());
+ env, obj, info, node->GetParent()->unique_id());
}
for (unsigned i = 0; i < node->PlatformChildCount(); ++i) {
Java_BrowserAccessibilityManager_addAccessibilityNodeInfoChild(
- env, obj, info, node->InternalGetChild(i)->GetId());
+ env, obj, info, node->PlatformGetChild(i)->unique_id());
}
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes(
env, obj, info,
@@ -355,6 +439,12 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
absolute_rect.width(), absolute_rect.height(),
is_root);
+ Java_BrowserAccessibilityManager_setAccessibilityNodeInfoKitKatAttributes(
+ env, obj, info,
+ is_root,
+ base::android::ConvertUTF16ToJavaString(
+ env, node->GetRoleDescription()).obj());
+
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLollipopAttributes(
env, obj, info,
node->CanOpenPopup(),
@@ -397,8 +487,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
const JavaParamRef<jobject>& event,
jint id,
jint event_type) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -500,7 +589,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
void BrowserAccessibilityManagerAndroid::Click(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node)
DoDefaultAction(*node);
}
@@ -508,22 +597,22 @@ void BrowserAccessibilityManagerAndroid::Click(JNIEnv* env,
void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node)
- SetFocus(node, true);
+ SetFocus(*node);
}
void BrowserAccessibilityManagerAndroid::Blur(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
- SetFocus(GetRoot(), true);
+ SetFocus(*GetRoot());
}
void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node)
ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size()));
}
@@ -533,7 +622,7 @@ void BrowserAccessibilityManagerAndroid::SetTextFieldValue(
const JavaParamRef<jobject>& obj,
jint id,
const JavaParamRef<jstring>& value) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node) {
BrowserAccessibilityManager::SetValue(
*node, base::android::ConvertJavaStringToUTF16(env, value));
@@ -546,7 +635,7 @@ void BrowserAccessibilityManagerAndroid::SetSelection(
jint id,
jint start,
jint end) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node)
SetTextSelection(*node, start, end);
}
@@ -556,7 +645,7 @@ jboolean BrowserAccessibilityManagerAndroid::AdjustSlider(
const JavaParamRef<jobject>& obj,
jint id,
jboolean increment) {
- BrowserAccessibility* node = GetFromID(id);
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -589,7 +678,7 @@ jboolean BrowserAccessibilityManagerAndroid::AdjustSlider(
void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
BrowserAccessibility* node) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
if (obj.is_null())
return;
@@ -606,7 +695,7 @@ void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
}
Java_BrowserAccessibilityManager_handleHover(
- env, obj.obj(), node->GetId());
+ env, obj.obj(), node->unique_id());
}
jint BrowserAccessibilityManagerAndroid::FindElementType(
@@ -615,58 +704,36 @@ jint BrowserAccessibilityManagerAndroid::FindElementType(
jint start_id,
const JavaParamRef<jstring>& element_type_str,
jboolean forwards) {
- BrowserAccessibility* node = GetFromID(start_id);
- if (!node)
+ BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id);
+ if (!start_node)
return 0;
- AndroidHtmlElementType element_type = HtmlElementTypeFromString(
- base::android::ConvertJavaStringToUTF16(env, element_type_str));
+ BrowserAccessibilityManager* root_manager = GetRootManager();
+ if (!root_manager)
+ return 0;
- node = forwards ? NextInTreeOrder(node) : PreviousInTreeOrder(node);
- while (node) {
- switch(element_type) {
- case HTML_ELEMENT_TYPE_SECTION:
- if (node->GetRole() == ui::AX_ROLE_ARTICLE ||
- node->GetRole() == ui::AX_ROLE_APPLICATION ||
- node->GetRole() == ui::AX_ROLE_BANNER ||
- node->GetRole() == ui::AX_ROLE_COMPLEMENTARY ||
- node->GetRole() == ui::AX_ROLE_CONTENT_INFO ||
- node->GetRole() == ui::AX_ROLE_HEADING ||
- node->GetRole() == ui::AX_ROLE_MAIN ||
- node->GetRole() == ui::AX_ROLE_NAVIGATION ||
- node->GetRole() == ui::AX_ROLE_SEARCH ||
- node->GetRole() == ui::AX_ROLE_REGION) {
- return node->GetId();
- }
- break;
- case HTML_ELEMENT_TYPE_LIST:
- if (node->GetRole() == ui::AX_ROLE_LIST ||
- node->GetRole() == ui::AX_ROLE_GRID ||
- node->GetRole() == ui::AX_ROLE_TABLE ||
- node->GetRole() == ui::AX_ROLE_TREE) {
- return node->GetId();
- }
- break;
- case HTML_ELEMENT_TYPE_CONTROL:
- if (static_cast<BrowserAccessibilityAndroid*>(node)->IsFocusable())
- return node->GetId();
- break;
- case HTML_ELEMENT_TYPE_ANY:
- // In theory, the API says that an accessibility service could
- // jump to an element by element name, like 'H1' or 'P'. This isn't
- // currently used by any accessibility service, and we think it's
- // better to keep them high-level like 'SECTION' or 'CONTROL', so we
- // just fall back on linear navigation when we don't recognize the
- // element type.
- if (static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable())
- return node->GetId();
- break;
- }
+ BrowserAccessibility* root = root_manager->GetRoot();
+ if (!root)
+ return 0;
- node = forwards ? NextInTreeOrder(node) : PreviousInTreeOrder(node);
- }
+ AccessibilityMatchPredicate predicate = PredicateForSearchKey(
+ base::android::ConvertJavaStringToUTF16(env, element_type_str));
- return 0;
+ OneShotAccessibilityTreeSearch tree_search(root);
+ tree_search.SetStartNode(start_node);
+ tree_search.SetDirection(
+ forwards ?
+ OneShotAccessibilityTreeSearch::FORWARDS :
+ OneShotAccessibilityTreeSearch::BACKWARDS);
+ tree_search.SetResultLimit(1);
+ tree_search.SetImmediateDescendantsOnly(false);
+ tree_search.SetVisibleOnly(false);
+ tree_search.AddPredicate(predicate);
+
+ if (tree_search.CountMatches() == 0)
+ return 0;
+
+ return tree_search.GetMatchAtIndex(0)->unique_id();
}
jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
@@ -676,8 +743,7 @@ jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
jboolean extend_selection,
jint id,
jint cursor_index) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -706,8 +772,7 @@ jboolean BrowserAccessibilityManagerAndroid::PreviousAtGranularity(
jboolean extend_selection,
jint id,
jint cursor_index) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -827,8 +892,7 @@ bool BrowserAccessibilityManagerAndroid::IsSlider(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint id) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -840,8 +904,7 @@ bool BrowserAccessibilityManagerAndroid::Scroll(
const JavaParamRef<jobject>& obj,
jint id,
int direction) {
- BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
- GetFromID(id));
+ BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (!node)
return false;
@@ -852,9 +915,12 @@ void BrowserAccessibilityManagerAndroid::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
const std::vector<ui::AXTreeDelegate::Change>& changes) {
+ BrowserAccessibilityManager::OnAtomicUpdateFinished(
+ tree, root_changed, changes);
+
if (root_changed) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
if (obj.is_null())
return;
@@ -868,6 +934,24 @@ BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() {
return false;
}
+BrowserAccessibilityAndroid*
+BrowserAccessibilityManagerAndroid::GetFromUniqueID(int32_t unique_id) {
+ return static_cast<BrowserAccessibilityAndroid*>(
+ BrowserAccessibility::GetFromUniqueID(unique_id));
+}
+
+ScopedJavaLocalRef<jobject>
+BrowserAccessibilityManagerAndroid::GetJavaRefFromRootManager() {
+ BrowserAccessibilityManagerAndroid* root_manager =
+ static_cast<BrowserAccessibilityManagerAndroid*>(
+ GetRootManager());
+ if (!root_manager)
+ return ScopedJavaLocalRef<jobject>();
+
+ JNIEnv* env = AttachCurrentThread();
+ return root_manager->java_ref().get(env);
+}
+
bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
return RegisterNativesImpl(env);
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
index 4bc42b54be5..d74699db24a 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -77,7 +77,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
// Implementation of BrowserAccessibilityManager.
void NotifyAccessibilityEvent(ui::AXEvent event_type,
BrowserAccessibility* node) override;
- void OnLocationChanges(
+ void SendLocationChangeEvents(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params)
override;
@@ -85,6 +85,10 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
// Methods called from Java via JNI
// --------------------------------------------------------------------------
+ // Global methods.
+ base::android::ScopedJavaLocalRef<jstring> GetSupportedHtmlElementTypes(
+ JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
// Tree methods.
jint GetRootId(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
jboolean IsNodeValid(JNIEnv* env,
@@ -214,6 +218,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
jint id,
int direction);
+ JavaObjectWeakGlobalRef& java_ref() { return java_ref_; }
+
protected:
// AXTreeDelegate overrides.
void OnAtomicUpdateFinished(
@@ -224,6 +230,10 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
bool UseRootScrollOffsetsWhenComputingBounds() override;
private:
+ BrowserAccessibilityAndroid* GetFromUniqueID(int32_t unique_id);
+
+ base::android::ScopedJavaLocalRef<jobject> GetJavaRefFromRootManager();
+
// This gives BrowserAccessibilityManager::Create access to the class
// constructor.
friend class BrowserAccessibilityManager;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
index 0cda76d2e93..715081920c4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -6,9 +6,16 @@
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_
#import <Cocoa/Cocoa.h>
+#include <stdint.h>
+
+#include <map>
+#include <vector>
#include "base/macros.h"
+#include "base/strings/string16.h"
+#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/public/browser/ax_event_notification_details.h"
namespace content {
@@ -21,17 +28,26 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+ ~BrowserAccessibilityManagerMac() override;
+
static ui::AXTreeUpdate GetEmptyDocument();
- BrowserAccessibility* GetFocus(BrowserAccessibility* root) override;
+ BrowserAccessibility* GetFocus() override;
// Implementation of BrowserAccessibilityManager.
void NotifyAccessibilityEvent(ui::AXEvent event_type,
BrowserAccessibility* node) override;
+ void OnAccessibilityEvents(
+ const std::vector<AXEventNotificationDetails>& details) override;
+
NSView* parent_view() { return parent_view_; }
private:
+ // AXTreeDelegate methods.
+ void OnNodeDataWillChange(ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) override;
void OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
@@ -40,12 +56,23 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
// Returns an autoreleased object.
NSDictionary* GetUserInfoForSelectedTextChangedNotification();
+ // Returns an autoreleased object.
+ NSDictionary* GetUserInfoForValueChangedNotification(
+ const BrowserAccessibilityCocoa* native_node,
+ const base::string16& deleted_text,
+ const base::string16& inserted_text) const;
+
// This gives BrowserAccessibilityManager::Create access to the class
// constructor.
friend class BrowserAccessibilityManager;
NSView* parent_view_;
+ // Keeps track of any edits that have been made by the user during a tree
+ // update. Used by NSAccessibilityValueChangedNotification.
+ // Maps AXNode IDs to name or value attribute changes.
+ std::map<int32_t, base::string16> text_edits_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 0937229b2aa..e43122e120b 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -4,19 +4,19 @@
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
-#include <stddef.h>
-
#import "base/mac/mac_util.h"
#import "base/mac/sdk_forward_declarations.h"
#include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#import "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/common/accessibility_messages.h"
-
namespace {
-// Declare accessibility constants and enums only present in WebKit.
+// Declare undocumented accessibility constants and enums only present in
+// WebKit.
enum AXTextStateChangeType {
AXTextStateChangeTypeUnknown,
@@ -46,6 +46,17 @@ enum AXTextSelectionGranularity {
AXTextSelectionGranularityAll
};
+enum AXTextEditType {
+ AXTextEditTypeUnknown,
+ AXTextEditTypeDelete,
+ AXTextEditTypeInsert,
+ AXTextEditTypeTyping,
+ AXTextEditTypeDictation,
+ AXTextEditTypeCut,
+ AXTextEditTypePaste,
+ AXTextEditTypeAttributesChange
+};
+
NSString* const NSAccessibilityAutocorrectionOccurredNotification =
@"AXAutocorrectionOccurred";
NSString* const NSAccessibilityLayoutCompleteNotification =
@@ -58,6 +69,9 @@ NSString* const NSAccessibilityLiveRegionChangedNotification =
@"AXLiveRegionChanged";
NSString* const NSAccessibilityMenuItemSelectedNotification =
@"AXMenuItemSelected";
+
+// Attributes used for NSAccessibilitySelectedTextChangedNotification and
+// NSAccessibilityValueChangedNotification.
NSString* const NSAccessibilityTextStateChangeTypeKey =
@"AXTextStateChangeType";
NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
@@ -67,8 +81,14 @@ NSString* const NSAccessibilityTextSelectionGranularity =
@"AXTextSelectionGranularity";
NSString* const NSAccessibilityTextSelectionChangedFocus =
@"AXTextSelectionChangedFocus";
-NSString* const NSAccessibilityTextChangeElement =
- @"AXAccessibilityTextChangeElement";
+NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
+ @"AXSelectedTextMarkerRange";
+NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
+NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
+NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
+NSString* const NSAccessibilityTextChangeValueLength =
+ @"AXTextChangeValueLength";
+NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
} // namespace
@@ -93,6 +113,8 @@ BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
Initialize(initial_tree);
}
+BrowserAccessibilityManagerMac::~BrowserAccessibilityManagerMac() {}
+
// static
ui::AXTreeUpdate
BrowserAccessibilityManagerMac::GetEmptyDocument() {
@@ -106,16 +128,15 @@ ui::AXTreeUpdate
return update;
}
-BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus(
- BrowserAccessibility* root) {
+BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus() {
// On Mac, list boxes should always get focus on the whole list, otherwise
// information about the number of selected items will never be reported.
- BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
+ BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus();
if (node && node->GetRole() == ui::AX_ROLE_LIST_BOX)
return node;
// For other roles, follow the active descendant.
- return GetActiveDescendantFocus(root);
+ return GetActiveDescendantFocus(node);
}
void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
@@ -125,8 +146,7 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
return;
if (event_type == ui::AX_EVENT_FOCUS) {
- BrowserAccessibility* active_descendant = GetActiveDescendantFocus(
- GetRoot());
+ BrowserAccessibility* active_descendant = GetActiveDescendantFocus(node);
if (active_descendant)
node = active_descendant;
@@ -135,11 +155,11 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
node->GetParent() &&
node->GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
node = node->GetParent();
- SetFocus(node, false);
+ SetFocus(*node);
}
}
- auto native_node = node->ToBrowserAccessibilityCocoa();
+ auto native_node = ToBrowserAccessibilityCocoa(node);
DCHECK(native_node);
// Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
@@ -182,6 +202,13 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
break;
case ui::AX_EVENT_DOCUMENT_SELECTION_CHANGED: {
mac_notification = NSAccessibilitySelectedTextChangedNotification;
+ // WebKit fires a notification both on the focused object and the root.
+ BrowserAccessibility* focus = GetFocus();
+ if (!focus)
+ break; // Just fire a notification on the root.
+ NSAccessibilityPostNotification(ToBrowserAccessibilityCocoa(focus),
+ mac_notification);
+
if (base::mac::IsOSElCapitanOrLater()) {
// |NSAccessibilityPostNotificationWithUserInfo| should be used on OS X
// 10.11 or later to notify Voiceover about text selection changes. This
@@ -189,15 +216,46 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
// appear to be needed by Voiceover before version 10.11.
NSDictionary* user_info =
GetUserInfoForSelectedTextChangedNotification();
+
+ BrowserAccessibility* root = GetRoot();
+ if (!root)
+ return;
+
NSAccessibilityPostNotificationWithUserInfo(
- native_node, mac_notification, user_info);
+ ToBrowserAccessibilityCocoa(focus), mac_notification, user_info);
+ NSAccessibilityPostNotificationWithUserInfo(
+ ToBrowserAccessibilityCocoa(root), mac_notification, user_info);
return;
}
break;
}
case ui::AX_EVENT_CHECKED_STATE_CHANGED:
+ mac_notification = NSAccessibilityValueChangedNotification;
+ break;
case ui::AX_EVENT_VALUE_CHANGED:
mac_notification = NSAccessibilityValueChangedNotification;
+ if (base::mac::IsOSElCapitanOrLater() && text_edits_.size()) {
+ // It seems that we don't need to distinguish between deleted and
+ // inserted text for now.
+ base::string16 deleted_text;
+ base::string16 inserted_text;
+ int32_t id = node->GetId();
+ const auto iterator = text_edits_.find(id);
+ if (iterator != text_edits_.end())
+ inserted_text = iterator->second;
+ NSDictionary* user_info = GetUserInfoForValueChangedNotification(
+ native_node, deleted_text, inserted_text);
+
+ BrowserAccessibility* root = GetRoot();
+ if (!root)
+ return;
+
+ NSAccessibilityPostNotificationWithUserInfo(
+ native_node, mac_notification, user_info);
+ NSAccessibilityPostNotificationWithUserInfo(
+ ToBrowserAccessibilityCocoa(root), mac_notification, user_info);
+ return;
+ }
break;
// TODO(nektar): Need to add an event for live region created.
case ui::AX_EVENT_LIVE_REGION_CHANGED:
@@ -244,6 +302,63 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
NSAccessibilityPostNotification(native_node, mac_notification);
}
+void BrowserAccessibilityManagerMac::OnAccessibilityEvents(
+ const std::vector<AXEventNotificationDetails>& details) {
+ text_edits_.clear();
+ // Call the base method last as it might delete the tree if it receives an
+ // invalid message.
+ BrowserAccessibilityManager::OnAccessibilityEvents(details);
+}
+
+void BrowserAccessibilityManagerMac::OnNodeDataWillChange(
+ ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) {
+ BrowserAccessibilityManager::OnNodeDataWillChange(tree, old_node_data,
+ new_node_data);
+
+ // Starting from OS X 10.11, if the user has edited some text we need to
+ // dispatch the actual text that changed on the value changed notification.
+ // We run this code on all OS X versions to get the highest test coverage.
+ base::string16 old_text, new_text;
+ ui::AXRole role = new_node_data.role;
+ if (role == ui::AX_ROLE_COMBO_BOX || role == ui::AX_ROLE_SEARCH_BOX ||
+ role == ui::AX_ROLE_TEXT_FIELD) {
+ old_text = old_node_data.GetString16Attribute(ui::AX_ATTR_VALUE);
+ new_text = new_node_data.GetString16Attribute(ui::AX_ATTR_VALUE);
+ } else if (new_node_data.state & (1 << ui::AX_STATE_EDITABLE)) {
+ old_text = old_node_data.GetString16Attribute(ui::AX_ATTR_NAME);
+ new_text = new_node_data.GetString16Attribute(ui::AX_ATTR_NAME);
+ }
+
+ if ((old_text.empty() && new_text.empty()) ||
+ old_text.length() == new_text.length()) {
+ return;
+ }
+
+ if (old_text.length() < new_text.length()) {
+ // Insertion.
+ size_t i = 0;
+ while (i < old_text.length() && i < new_text.length() &&
+ old_text[i] == new_text[i]) {
+ ++i;
+ }
+ size_t length = (new_text.length() - i) - (old_text.length() - i);
+ base::string16 inserted_text = new_text.substr(i, length);
+ text_edits_[new_node_data.id] = inserted_text;
+ } else {
+ // Deletion.
+ size_t i = 0;
+ while (i < old_text.length() && i < new_text.length() &&
+ old_text[i] == new_text[i]) {
+ ++i;
+ }
+ size_t length = (old_text.length() - i) - (new_text.length() - i);
+ base::string16 deleted_text = old_text.substr(i, length);
+ text_edits_[new_node_data.id] = deleted_text;
+ }
+}
+
void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
@@ -281,35 +396,65 @@ void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
}
}
-// Returns an autoreleased object.
NSDictionary* BrowserAccessibilityManagerMac::
GetUserInfoForSelectedTextChangedNotification() {
NSMutableDictionary* user_info = [[[NSMutableDictionary alloc] init]
autorelease];
- [user_info setObject:[NSNumber numberWithBool:YES]
- forKey:NSAccessibilityTextStateSyncKey];
- [user_info setObject:[NSNumber numberWithInt:AXTextStateChangeTypeUnknown]
+ [user_info setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
+ [user_info setObject:@(AXTextStateChangeTypeUnknown)
forKey:NSAccessibilityTextStateChangeTypeKey];
- [user_info
- setObject:[NSNumber numberWithInt:AXTextSelectionDirectionUnknown]
- forKey:NSAccessibilityTextSelectionDirection];
- [user_info
- setObject:[NSNumber numberWithInt:AXTextSelectionGranularityUnknown]
- forKey:NSAccessibilityTextSelectionGranularity];
- [user_info setObject:[NSNumber numberWithBool:YES]
- forKey:NSAccessibilityTextSelectionChangedFocus];
- // TODO(nektar): Set selected text marker range.
+ [user_info setObject:@(AXTextSelectionDirectionUnknown)
+ forKey:NSAccessibilityTextSelectionDirection];
+ [user_info setObject:@(AXTextSelectionGranularityUnknown)
+ forKey:NSAccessibilityTextSelectionGranularity];
+ [user_info setObject:@YES forKey:NSAccessibilityTextSelectionChangedFocus];
int32_t focus_id = GetTreeData().sel_focus_object_id;
BrowserAccessibility* focus_object = GetFromID(focus_id);
if (focus_object) {
- auto native_focus_object = focus_object->ToBrowserAccessibilityCocoa();
- if (native_focus_object)
+ focus_object = focus_object->GetClosestPlatformObject();
+ auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
+ if (native_focus_object && [native_focus_object instanceActive]) {
+ [user_info setObject:[native_focus_object selectedTextMarkerRange]
+ forKey:NSAccessibilitySelectedTextMarkerRangeAttribute];
[user_info setObject:native_focus_object
forKey:NSAccessibilityTextChangeElement];
+ }
}
return user_info;
}
+NSDictionary*
+BrowserAccessibilityManagerMac::GetUserInfoForValueChangedNotification(
+ const BrowserAccessibilityCocoa* native_node,
+ const base::string16& deleted_text,
+ const base::string16& inserted_text) const {
+ DCHECK(native_node);
+ if (deleted_text.empty() && inserted_text.empty())
+ return nil;
+
+ NSMutableArray* changes = [[[NSMutableArray alloc] init] autorelease];
+ if (!deleted_text.empty()) {
+ [changes addObject:@{
+ NSAccessibilityTextEditType : @(AXTextEditTypeUnknown),
+ NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
+ NSAccessibilityTextChangeValue : base::SysUTF16ToNSString(deleted_text)
+ }];
+ }
+ if (!inserted_text.empty()) {
+ [changes addObject:@{
+ NSAccessibilityTextEditType : @(AXTextEditTypeUnknown),
+ NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
+ NSAccessibilityTextChangeValue : base::SysUTF16ToNSString(inserted_text)
+ }];
+ }
+
+ return @{
+ NSAccessibilityTextStateChangeTypeKey : @(AXTextStateChangeTypeEdit),
+ NSAccessibilityTextChangeValues : changes,
+ NSAccessibilityTextChangeElement : native_node
+ };
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index c3a059652df..b13338f792e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -88,6 +88,9 @@ class TestBrowserAccessibilityDelegate
const gfx::Rect& bounds) const override {
return gfx::Point();
}
+ gfx::Rect AccessibilityTransformToRootCoordSpace(
+ const gfx::Rect& bounds) override { return gfx::Rect(); }
+ SiteInstance* AccessibilityGetSiteInstance() override { return nullptr; }
void AccessibilityHitTest(const gfx::Point& point) override {}
void AccessibilitySetAccessibilityFocus(int acc_obj_id) override {}
void AccessibilityFatalError() override { got_fatal_error_ = true; }
@@ -967,17 +970,18 @@ TEST(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
nullptr,
new CountedBrowserAccessibilityFactory()));
- auto root_accessible = manager->GetRoot();
+ BrowserAccessibility* root_accessible = manager->GetRoot();
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(3U, root_accessible->PlatformChildCount());
- auto node2_accessible = root_accessible->PlatformGetChild(0);
+ BrowserAccessibility* node2_accessible = root_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, node2_accessible);
- auto node3_accessible = root_accessible->PlatformGetChild(1);
+ BrowserAccessibility* node3_accessible = root_accessible->PlatformGetChild(1);
ASSERT_NE(nullptr, node3_accessible);
ASSERT_EQ(1U, node3_accessible->PlatformChildCount());
- auto node4_accessible = node3_accessible->PlatformGetChild(0);
+ BrowserAccessibility* node4_accessible =
+ node3_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, node4_accessible);
- auto node5_accessible = root_accessible->PlatformGetChild(2);
+ BrowserAccessibility* node5_accessible = root_accessible->PlatformGetChild(2);
ASSERT_NE(nullptr, node5_accessible);
EXPECT_EQ(nullptr, manager->NextInTreeOrder(nullptr));
@@ -1042,26 +1046,30 @@ TEST(BrowserAccessibilityManagerTest, TestNextPreviousTextOnlyObject) {
nullptr,
new CountedBrowserAccessibilityFactory()));
- auto root_accessible = manager->GetRoot();
+ BrowserAccessibility* root_accessible = manager->GetRoot();
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(4U, root_accessible->PlatformChildCount());
- auto node2_accessible = root_accessible->PlatformGetChild(0);
+ BrowserAccessibility* node2_accessible = root_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, node2_accessible);
- auto text1_accessible = root_accessible->PlatformGetChild(1);
+ BrowserAccessibility* text1_accessible = root_accessible->PlatformGetChild(1);
ASSERT_NE(nullptr, text1_accessible);
- auto node3_accessible = root_accessible->PlatformGetChild(2);
+ BrowserAccessibility* node3_accessible = root_accessible->PlatformGetChild(2);
ASSERT_NE(nullptr, node3_accessible);
ASSERT_EQ(3U, node3_accessible->PlatformChildCount());
- auto text2_accessible = node3_accessible->PlatformGetChild(0);
+ BrowserAccessibility* text2_accessible =
+ node3_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, text2_accessible);
- auto node4_accessible = node3_accessible->PlatformGetChild(1);
+ BrowserAccessibility* node4_accessible =
+ node3_accessible->PlatformGetChild(1);
ASSERT_NE(nullptr, node4_accessible);
- auto text3_accessible = node3_accessible->PlatformGetChild(2);
+ BrowserAccessibility* text3_accessible =
+ node3_accessible->PlatformGetChild(2);
ASSERT_NE(nullptr, text3_accessible);
- auto node5_accessible = root_accessible->PlatformGetChild(3);
+ BrowserAccessibility* node5_accessible = root_accessible->PlatformGetChild(3);
ASSERT_NE(nullptr, node5_accessible);
ASSERT_EQ(1U, node5_accessible->PlatformChildCount());
- auto text4_accessible = node5_accessible->PlatformGetChild(0);
+ BrowserAccessibility* text4_accessible =
+ node5_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, text4_accessible);
EXPECT_EQ(nullptr, manager->NextTextOnlyObject(nullptr));
@@ -1092,6 +1100,295 @@ TEST(BrowserAccessibilityManagerTest, TestNextPreviousTextOnlyObject) {
EXPECT_EQ(nullptr, manager->PreviousTextOnlyObject(root_accessible));
}
+TEST(BrowserAccessibilityManagerTest, TestFindIndicesInCommonParent) {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+
+ ui::AXNodeData div;
+ div.id = 2;
+ div.role = ui::AX_ROLE_DIV;
+ root.child_ids.push_back(div.id);
+
+ ui::AXNodeData button;
+ button.id = 3;
+ button.role = ui::AX_ROLE_BUTTON;
+ div.child_ids.push_back(button.id);
+
+ ui::AXNodeData button_text;
+ button_text.id = 4;
+ button_text.role = ui::AX_ROLE_STATIC_TEXT;
+ button_text.SetName("Button");
+ button.child_ids.push_back(button_text.id);
+
+ ui::AXNodeData line_break;
+ line_break.id = 5;
+ line_break.role = ui::AX_ROLE_LINE_BREAK;
+ line_break.SetName("\n");
+ div.child_ids.push_back(line_break.id);
+
+ ui::AXNodeData paragraph;
+ paragraph.id = 6;
+ paragraph.role = ui::AX_ROLE_PARAGRAPH;
+ root.child_ids.push_back(paragraph.id);
+
+ ui::AXNodeData paragraph_text;
+ paragraph_text.id = 7;
+ paragraph_text.role = ui::AX_ROLE_STATIC_TEXT;
+ paragraph.child_ids.push_back(paragraph_text.id);
+
+ ui::AXNodeData paragraph_line1;
+ paragraph_line1.id = 8;
+ paragraph_line1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ paragraph_line1.SetName("Hello ");
+ paragraph_text.child_ids.push_back(paragraph_line1.id);
+
+ ui::AXNodeData paragraph_line2;
+ paragraph_line2.id = 9;
+ paragraph_line2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ paragraph_line2.SetName("world.");
+ paragraph_text.child_ids.push_back(paragraph_line2.id);
+
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, div, button, button_text, line_break,
+ paragraph, paragraph_text, paragraph_line1,
+ paragraph_line2),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+
+ BrowserAccessibility* root_accessible = manager->GetRoot();
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+ BrowserAccessibility* div_accessible = root_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, div_accessible);
+ ASSERT_EQ(2U, div_accessible->PlatformChildCount());
+ BrowserAccessibility* button_accessible = div_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, button_accessible);
+ BrowserAccessibility* button_text_accessible =
+ button_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, button_text_accessible);
+ BrowserAccessibility* line_break_accessible =
+ div_accessible->PlatformGetChild(1);
+ ASSERT_NE(nullptr, line_break_accessible);
+ BrowserAccessibility* paragraph_accessible =
+ root_accessible->PlatformGetChild(1);
+ ASSERT_NE(nullptr, paragraph_accessible);
+ BrowserAccessibility* paragraph_text_accessible =
+ paragraph_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, paragraph_text_accessible);
+ ASSERT_EQ(2U, paragraph_text_accessible->InternalChildCount());
+ BrowserAccessibility* paragraph_line1_accessible =
+ paragraph_text_accessible->InternalGetChild(0);
+ ASSERT_NE(nullptr, paragraph_line1_accessible);
+ BrowserAccessibility* paragraph_line2_accessible =
+ paragraph_text_accessible->InternalGetChild(1);
+ ASSERT_NE(nullptr, paragraph_line2_accessible);
+
+ BrowserAccessibility* common_parent = nullptr;
+ int child_index1, child_index2;
+ EXPECT_FALSE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *root_accessible, *root_accessible, &common_parent, &child_index1,
+ &child_index2));
+ EXPECT_EQ(nullptr, common_parent);
+ EXPECT_EQ(-1, child_index1);
+ EXPECT_EQ(-1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *div_accessible, *paragraph_accessible, &common_parent, &child_index1,
+ &child_index2));
+ EXPECT_EQ(root_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *div_accessible, *paragraph_line1_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(root_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *line_break_accessible, *paragraph_text_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(root_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *button_text_accessible, *line_break_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(div_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *paragraph_accessible, *paragraph_line2_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(root_accessible, common_parent);
+ EXPECT_EQ(1, child_index1);
+ EXPECT_EQ(1, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *paragraph_text_accessible, *paragraph_line1_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(paragraph_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(0, child_index2);
+
+ EXPECT_TRUE(BrowserAccessibilityManager::FindIndicesInCommonParent(
+ *paragraph_line1_accessible, *paragraph_line2_accessible, &common_parent,
+ &child_index1, &child_index2));
+ EXPECT_EQ(paragraph_text_accessible, common_parent);
+ EXPECT_EQ(0, child_index1);
+ EXPECT_EQ(1, child_index2);
+}
+
+TEST(BrowserAccessibilityManagerTest, TestGetTextForRange) {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+
+ ui::AXNodeData div;
+ div.id = 2;
+ div.role = ui::AX_ROLE_DIV;
+ root.child_ids.push_back(div.id);
+
+ ui::AXNodeData button;
+ button.id = 3;
+ button.role = ui::AX_ROLE_BUTTON;
+ div.child_ids.push_back(button.id);
+
+ ui::AXNodeData button_text;
+ button_text.id = 4;
+ button_text.role = ui::AX_ROLE_STATIC_TEXT;
+ button_text.SetName("Button");
+ button.child_ids.push_back(button_text.id);
+
+ ui::AXNodeData line_break;
+ line_break.id = 5;
+ line_break.role = ui::AX_ROLE_LINE_BREAK;
+ line_break.SetName("\n");
+ div.child_ids.push_back(line_break.id);
+
+ ui::AXNodeData paragraph;
+ paragraph.id = 6;
+ paragraph.role = ui::AX_ROLE_PARAGRAPH;
+ root.child_ids.push_back(paragraph.id);
+
+ ui::AXNodeData paragraph_text;
+ paragraph_text.id = 7;
+ paragraph_text.role = ui::AX_ROLE_STATIC_TEXT;
+ paragraph_text.SetName("Hello world.");
+ paragraph.child_ids.push_back(paragraph_text.id);
+
+ ui::AXNodeData paragraph_line1;
+ paragraph_line1.id = 8;
+ paragraph_line1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ paragraph_line1.SetName("Hello ");
+ paragraph_text.child_ids.push_back(paragraph_line1.id);
+
+ ui::AXNodeData paragraph_line2;
+ paragraph_line2.id = 9;
+ paragraph_line2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ paragraph_line2.SetName("world.");
+ paragraph_text.child_ids.push_back(paragraph_line2.id);
+
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, div, button, button_text, line_break,
+ paragraph, paragraph_text, paragraph_line1,
+ paragraph_line2),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+
+ BrowserAccessibility* root_accessible = manager->GetRoot();
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+ BrowserAccessibility* div_accessible = root_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, div_accessible);
+ ASSERT_EQ(2U, div_accessible->PlatformChildCount());
+ BrowserAccessibility* button_accessible = div_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, button_accessible);
+ BrowserAccessibility* button_text_accessible =
+ button_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, button_text_accessible);
+ BrowserAccessibility* line_break_accessible =
+ div_accessible->PlatformGetChild(1);
+ ASSERT_NE(nullptr, line_break_accessible);
+ BrowserAccessibility* paragraph_accessible =
+ root_accessible->PlatformGetChild(1);
+ ASSERT_NE(nullptr, paragraph_accessible);
+ BrowserAccessibility* paragraph_text_accessible =
+ paragraph_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, paragraph_text_accessible);
+ ASSERT_EQ(2U, paragraph_text_accessible->InternalChildCount());
+ BrowserAccessibility* paragraph_line1_accessible =
+ paragraph_text_accessible->InternalGetChild(0);
+ ASSERT_NE(nullptr, paragraph_line1_accessible);
+ BrowserAccessibility* paragraph_line2_accessible =
+ paragraph_text_accessible->InternalGetChild(1);
+ ASSERT_NE(nullptr, paragraph_line2_accessible);
+
+ EXPECT_EQ(base::ASCIIToUTF16("Button\nHello world."),
+ BrowserAccessibilityManager::GetTextForRange(*root_accessible, 0,
+ *root_accessible, 19));
+ EXPECT_EQ(base::ASCIIToUTF16("ton\nHello world."),
+ BrowserAccessibilityManager::GetTextForRange(*root_accessible, 3,
+ *root_accessible, 19));
+ EXPECT_EQ(base::ASCIIToUTF16("Button\nHello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *div_accessible, 0, *paragraph_accessible, 12));
+ EXPECT_EQ(base::ASCIIToUTF16("ton\nHello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *div_accessible, 3, *paragraph_accessible, 12));
+
+ EXPECT_EQ(base::ASCIIToUTF16("Button\n"),
+ BrowserAccessibilityManager::GetTextForRange(*div_accessible, 0,
+ *div_accessible, 1));
+ EXPECT_EQ(base::ASCIIToUTF16("Button\n"),
+ BrowserAccessibilityManager::GetTextForRange(
+ *button_accessible, 0, *line_break_accessible, 1));
+
+ EXPECT_EQ(base::ASCIIToUTF16("Hello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_accessible, 0, *paragraph_accessible, 12));
+ EXPECT_EQ(base::ASCIIToUTF16("Hello wor"),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_accessible, 0, *paragraph_accessible, 9));
+ EXPECT_EQ(base::ASCIIToUTF16("Hello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_text_accessible, 0, *paragraph_text_accessible, 12));
+ EXPECT_EQ(base::ASCIIToUTF16(" world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_text_accessible, 5, *paragraph_text_accessible, 12));
+ EXPECT_EQ(base::ASCIIToUTF16("Hello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_accessible, 0, *paragraph_text_accessible, 12));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("Hello "),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line1_accessible, 0, *paragraph_line1_accessible, 6));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("Hello"),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line1_accessible, 0, *paragraph_line1_accessible, 5));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("ello "),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line1_accessible, 1, *paragraph_line1_accessible, 6));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line2_accessible, 0, *paragraph_line2_accessible, 6));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("orld"),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line2_accessible, 1, *paragraph_line2_accessible, 5));
+ EXPECT_EQ(
+ base::ASCIIToUTF16("Hello world."),
+ BrowserAccessibilityManager::GetTextForRange(
+ *paragraph_line1_accessible, 0, *paragraph_line2_accessible, 6));
+}
+
TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
// Create a really simple tree with one root node and one focused child.
ui::AXNodeData root;
@@ -1102,27 +1399,18 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
ui::AXNodeData node2;
node2.id = 2;
- node2.state = 1 << ui::AX_STATE_FOCUSED;
+ ui::AXTreeUpdate initial_state = MakeAXTreeUpdate(root, node2);
+ initial_state.has_tree_data = true;
+ initial_state.tree_data.focus_id = 2;
scoped_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
- MakeAXTreeUpdate(root, node2),
+ initial_state,
nullptr,
new CountedBrowserAccessibilityFactory()));
ASSERT_EQ(1, manager->GetRoot()->GetId());
- ASSERT_EQ(1, manager->GetFocus(manager->GetRoot())->GetId());
-
- // Send the focus event for node 2.
- std::vector<AXEventNotificationDetails> events;
- events.push_back(AXEventNotificationDetails());
- events[0].update = MakeAXTreeUpdate(node2);
- events[0].id = 2;
- events[0].event_type = ui::AX_EVENT_FOCUS;
- manager->OnAccessibilityEvents(events);
-
- ASSERT_EQ(1, manager->GetRoot()->GetId());
- ASSERT_EQ(2, manager->GetFocus(manager->GetRoot())->GetId());
+ ASSERT_EQ(2, manager->GetFocus()->GetId());
// Now replace the tree with a new tree consisting of a single root.
ui::AXNodeData root2;
@@ -1140,7 +1428,7 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
// Make sure that the focused node was updated to the new root and
// that this doesn't crash.
ASSERT_EQ(3, manager->GetRoot()->GetId());
- ASSERT_EQ(3, manager->GetFocus(manager->GetRoot())->GetId());
+ ASSERT_EQ(3, manager->GetFocus()->GetId());
}
TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
@@ -1155,7 +1443,6 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
ui::AXNodeData node2;
node2.id = 2;
- node2.state = 1 << ui::AX_STATE_FOCUSED;
ui::AXNodeData node3;
node3.id = 3;
@@ -1165,25 +1452,17 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
node4.id = 4;
node4.state = 0;
+ ui::AXTreeUpdate initial_state = MakeAXTreeUpdate(root, node2, node3, node4);
+ initial_state.has_tree_data = true;
+ initial_state.tree_data.focus_id = 2;
scoped_ptr<BrowserAccessibilityManager> manager(
BrowserAccessibilityManager::Create(
- MakeAXTreeUpdate(root, node2, node3, node4),
+ initial_state,
nullptr,
new CountedBrowserAccessibilityFactory()));
ASSERT_EQ(1, manager->GetRoot()->GetId());
- ASSERT_EQ(1, manager->GetFocus(manager->GetRoot())->GetId());
-
- // Send the focus event for node 2.
- std::vector<AXEventNotificationDetails> events;
- events.push_back(AXEventNotificationDetails());
- events[0].update = MakeAXTreeUpdate(node2);
- events[0].id = 2;
- events[0].event_type = ui::AX_EVENT_FOCUS;
- manager->OnAccessibilityEvents(events);
-
- ASSERT_EQ(1, manager->GetRoot()->GetId());
- ASSERT_EQ(2, manager->GetFocus(manager->GetRoot())->GetId());
+ ASSERT_EQ(2, manager->GetFocus()->GetId());
// Now replace the tree with a new tree consisting of a single root.
ui::AXNodeData root2;
@@ -1203,7 +1482,7 @@ TEST(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash2) {
// Make sure that the focused node was updated to the new root and
// that this doesn't crash.
ASSERT_EQ(3, manager->GetRoot()->GetId());
- ASSERT_EQ(3, manager->GetFocus(manager->GetRoot())->GetId());
+ ASSERT_EQ(3, manager->GetFocus()->GetId());
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
index 4f963ebcb02..0595ea7d2fe 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -20,10 +20,6 @@
namespace content {
-// Map from unique_id_win to BrowserAccessibility
-using UniqueIDWinMap = base::hash_map<LONG, BrowserAccessibility*>;
-base::LazyInstance<UniqueIDWinMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER;
-
// static
BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
const ui::AXTreeUpdate& initial_tree,
@@ -42,11 +38,10 @@ BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
: BrowserAccessibilityManager(delegate, factory),
- tracked_scroll_object_(NULL),
- focus_event_on_root_needed_(false),
- inside_on_window_focused_(false) {
+ tracked_scroll_object_(NULL) {
ui::win::CreateATLModuleIfNeeded();
Initialize(initial_tree);
+ ui::GetIAccessible2UsageObserverList().AddObserver(this);
}
BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
@@ -59,6 +54,7 @@ BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
tracked_scroll_object_->Release();
tracked_scroll_object_ = NULL;
}
+ ui::GetIAccessible2UsageObserverList().RemoveObserver(this);
}
// static
@@ -93,7 +89,8 @@ IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() {
void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(
DWORD event, BrowserAccessibility* node) {
- BrowserAccessibilityDelegate* delegate = GetDelegateFromRootManager();
+ BrowserAccessibilityDelegate* delegate =
+ node->manager()->GetDelegateFromRootManager();
if (!delegate) {
// This line and other LOG(WARNING) lines are temporary, to debug
// flaky failures in DumpAccessibilityEvent* tests.
@@ -118,65 +115,19 @@ void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(
// It doesn't make sense to fire a REORDER event on a leaf node; that
// happens when the node has internal children line inline text boxes.
- if (event == EVENT_OBJECT_REORDER && node->PlatformIsLeaf())
- return;
-
- // Don't fire focus, or load complete notifications if the
- // window isn't focused, because that can confuse screen readers into
- // entering their "browse" mode.
- if ((event == EVENT_OBJECT_FOCUS ||
- event == IA2_EVENT_DOCUMENT_LOAD_COMPLETE) &&
- !NativeViewHasFocus()) {
+ if (event == EVENT_OBJECT_REORDER && node->PlatformChildCount() == 0)
return;
- }
- // NVDA gets confused if we focus the main document element when it hasn't
- // finished loading and it has no children at all, so suppress that event.
- if (event == EVENT_OBJECT_FOCUS &&
- node == GetRoot() &&
- node->PlatformChildCount() == 0 &&
- !node->HasState(ui::AX_STATE_BUSY) &&
- !node->manager()->GetTreeData().loaded) {
- return;
- }
-
- // If a focus event is needed on the root, fire that first before
- // this event.
- if (event == EVENT_OBJECT_FOCUS && node == GetRoot())
- focus_event_on_root_needed_ = false;
- else if (focus_event_on_root_needed_)
- OnWindowFocused();
-
- LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
+ // Pass the negation of this node's unique id in the |child_id|
+ // argument to NotifyWinEvent; the AT client will then call get_accChild
+ // on the HWND's accessibility object and pass it that same id, which
+ // we can use to retrieve the IAccessible for this node.
+ LONG child_id = -node->unique_id();
::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
}
-void BrowserAccessibilityManagerWin::OnWindowFocused() {
- // Make sure we don't call this recursively.
- if (inside_on_window_focused_)
- return;
- inside_on_window_focused_ = true;
-
- // This is called either when this web frame gets focused, or when
- // the root of the accessibility tree changes. In both cases, we need
- // to fire a focus event on the root and then on the focused element
- // within the page, if different.
-
- // Set this flag so that we'll keep trying to fire these focus events
- // if they're not successful this time.
- focus_event_on_root_needed_ = true;
-
- if (!NativeViewHasFocus()) {
- inside_on_window_focused_ = false;
- return;
- }
-
- // Try to fire a focus event on the root first and then the focused node.
- // This will clear focus_event_on_root_needed_ if successful.
- if (focus_ != tree_->root() && GetRoot())
- NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
- BrowserAccessibilityManager::OnWindowFocused();
- inside_on_window_focused_ = false;
+void BrowserAccessibilityManagerWin::OnIAccessible2Used() {
+ BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected();
}
void BrowserAccessibilityManagerWin::UserIsReloading() {
@@ -213,23 +164,6 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
return;
}
- // NVDA gets confused if we focus the main document element when it hasn't
- // finished loading and it has no children at all, so suppress that event.
- if (event_type == ui::AX_EVENT_FOCUS &&
- node == GetRoot() &&
- node->PlatformChildCount() == 0 &&
- !node->HasState(ui::AX_STATE_BUSY) &&
- !node->manager()->GetTreeData().loaded) {
- return;
- }
-
- // If a focus event is needed on the root, fire that first before
- // this event.
- if (event_type == ui::AX_EVENT_FOCUS && node == GetRoot())
- focus_event_on_root_needed_ = false;
- else if (focus_event_on_root_needed_)
- OnWindowFocused();
-
LONG event_id = EVENT_MIN;
switch (event_type) {
case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
@@ -287,13 +221,9 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
if (!node)
return;
- if (event_id != EVENT_MIN) {
- // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
- // the AT client will then call get_accChild on the HWND's accessibility
- // object and pass it that same id, which we can use to retrieve the
- // IAccessible for this node.
+ if (event_id != EVENT_MIN)
MaybeCallNotifyWinEvent(event_id, node);
- }
+
// If this is a layout complete notification (sent when a container scrolls)
// and there is a descendant tracked object, send a notification on it.
@@ -308,6 +238,26 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
}
}
+bool BrowserAccessibilityManagerWin::CanFireEvents() {
+ BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
+ if (!root_delegate)
+ return false;
+ HWND hwnd = root_delegate->AccessibilityGetAcceleratedWidget();
+ return hwnd != nullptr;
+}
+
+void BrowserAccessibilityManagerWin::FireFocusEvent(
+ BrowserAccessibility* node) {
+ // On Windows, we always fire a FOCUS event on the root of a frame before
+ // firing a focus event within that frame.
+ if (node->manager() != last_focused_manager_ &&
+ node != node->manager()->GetRoot()) {
+ NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node->manager()->GetRoot());
+ }
+
+ BrowserAccessibilityManager::FireFocusEvent(node);
+}
+
void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree,
ui::AXNode* node) {
DCHECK(node);
@@ -317,8 +267,6 @@ void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree,
return;
if (!obj->IsNative())
return;
- LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
- g_unique_id_map.Get()[unique_id_win] = obj;
}
void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree,
@@ -326,8 +274,6 @@ void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree,
DCHECK(node);
BrowserAccessibility* obj = GetFromAXNode(node);
if (obj && obj->IsNative()) {
- g_unique_id_map.Get().erase(
- obj->ToBrowserAccessibilityWin()->unique_id_win());
if (obj == tracked_scroll_object_) {
tracked_scroll_object_->Release();
tracked_scroll_object_ = NULL;
@@ -346,12 +292,6 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
BrowserAccessibilityManager::OnAtomicUpdateFinished(
tree, root_changed, changes);
- if (root_changed) {
- // In order to make screen readers aware of the new accessibility root,
- // we need to fire a focus event on it.
- OnWindowFocused();
- }
-
// Do a sequence of Windows-specific updates on each node. Each one is
// done in a single pass that must complete before the next step starts.
// The first step moves win_attributes_ to old_win_attributes_ and then
@@ -361,7 +301,7 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
DCHECK(changed_node);
BrowserAccessibility* obj = GetFromAXNode(changed_node);
if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
- obj->ToBrowserAccessibilityWin()->UpdateStep1ComputeWinAttributes();
+ ToBrowserAccessibilityWin(obj)->UpdateStep1ComputeWinAttributes();
}
// The next step updates the hypertext of each node, which is a
@@ -372,7 +312,7 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
DCHECK(changed_node);
BrowserAccessibility* obj = GetFromAXNode(changed_node);
if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
- obj->ToBrowserAccessibilityWin()->UpdateStep2ComputeHypertext();
+ ToBrowserAccessibilityWin(obj)->UpdateStep2ComputeHypertext();
}
// The third step fires events on nodes based on what's changed - like
@@ -388,7 +328,7 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
DCHECK(changed_node);
BrowserAccessibility* obj = GetFromAXNode(changed_node);
if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) {
- obj->ToBrowserAccessibilityWin()->UpdateStep3FireEvents(
+ ToBrowserAccessibilityWin(obj)->UpdateStep3FireEvents(
changes[i].type == AXTreeDelegate::SUBTREE_CREATED);
}
}
@@ -402,13 +342,4 @@ void BrowserAccessibilityManagerWin::TrackScrollingObject(
tracked_scroll_object_->AddRef();
}
-BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
- LONG unique_id_win) {
- auto iter = g_unique_id_map.Get().find(unique_id_win);
- if (iter == g_unique_id_map.Get().end())
- return nullptr;
-
- return iter->second->ToBrowserAccessibilityWin();
-}
-
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
index b9da9a12c6a..04b8aa241bb 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -11,13 +11,15 @@
#include "base/memory/scoped_ptr.h"
#include "base/win/scoped_comptr.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
namespace content {
class BrowserAccessibilityWin;
// Manages a tree of BrowserAccessibilityWin objects.
class CONTENT_EXPORT BrowserAccessibilityManagerWin
- : public BrowserAccessibilityManager {
+ : public BrowserAccessibilityManager,
+ public ui::IAccessible2UsageObserver {
public:
BrowserAccessibilityManagerWin(
const ui::AXTreeUpdate& initial_tree,
@@ -37,26 +39,26 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// Calls NotifyWinEvent if the parent window's IAccessible pointer is known.
void MaybeCallNotifyWinEvent(DWORD event, BrowserAccessibility* node);
+ // IAccessible2UsageObserver
+ void OnIAccessible2Used() override;
+
// BrowserAccessibilityManager methods
- void OnWindowFocused() override;
void UserIsReloading() override;
void NotifyAccessibilityEvent(
ui::AXEvent event_type, BrowserAccessibility* node) override;
+ bool CanFireEvents() override;
+ void FireFocusEvent(BrowserAccessibility* node) override;
// Track this object and post a VISIBLE_DATA_CHANGED notification when
// its container scrolls.
// TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
void TrackScrollingObject(BrowserAccessibilityWin* node);
- // Return a pointer to the object corresponding to the given windows-specific
- // unique id, does not make a new reference.
- BrowserAccessibilityWin* GetFromUniqueIdWin(LONG unique_id_win);
-
// Called when |accessible_hwnd_| is deleted by its parent.
void OnAccessibleHwndDeleted();
protected:
- // AXTree methods.
+ // AXTreeDelegate methods.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(
@@ -73,14 +75,6 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
BrowserAccessibilityWin* tracked_scroll_object_;
- // Set to true if we need to fire a focus event on the root as soon as
- // possible.
- bool focus_event_on_root_needed_;
-
- // A flag to keep track of if we're inside the OnWindowFocused call stack
- // so we don't keep calling it recursively.
- bool inside_on_window_focused_;
-
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
index 8fb3442d422..4038d66d063 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -122,7 +122,7 @@ void BrowserAccessibilityStateImpl::UpdateHistograms() {
switches::kForceRendererAccessibility));
}
-#if !defined(OS_WIN)
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
}
#endif
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_state_impl_mac.mm
new file mode 100644
index 00000000000..863627f0f2e
--- /dev/null
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl_mac.mm
@@ -0,0 +1,44 @@
+// 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 "content/browser/accessibility/browser_accessibility_state_impl.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/metrics/histogram.h"
+
+@interface NSWorkspace (Partials)
+
+@property(readonly) BOOL accessibilityDisplayShouldDifferentiateWithoutColor;
+@property(readonly) BOOL accessibilityDisplayShouldIncreaseContrast;
+@property(readonly) BOOL accessibilityDisplayShouldReduceTransparency;
+
+@end
+
+namespace content {
+
+void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
+ // NOTE: This function is running on the file thread.
+ NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
+
+ SEL sel = @selector(accessibilityDisplayShouldIncreaseContrast);
+ if (![workspace respondsToSelector:sel])
+ return;
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "Accessibility.Mac.DifferentiateWithoutColor",
+ workspace.accessibilityDisplayShouldDifferentiateWithoutColor);
+ UMA_HISTOGRAM_BOOLEAN(
+ "Accessibility.Mac.IncreaseContrast",
+ workspace.accessibilityDisplayShouldIncreaseContrast);
+ UMA_HISTOGRAM_BOOLEAN(
+ "Accessibility.Mac.ReduceTransparency",
+ workspace.accessibilityDisplayShouldReduceTransparency);
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "Accessibility.Mac.FullKeyboardAccessEnabled",
+ static_cast<NSApplication*>(NSApp).fullKeyboardAccessEnabled);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index 1409b0f1ab5..1267770e9a2 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.cc b/chromium/content/browser/accessibility/browser_accessibility_win.cc
index 54165ed7323..98aeb77bc77 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.cc
@@ -20,6 +20,7 @@
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/common/accessibility_messages.h"
#include "content/public/common/content_client.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_text_utils.h"
#include "ui/base/win/accessibility_ids_win.h"
#include "ui/base/win/accessibility_misc_utils.h"
@@ -42,10 +43,6 @@ const GUID GUID_IAccessibleContentDocument = {
const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter = L'\xfffc';
-// static
-LONG BrowserAccessibilityWin::next_unique_id_win_ =
- base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
-
//
// BrowserAccessibilityRelation
//
@@ -119,9 +116,8 @@ STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) {
*n_targets = static_cast<long>(target_ids_.size());
- BrowserAccessibilityManager* manager = owner_->manager();
for (long i = *n_targets - 1; i >= 0; --i) {
- BrowserAccessibility* result = manager->GetFromID(target_ids_[i]);
+ BrowserAccessibilityWin* result = owner_->GetFromID(target_ids_[i]);
if (!result || !result->instance_active()) {
*n_targets = 0;
break;
@@ -143,14 +139,12 @@ STDMETHODIMP BrowserAccessibilityRelation::get_target(long target_index,
return E_INVALIDARG;
}
- BrowserAccessibilityManager* manager = owner_->manager();
- BrowserAccessibility* result =
- manager->GetFromID(target_ids_[target_index]);
+ BrowserAccessibility* result = owner_->GetFromID(target_ids_[target_index]);
if (!result || !result->instance_active())
return E_FAIL;
*target = static_cast<IAccessible*>(
- result->ToBrowserAccessibilityWin()->NewReference());
+ ToBrowserAccessibilityWin(result)->NewReference());
return S_OK;
}
@@ -207,29 +201,10 @@ BrowserAccessibility* BrowserAccessibility::Create() {
return instance->NewReference();
}
-const BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin()
- const {
- return static_cast<const BrowserAccessibilityWin*>(this);
-}
-
-BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() {
- return static_cast<BrowserAccessibilityWin*>(this);
-}
-
BrowserAccessibilityWin::BrowserAccessibilityWin()
: win_attributes_(new WinAttributes()),
previous_scroll_x_(0),
previous_scroll_y_(0) {
- // Start unique IDs at -1 and decrement each time, because get_accChild
- // uses positive IDs to enumerate children, so we use negative IDs to
- // clearly distinguish between indices and unique IDs.
- unique_id_win_ = next_unique_id_win_;
- if (next_unique_id_win_ ==
- base::win::kLastBrowserAccessibilityManagerAccessibilityId) {
- next_unique_id_win_ =
- base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
- }
- next_unique_id_win_--;
}
BrowserAccessibilityWin::~BrowserAccessibilityWin() {
@@ -254,6 +229,10 @@ HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
if (!target)
return E_INVALIDARG;
+ // Return an error if it's not clickable.
+ if (!target->HasStringAttribute(ui::AX_ATTR_ACTION))
+ return DISP_E_MEMBERNOTFOUND;
+
manager()->DoDefaultAction(*target);
return S_OK;
}
@@ -281,7 +260,7 @@ STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left,
child->lVal = CHILDID_SELF;
} else {
child->vt = VT_DISPATCH;
- child->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
+ child->pdispVal = ToBrowserAccessibilityWin(result)->NewReference();
}
return S_OK;
}
@@ -355,7 +334,7 @@ STDMETHODIMP BrowserAccessibilityWin::accNavigate(LONG nav_dir,
}
end->vt = VT_DISPATCH;
- end->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
+ end->pdispVal = ToBrowserAccessibilityWin(result)->NewReference();
return S_OK;
}
@@ -435,7 +414,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) {
return E_INVALIDARG;
BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>(
- manager()->GetFocus(this));
+ manager()->GetFocus());
if (focus == this) {
focus_child->vt = VT_I4;
focus_child->lVal = CHILDID_SELF;
@@ -487,8 +466,16 @@ STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
return E_INVALIDARG;
base::string16 name_str = target->name();
- if (name_str.empty())
- return S_FALSE;
+ if (name_str.empty()) {
+ if (target->ia2_role() == ROLE_SYSTEM_DOCUMENT && GetParent()) {
+ // Hack: Some versions of JAWS crash if they get an empty name on
+ // a document that's the child of an iframe, so always return a
+ // nonempty string for this role. https://crbug.com/583057
+ name_str = L" ";
+ } else {
+ return S_FALSE;
+ }
+ }
*name = SysAllocString(name_str.c_str());
@@ -503,7 +490,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
if (!disp_parent)
return E_INVALIDARG;
- IAccessible* parent_obj = GetParent()->ToBrowserAccessibilityWin();
+ IAccessible* parent_obj = ToBrowserAccessibilityWin(GetParent());
if (parent_obj == NULL) {
// This happens if we're the root of the tree;
// return the IAccessible for the window.
@@ -562,7 +549,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
state->vt = VT_I4;
state->lVal = target->ia_state();
- if (manager()->GetFocus(NULL) == this)
+ if (manager()->GetFocus() == this)
state->lVal |= STATE_SYSTEM_FOCUSED;
return S_OK;
@@ -591,14 +578,15 @@ STDMETHODIMP BrowserAccessibilityWin::get_accValue(VARIANT var_id,
// Expose color well value.
if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) {
- int color = target->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE);
- int red = (color >> 16) & 0xFF;
- int green = (color >> 8) & 0xFF;
- int blue = color & 0xFF;
+ unsigned int color = static_cast<unsigned int>(
+ target->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE));
+ unsigned int red = SkColorGetR(color);
+ unsigned int green = SkColorGetG(color);
+ unsigned int blue = SkColorGetB(color);
base::string16 value_text;
- value_text = base::IntToString16((red * 100) / 255) + L"% red " +
- base::IntToString16((green * 100) / 255) + L"% green " +
- base::IntToString16((blue * 100) / 255) + L"% blue";
+ value_text = base::UintToString16(red * 100 / 255) + L"% red " +
+ base::UintToString16(green * 100 / 255) + L"% green " +
+ base::UintToString16(blue * 100 / 255) + L"% blue";
*value = SysAllocString(value_text.c_str());
DCHECK(*value);
return S_OK;
@@ -638,7 +626,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
selected->vt = VT_DISPATCH;
selected->pdispVal =
- InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
+ ToBrowserAccessibilityWin(InternalGetChild(i))->NewReference();
return S_OK;
}
}
@@ -653,7 +641,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
enum_variant->ItemAt(index)->vt = VT_DISPATCH;
enum_variant->ItemAt(index)->pdispVal =
- InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
+ ToBrowserAccessibilityWin(InternalGetChild(i))->NewReference();
++index;
}
}
@@ -669,7 +657,7 @@ STDMETHODIMP BrowserAccessibilityWin::accSelect(
return E_FAIL;
if (flags_sel & SELFLAG_TAKEFOCUS) {
- manager()->SetFocus(this, true);
+ manager()->SetFocus(*this);
return S_OK;
}
@@ -702,19 +690,16 @@ STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
}
STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
- if (!instance_active())
- return E_FAIL;
-
if (!attributes)
return E_INVALIDARG;
+ *attributes = nullptr;
+
+ if (!instance_active())
+ return E_FAIL;
- // The iaccessible2 attributes are a set of key-value pairs
- // separated by semicolons, with a colon between the key and the value.
base::string16 str;
- const std::vector<base::string16>& attributes_list = ia2_attributes();
- for (unsigned int i = 0; i < attributes_list.size(); ++i) {
- str += attributes_list[i] + L';';
- }
+ for (const base::string16& attribute : ia2_attributes())
+ str += attribute + L';';
if (str.empty())
return S_FALSE;
@@ -743,7 +728,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_uniqueID(LONG* unique_id) {
if (!unique_id)
return E_INVALIDARG;
- *unique_id = unique_id_win_;
+ *unique_id = -unique_id_;
return S_OK;
}
@@ -862,7 +847,6 @@ STDMETHODIMP BrowserAccessibilityWin::scrollTo(IA2ScrollType scroll_type) {
}
manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
-
return S_OK;
}
@@ -1196,8 +1180,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column,
GetIntListAttribute(ui::AX_ATTR_CELL_IDS);
for (int i = 0; i < rows; ++i) {
int cell_id = cell_ids[i * columns + column];
- BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
- manager()->GetFromID(cell_id));
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) {
base::string16 cell_name = cell->GetString16Attribute(
ui::AX_ATTR_NAME);
@@ -1242,8 +1225,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt(
const std::vector<int32_t>& cell_ids =
GetIntListAttribute(ui::AX_ATTR_CELL_IDS);
int cell_id = cell_ids[row * columns + column];
- BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
- manager()->GetFromID(cell_id));
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
int colspan;
if (cell &&
cell->GetIntAttribute(
@@ -1280,8 +1262,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long cell_index,
return S_FALSE;
int cell_id = unique_cell_ids[cell_index];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
int col_index;
if (cell &&
cell->GetIntAttribute(
@@ -1385,8 +1366,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row,
GetIntListAttribute(ui::AX_ATTR_CELL_IDS);
for (int i = 0; i < columns; ++i) {
int cell_id = cell_ids[row * columns + i];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
base::string16 cell_name = cell->GetString16Attribute(
ui::AX_ATTR_NAME);
@@ -1430,8 +1410,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt(long row,
const std::vector<int32_t>& cell_ids =
GetIntListAttribute(ui::AX_ATTR_CELL_IDS);
int cell_id = cell_ids[row * columns + column];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
int rowspan;
if (cell &&
cell->GetIntAttribute(
@@ -1468,8 +1447,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long cell_index,
return S_FALSE;
int cell_id = unique_cell_ids[cell_index];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
int cell_row_index;
if (cell &&
cell->GetIntAttribute(
@@ -1597,8 +1575,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
return S_FALSE;
int cell_id = unique_cell_ids[index];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
int rowspan;
int colspan;
if (cell &&
@@ -1756,8 +1733,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells(
for (int i = 0; i < rows; ++i) {
int cell_id = cell_ids[i * columns + column];
- BrowserAccessibilityWin* cell =
- manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* cell = GetFromID(cell_id);
if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER)
(*n_column_header_cells)++;
}
@@ -1770,7 +1746,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells(
BrowserAccessibility* cell = manager()->GetFromID(cell_id);
if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) {
(*cell_accessibles)[index] = static_cast<IAccessible*>(
- cell->ToBrowserAccessibilityWin()->NewReference());
+ ToBrowserAccessibilityWin(cell)->NewReference());
++index;
}
}
@@ -1867,7 +1843,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells(
BrowserAccessibility* cell = manager()->GetFromID(cell_id);
if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
(*cell_accessibles)[index] = static_cast<IAccessible*>(
- cell->ToBrowserAccessibilityWin()->NewReference());
+ ToBrowserAccessibilityWin(cell)->NewReference());
++index;
}
}
@@ -1962,7 +1938,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_table(IUnknown** table) {
}
*table = static_cast<IAccessibleTable*>(
- find_table->ToBrowserAccessibilityWin()->NewReference());
+ ToBrowserAccessibilityWin(find_table)->NewReference());
return S_OK;
}
@@ -2364,15 +2340,40 @@ STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index,
return S_OK;
}
-//
-// IAccessibleText methods not implemented.
-//
-
STDMETHODIMP BrowserAccessibilityWin::get_attributes(LONG offset,
LONG* start_offset,
LONG* end_offset,
BSTR* text_attributes) {
- return E_NOTIMPL;
+ if (!start_offset || !end_offset || !text_attributes)
+ return E_INVALIDARG;
+
+ *start_offset = *end_offset = 0;
+ *text_attributes = nullptr;
+ if (!instance_active())
+ return E_FAIL;
+
+ const base::string16& text = GetText();
+ HandleSpecialTextOffset(text, &offset);
+ if (offset < 0 || offset > static_cast<LONG>(text.size()))
+ return E_INVALIDARG;
+
+ ComputeStylesIfNeeded();
+ *start_offset = FindStartOfStyle(offset, ui::BACKWARDS_DIRECTION);
+ *end_offset = FindStartOfStyle(offset, ui::FORWARDS_DIRECTION);
+
+ base::string16 attributes_str;
+ const std::vector<base::string16>& attributes =
+ offset_to_text_attributes().find(*start_offset)->second;
+ for (const base::string16& attribute : attributes) {
+ attributes_str += attribute + L';';
+ }
+
+ if (attributes.empty())
+ return S_FALSE;
+
+ *text_attributes = SysAllocString(attributes_str.c_str());
+ DCHECK(*text_attributes);
+ return S_OK;
}
//
@@ -2403,14 +2404,12 @@ STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
}
int32_t id = hyperlinks()[index];
- BrowserAccessibilityWin* child =
- manager()->GetFromID(id)->ToBrowserAccessibilityWin();
- if (child) {
- *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
- return S_OK;
- }
+ BrowserAccessibilityWin* link = GetFromID(id);
+ if (!link)
+ return E_FAIL;
- return E_FAIL;
+ *hyperlink = static_cast<IAccessibleHyperlink*>(link->NewReference());
+ return S_OK;
}
STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
@@ -2502,7 +2501,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_startIndex(long* index) {
const auto parent = GetParent();
if (parent) {
hypertext_offset =
- parent->ToBrowserAccessibilityWin()->GetHypertextOffsetFromChild(*this);
+ ToBrowserAccessibilityWin(parent)->GetHypertextOffsetFromChild(*this);
}
*index = static_cast<LONG>(hypertext_offset);
return S_OK;
@@ -2743,7 +2742,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
*name_space_id = 0;
*node_value = SysAllocString(value().c_str());
*num_children = PlatformChildCount();
- *unique_id = unique_id_win_;
+ *unique_id = -unique_id_;
if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
GetRole() == ui::AX_ROLE_WEB_AREA) {
@@ -2881,7 +2880,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) {
if (!node)
return E_INVALIDARG;
- *node = GetParent()->ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(GetParent())->NewReference();
return S_OK;
}
@@ -2897,7 +2896,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) {
return S_FALSE;
}
- *node = PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(PlatformGetChild(0))->NewReference();
return S_OK;
}
@@ -2913,8 +2912,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) {
return S_FALSE;
}
- *node = PlatformGetChild(PlatformChildCount() - 1)
- ->ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(
+ PlatformGetChild(PlatformChildCount() - 1))->NewReference();
return S_OK;
}
@@ -2931,8 +2930,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_previousSibling(
return S_FALSE;
}
- *node = GetParent()->InternalGetChild(GetIndexInParent() - 1)->
- ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(
+ GetParent()->InternalGetChild(GetIndexInParent() - 1))->NewReference();
return S_OK;
}
@@ -2951,8 +2950,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) {
return S_FALSE;
}
- *node = GetParent()->InternalGetChild(GetIndexInParent() + 1)->
- ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(
+ GetParent()->InternalGetChild(GetIndexInParent() + 1))->NewReference();
return S_OK;
}
@@ -2974,7 +2973,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_childAt(
return S_FALSE;
}
- *node = child->ToBrowserAccessibilityWin()->NewReference();
+ *node = ToBrowserAccessibilityWin(child)->NewReference();
return S_OK;
}
@@ -2988,7 +2987,20 @@ BrowserAccessibilityWin::get_localInterface(void** local_interface) {
}
STDMETHODIMP BrowserAccessibilityWin::get_language(BSTR* language) {
- return E_NOTIMPL;
+ if (!language)
+ return E_INVALIDARG;
+ *language = nullptr;
+
+ if (!instance_active())
+ return E_FAIL;
+
+ base::string16 lang = GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE);
+ if (lang.empty())
+ lang = L"en-US";
+
+ *language = SysAllocString(lang.c_str());
+ DCHECK(*language);
+ return S_OK;
}
//
@@ -3067,7 +3079,21 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring(
}
STDMETHODIMP BrowserAccessibilityWin::get_fontFamily(BSTR* font_family) {
- return E_NOTIMPL;
+ if (!font_family)
+ return E_INVALIDARG;
+ *font_family = nullptr;
+
+ if (!instance_active())
+ return E_FAIL;
+
+ base::string16 family =
+ GetInheritedString16Attribute(ui::AX_ATTR_FONT_FAMILY);
+ if (family.empty())
+ return S_FALSE;
+
+ *font_family = SysAllocString(family.c_str());
+ DCHECK(*font_family);
+ return S_OK;
}
//
@@ -3093,7 +3119,7 @@ STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guid_service,
BrowserAccessibility* node = this;
while (node->GetParent())
node = node->GetParent()->manager()->GetRoot();
- return node->ToBrowserAccessibilityWin()->QueryInterface(
+ return ToBrowserAccessibilityWin(node)->QueryInterface(
IID_IAccessible2, object);
}
@@ -3248,6 +3274,45 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
this_ptr, entries, iid, object);
}
+void BrowserAccessibilityWin::ComputeStylesIfNeeded() {
+ if (!offset_to_text_attributes().empty())
+ return;
+
+ std::map<int, std::vector<base::string16>> attributes_map;
+ if (PlatformIsLeaf()) {
+ attributes_map[0] = ComputeTextAttributes();
+ win_attributes_->offset_to_text_attributes.swap(attributes_map);
+ return;
+ }
+
+ int start_offset = 0;
+ for (size_t i = 0; i < PlatformChildCount(); ++i) {
+ const auto child = ToBrowserAccessibilityWin(PlatformGetChild(i));
+ DCHECK(child);
+ std::vector<base::string16> attributes(child->ComputeTextAttributes());
+
+ if (attributes_map.empty()) {
+ attributes_map[start_offset] = attributes;
+ } else {
+ // Only add the attributes for this child if we are at the start of a new
+ // style span.
+ std::vector<base::string16> previous_attributes =
+ attributes_map.rbegin()->second;
+ if (!std::equal(attributes.begin(), attributes.end(),
+ previous_attributes.begin())) {
+ attributes_map[start_offset] = attributes;
+ }
+ }
+
+ if (child->IsTextOnlyObject())
+ start_offset += child->GetText().length();
+ else
+ start_offset += 1;
+ }
+
+ win_attributes_->offset_to_text_attributes.swap(attributes_map);
+}
+
base::string16 BrowserAccessibilityWin::GetText() const {
if (PlatformIsChildOfLeaf())
return BrowserAccessibility::GetText();
@@ -3308,6 +3373,13 @@ void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() {
BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY,
"container-busy");
+ // Expose the non-standard explicit-name IA2 attribute.
+ int name_from;
+ if (GetIntAttribute(ui::AX_ATTR_NAME_FROM, &name_from) &&
+ name_from != ui::AX_NAME_FROM_CONTENTS) {
+ win_attributes_->ia2_attributes.push_back(L"explicit-name:true");
+ }
+
// Expose table cell index.
if (IsCellOrTableHeaderRole()) {
BrowserAccessibility* table = GetParent();
@@ -3325,44 +3397,6 @@ void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() {
}
}
- // Expose invalid state for form controls and elements with aria-invalid.
- int invalid_state;
- if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE, &invalid_state)) {
- // TODO(nektar): Handle the possibility of having multiple aria-invalid
- // attributes defined, e.g., "invalid:spelling,grammar".
- switch (invalid_state) {
- case ui::AX_INVALID_STATE_FALSE:
- win_attributes_->ia2_attributes.push_back(L"invalid:false");
- break;
- case ui::AX_INVALID_STATE_TRUE:
- win_attributes_->ia2_attributes.push_back(L"invalid:true");
- break;
- case ui::AX_INVALID_STATE_SPELLING:
- win_attributes_->ia2_attributes.push_back(L"invalid:spelling");
- break;
- case ui::AX_INVALID_STATE_GRAMMAR:
- win_attributes_->ia2_attributes.push_back(L"invalid:grammar");
- break;
- case ui::AX_INVALID_STATE_OTHER:
- {
- base::string16 aria_invalid_value;
- if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE,
- &aria_invalid_value)) {
- SanitizeStringAttributeForIA2(aria_invalid_value,
- &aria_invalid_value);
- win_attributes_->ia2_attributes.push_back(
- L"invalid:" + aria_invalid_value);
- } else {
- // Set the attribute to L"true", since we cannot be more specific.
- win_attributes_->ia2_attributes.push_back(L"invalid:true");
- }
- }
- break;
- default:
- NOTREACHED();
- }
- }
-
// Expose row or column header sort direction.
int32_t sort_direction;
if ((ia_role() == ROLE_SYSTEM_COLUMNHEADER ||
@@ -3442,8 +3476,7 @@ void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() {
// the character index of each embedded object character to the id of the
// child object it points to.
for (unsigned int i = 0; i < PlatformChildCount(); ++i) {
- BrowserAccessibilityWin* child =
- PlatformGetChild(i)->ToBrowserAccessibilityWin();
+ const auto child = ToBrowserAccessibilityWin(PlatformGetChild(i));
DCHECK(child);
// Similar to Firefox, we don't expose text-only objects in IA2 hypertext.
if (child->IsTextOnlyObject()) {
@@ -3547,18 +3580,22 @@ void BrowserAccessibilityWin::UpdateStep3FireEvents(bool is_subtree_creation) {
// Changing a static text node can affect the IAccessibleText hypertext
// of the parent node, so force an update on the parent.
- BrowserAccessibilityWin* parent = GetParent()->ToBrowserAccessibilityWin();
+ BrowserAccessibilityWin* parent = ToBrowserAccessibilityWin(GetParent());
if (parent && IsTextOnlyObject() &&
name() != old_win_attributes_->name) {
- parent->UpdateStep1ComputeWinAttributes();
- parent->UpdateStep2ComputeHypertext();
- parent->UpdateStep3FireEvents(false);
+ parent->UpdatePlatformAttributes();
}
}
old_win_attributes_.reset(nullptr);
}
+void BrowserAccessibilityWin::UpdatePlatformAttributes() {
+ UpdateStep1ComputeWinAttributes();
+ UpdateStep2ComputeHypertext();
+ UpdateStep3FireEvents(false);
+}
+
void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() {
manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
EVENT_OBJECT_HIDE, this);
@@ -3581,6 +3618,182 @@ void BrowserAccessibilityWin::OnLocationChanged() {
EVENT_OBJECT_LOCATIONCHANGE, this);
}
+std::vector<base::string16> BrowserAccessibilityWin::ComputeTextAttributes()
+ const {
+ std::vector<base::string16> attributes;
+
+ // We include list markers for now, but there might be other objects that are
+ // auto generated.
+ // TODO(nektar): Compute what objects are auto-generated in Blink.
+ if (GetRole() == ui::AX_ROLE_LIST_MARKER)
+ attributes.push_back(L"auto-generated:true");
+ else
+ attributes.push_back(L"auto-generated:false");
+
+ int color;
+ base::string16 color_value(L"transparent");
+ if (GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR, &color)) {
+ unsigned int alpha = SkColorGetA(color);
+ unsigned int red = SkColorGetR(color);
+ unsigned int green = SkColorGetG(color);
+ unsigned int blue = SkColorGetB(color);
+ if (alpha) {
+ color_value = L"rgb(" + base::UintToString16(red) + L',' +
+ base::UintToString16(green) + L',' +
+ base::UintToString16(blue) + L')';
+ }
+ }
+ SanitizeStringAttributeForIA2(color_value, &color_value);
+ attributes.push_back(L"background-color:" + color_value);
+
+ if (GetIntAttribute(ui::AX_ATTR_COLOR, &color)) {
+ unsigned int red = SkColorGetR(color);
+ unsigned int green = SkColorGetG(color);
+ unsigned int blue = SkColorGetB(color);
+ color_value = L"rgb(" + base::UintToString16(red) + L',' +
+ base::UintToString16(green) + L',' +
+ base::UintToString16(blue) + L')';
+ } else {
+ color_value = L"rgb(0,0,0)";
+ }
+ SanitizeStringAttributeForIA2(color_value, &color_value);
+ attributes.push_back(L"color:" + color_value);
+
+ base::string16 font_family(
+ GetInheritedString16Attribute(ui::AX_ATTR_FONT_FAMILY));
+ // Attribute has no default value.
+ if (!font_family.empty()) {
+ SanitizeStringAttributeForIA2(font_family, &font_family);
+ attributes.push_back(L"font-family:" + font_family);
+ }
+
+ float font_size;
+ // Attribute has no default value.
+ if (GetFloatAttribute(ui::AX_ATTR_FONT_SIZE, &font_size)) {
+ // The IA2 Spec requires the value to be in pt, not in pixels.
+ // There are 72 points per inch.
+ // We assume that there are 96 pixels per inch on a standard display.
+ // TODO(nektar): Figure out the current value of pixels per inch.
+ float points = font_size * 72.0 / 96.0;
+ attributes.push_back(L"font-size:" +
+ base::UTF8ToUTF16(base::DoubleToString(points)) +
+ L"pt");
+ }
+
+ auto text_style =
+ static_cast<ui::AXTextStyle>(GetIntAttribute(ui::AX_ATTR_TEXT_STYLE));
+ if (text_style == ui::AX_TEXT_STYLE_NONE) {
+ attributes.push_back(L"font-style:normal");
+ attributes.push_back(L"font-weight:normal");
+ } else {
+ if (text_style & ui::AX_TEXT_STYLE_BOLD)
+ attributes.push_back(L"font-weight:bold");
+
+ base::string16 font_style;
+ if (text_style & ui::AX_TEXT_STYLE_ITALIC)
+ font_style += L",italic";
+ if (text_style & ui::AX_TEXT_STYLE_UNDERLINE)
+ font_style += L",underline";
+ if (text_style & ui::AX_TEXT_STYLE_LINE_THROUGH)
+ font_style += L",line-through";
+ // TODO(nektar): Support more font style attributes in Blink.
+
+ if (font_style.empty()) {
+ font_style = L"normal";
+ } else {
+ // Remove the leading comma.
+ font_style.erase(0, 1);
+ }
+ attributes.push_back(L"font-style:" + font_style);
+ }
+
+ auto invalid_state = static_cast<ui::AXInvalidState>(
+ GetIntAttribute(ui::AX_ATTR_INVALID_STATE));
+ switch (invalid_state) {
+ case ui::AX_INVALID_STATE_NONE:
+ case ui::AX_INVALID_STATE_FALSE:
+ attributes.push_back(L"invalid:false");
+ break;
+ case ui::AX_INVALID_STATE_TRUE:
+ attributes.push_back(L"invalid:true");
+ break;
+ case ui::AX_INVALID_STATE_SPELLING:
+ case ui::AX_INVALID_STATE_GRAMMAR: {
+ base::string16 spelling_grammar_value;
+ if (invalid_state & ui::AX_INVALID_STATE_SPELLING)
+ spelling_grammar_value = L"spelling";
+ else if (invalid_state & ui::AX_INVALID_STATE_GRAMMAR)
+ spelling_grammar_value = L"grammar";
+ else
+ spelling_grammar_value = L"spelling,grammar";
+ attributes.push_back(L"invalid:" + spelling_grammar_value);
+ break;
+ }
+ case ui::AX_INVALID_STATE_OTHER: {
+ base::string16 aria_invalid_value;
+ if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE,
+ &aria_invalid_value)) {
+ SanitizeStringAttributeForIA2(aria_invalid_value, &aria_invalid_value);
+ attributes.push_back(L"invalid:" + aria_invalid_value);
+ } else {
+ // Set the attribute to L"true", since we cannot be more specific.
+ attributes.push_back(L"invalid:true");
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ base::string16 language(GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE));
+ // Default value should be L"en-US".
+ if (language.empty()) {
+ attributes.push_back(L"language:en-US");
+ } else {
+ SanitizeStringAttributeForIA2(language, &language);
+ attributes.push_back(L"language:" + language);
+ }
+
+ // TODO(nektar): Add Blink support for the following attributes.
+ // Currently set to their default values as dictated by the IA2 Spec.
+ attributes.push_back(L"text-line-through-mode:continuous");
+ attributes.push_back(L"text-line-through-style:none");
+ // Default value must be the empty string.
+ attributes.push_back(L"text-line-through-text:");
+ attributes.push_back(L"text-line-through-type:none");
+ attributes.push_back(L"text-line-through-width:auto");
+ attributes.push_back(L"text-outline:false");
+ attributes.push_back(L"text-position:baseline");
+ attributes.push_back(L"text-shadow:none");
+ attributes.push_back(L"text-underline-mode:continuous");
+ attributes.push_back(L"text-underline-style:none");
+ attributes.push_back(L"text-underline-type:none");
+ attributes.push_back(L"text-underline-width:auto");
+
+ auto text_direction = static_cast<ui::AXTextDirection>(
+ GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION));
+ switch (text_direction) {
+ case ui::AX_TEXT_DIRECTION_NONE:
+ case ui::AX_TEXT_DIRECTION_LTR:
+ attributes.push_back(L"writing-mode:lr");
+ break;
+ case ui::AX_TEXT_DIRECTION_RTL:
+ attributes.push_back(L"writing-mode:rl");
+ break;
+ case ui::AX_TEXT_DIRECTION_TTB:
+ attributes.push_back(L"writing-mode:tb");
+ break;
+ case ui::AX_TEXT_DIRECTION_BTT:
+ // Not listed in the IA2 Spec.
+ attributes.push_back(L"writing-mode:bt");
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ return attributes;
+}
+
BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
AddRef();
return this;
@@ -3589,17 +3802,21 @@ BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID(
const VARIANT& var_id) {
if (var_id.vt != VT_I4)
- return NULL;
+ return nullptr;
LONG child_id = var_id.lVal;
if (child_id == CHILDID_SELF)
return this;
if (child_id >= 1 && child_id <= static_cast<LONG>(PlatformChildCount()))
- return PlatformGetChild(child_id - 1)->ToBrowserAccessibilityWin();
+ return ToBrowserAccessibilityWin(PlatformGetChild(child_id - 1));
- return manager()->ToBrowserAccessibilityManagerWin()->
- GetFromUniqueIdWin(child_id);
+ BrowserAccessibilityWin* child = ToBrowserAccessibilityWin(
+ BrowserAccessibility::GetFromUniqueID(-child_id));
+ if (child && child->IsDescendantOf(this))
+ return child;
+
+ return nullptr;
}
HRESULT BrowserAccessibilityWin::GetStringAttributeAsBstr(
@@ -3672,7 +3889,7 @@ bool BrowserAccessibilityWin::IsHyperlink() const {
const auto parent = GetParent();
if (parent) {
hyperlink_index =
- parent->ToBrowserAccessibilityWin()->GetHyperlinkIndexFromChild(*this);
+ ToBrowserAccessibilityWin(parent)->GetHyperlinkIndexFromChild(*this);
}
if (hyperlink_index >= 0)
@@ -3680,6 +3897,23 @@ bool BrowserAccessibilityWin::IsHyperlink() const {
return false;
}
+BrowserAccessibilityWin*
+BrowserAccessibilityWin::GetHyperlinkFromHypertextOffset(int offset) const {
+ std::map<int32_t, int32_t>::iterator iterator =
+ hyperlink_offset_to_index().find(offset);
+ if (iterator == hyperlink_offset_to_index().end())
+ return nullptr;
+
+ int32_t index = iterator->second;
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, static_cast<int32_t>(hyperlinks().size()));
+ int32_t id = hyperlinks()[index];
+ BrowserAccessibilityWin* hyperlink = GetFromID(id);
+ if (!hyperlink)
+ return nullptr;
+ return hyperlink;
+}
+
int32_t BrowserAccessibilityWin::GetHyperlinkIndexFromChild(
const BrowserAccessibilityWin& child) const {
if (hyperlinks().empty())
@@ -3719,7 +3953,7 @@ int32_t BrowserAccessibilityWin::GetHypertextOffsetFromChild(
DCHECK_LT(index_in_parent, static_cast<int32_t>(InternalChildCount()));
for (uint32_t i = 0; i < static_cast<uint32_t>(index_in_parent); ++i) {
const BrowserAccessibilityWin* sibling =
- InternalGetChild(i)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(InternalGetChild(i));
DCHECK(sibling);
if (sibling->IsTextOnlyObject())
hypertextOffset += sibling->GetText().size();
@@ -3738,11 +3972,11 @@ int32_t BrowserAccessibilityWin::GetHypertextOffsetFromChild(
int32_t BrowserAccessibilityWin::GetHypertextOffsetFromDescendant(
const BrowserAccessibilityWin& descendant) const {
- auto parent_object = descendant.GetParent()->ToBrowserAccessibilityWin();
+ auto parent_object = ToBrowserAccessibilityWin(descendant.GetParent());
auto current_object = const_cast<BrowserAccessibilityWin*>(&descendant);
while (parent_object && parent_object != this) {
current_object = parent_object;
- parent_object = current_object->GetParent()->ToBrowserAccessibilityWin();
+ parent_object = ToBrowserAccessibilityWin(current_object->GetParent());
}
if (!parent_object)
return -1;
@@ -3823,8 +4057,7 @@ int BrowserAccessibilityWin::GetHypertextOffsetFromEndpoint(
int BrowserAccessibilityWin::GetSelectionAnchor() const {
int32_t anchor_id = manager()->GetTreeData().sel_anchor_object_id;
- const auto anchor_object =
- manager()->GetFromID(anchor_id)->ToBrowserAccessibilityWin();
+ const BrowserAccessibilityWin* anchor_object = GetFromID(anchor_id);
if (!anchor_object)
return -1;
@@ -3834,8 +4067,7 @@ int BrowserAccessibilityWin::GetSelectionAnchor() const {
int BrowserAccessibilityWin::GetSelectionFocus() const {
int32_t focus_id = manager()->GetTreeData().sel_focus_object_id;
- const auto focus_object =
- manager()->GetFromID(focus_id)->ToBrowserAccessibilityWin();
+ const BrowserAccessibilityWin* focus_object = GetFromID(focus_id);
if (!focus_object)
return -1;
@@ -3847,8 +4079,7 @@ void BrowserAccessibilityWin::GetSelectionOffsets(
int* selection_start, int* selection_end) const {
DCHECK(selection_start && selection_end);
- if (HasState(ui::AX_STATE_EDITABLE) &&
- !HasState(ui::AX_STATE_RICHLY_EDITABLE) &&
+ if (IsSimpleTextControl() &&
GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, selection_start) &&
GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, selection_end)) {
return;
@@ -3885,22 +4116,13 @@ void BrowserAccessibilityWin::GetSelectionOffsets(
// the selection.
int* largest_offset =
(*selection_start <= *selection_end) ? selection_end : selection_start;
- auto current_object = const_cast<BrowserAccessibilityWin*>(this);
- LONG hyperlink_index;
- HRESULT hr =
- current_object->get_hyperlinkIndex(*largest_offset, &hyperlink_index);
- if (hr != S_OK)
+ BrowserAccessibilityWin* hyperlink =
+ GetHyperlinkFromHypertextOffset(*largest_offset);
+ if (!hyperlink)
return;
- DCHECK_GE(hyperlink_index, 0);
- base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink;
- hr = current_object->get_hyperlink(hyperlink_index, hyperlink.Receive());
- DCHECK(SUCCEEDED(hr));
- base::win::ScopedComPtr<IAccessibleText> hyperlink_text;
- hr = hyperlink.QueryInterface(hyperlink_text.Receive());
- DCHECK(SUCCEEDED(hr));
LONG n_selections = 0;
- hr = hyperlink_text->get_nSelections(&n_selections);
+ HRESULT hr = hyperlink->get_nSelections(&n_selections);
DCHECK(SUCCEEDED(hr));
if (n_selections > 0)
++(*largest_offset);
@@ -4032,8 +4254,40 @@ LONG BrowserAccessibilityWin::FindBoundary(
text, line_breaks, boundary, start_offset, direction);
}
-BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) {
- return manager()->GetFromID(id)->ToBrowserAccessibilityWin();
+LONG BrowserAccessibilityWin::FindStartOfStyle(
+ LONG start_offset,
+ ui::TextBoundaryDirection direction) const {
+ LONG text_length = static_cast<LONG>(GetText().length());
+ DCHECK_GE(start_offset, 0);
+ DCHECK_LE(start_offset, text_length);
+
+ switch (direction) {
+ case ui::BACKWARDS_DIRECTION: {
+ if (offset_to_text_attributes().empty())
+ return 0;
+
+ auto iterator = offset_to_text_attributes().upper_bound(start_offset);
+ --iterator;
+ return static_cast<LONG>(iterator->first);
+ }
+ case ui::FORWARDS_DIRECTION: {
+ const auto iterator =
+ offset_to_text_attributes().upper_bound(start_offset);
+ if (iterator == offset_to_text_attributes().end())
+ return text_length;
+ return static_cast<LONG>(iterator->first);
+ }
+ default:
+ NOTREACHED();
+ }
+
+ return start_offset;
+}
+
+BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) const {
+ if (!instance_active())
+ return nullptr;
+ return ToBrowserAccessibilityWin(manager()->GetFromID(id));
}
bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
@@ -4056,6 +4310,25 @@ bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
return false;
}
+void BrowserAccessibilityWin::AddRelations(
+ ui::AXIntListAttribute src_attr,
+ const base::string16& iaccessiblerelation_type) {
+ if (!HasIntListAttribute(src_attr))
+ return;
+
+ const std::vector<int32_t>& ids = GetIntListAttribute(src_attr);
+ for (size_t i = 0; i < ids.size(); ++i) {
+ CComObject<BrowserAccessibilityRelation>* relation;
+ HRESULT hr =
+ CComObject<BrowserAccessibilityRelation>::CreateInstance(&relation);
+ DCHECK(SUCCEEDED(hr));
+ relation->AddRef();
+ relation->Initialize(this, iaccessiblerelation_type);
+ relation->AddTarget(ids[i]);
+ relations_.push_back(relation);
+ }
+}
+
void BrowserAccessibilityWin::UpdateRequiredAttributes() {
// Expose slider value.
if (ia_role() == ROLE_SYSTEM_PROGRESSBAR ||
@@ -4119,25 +4392,6 @@ void BrowserAccessibilityWin::UpdateRequiredAttributes() {
}
}
-void BrowserAccessibilityWin::AddRelations(
- ui::AXIntListAttribute src_attr,
- const base::string16& iaccessiblerelation_type) {
- if (!HasIntListAttribute(src_attr))
- return;
-
- const std::vector<int32_t>& ids = GetIntListAttribute(src_attr);
- for (size_t i = 0; i < ids.size(); ++i) {
- CComObject<BrowserAccessibilityRelation>* relation;
- HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
- &relation);
- DCHECK(SUCCEEDED(hr));
- relation->AddRef();
- relation->Initialize(this, iaccessiblerelation_type);
- relation->AddTarget(ids[i]);
- relations_.push_back(relation);
- }
-}
-
void BrowserAccessibilityWin::InitRoleAndState() {
int32_t ia_role = 0;
int32_t ia_state = 0;
@@ -4332,8 +4586,15 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_state |= STATE_SYSTEM_FOCUSABLE;
break;
case ui::AX_ROLE_EMBEDDED_OBJECT:
- ia_role = ROLE_SYSTEM_CLIENT;
- ia2_role = IA2_ROLE_EMBEDDED_OBJECT;
+ if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) {
+ // Windows screen readers assume that IA2_ROLE_EMBEDDED_OBJECT
+ // doesn't have any children, but it may be something like a
+ // browser plugin that has a document inside.
+ ia_role = ROLE_SYSTEM_GROUPING;
+ } else {
+ ia_role = ROLE_SYSTEM_CLIENT;
+ ia2_role = IA2_ROLE_EMBEDDED_OBJECT;
+ }
break;
case ui::AX_ROLE_FIGCAPTION:
role_name = html_tag;
@@ -4420,8 +4681,6 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role = ROLE_SYSTEM_LISTITEM;
if (ia_state & STATE_SYSTEM_SELECTABLE) {
ia_state |= STATE_SYSTEM_FOCUSABLE;
- if (HasState(ui::AX_STATE_FOCUSED))
- ia_state |= STATE_SYSTEM_FOCUSED;
}
break;
case ui::AX_ROLE_LIST_ITEM:
@@ -4470,8 +4729,6 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia2_state &= ~(IA2_STATE_EDITABLE);
if (ia_state & STATE_SYSTEM_SELECTABLE) {
ia_state |= STATE_SYSTEM_FOCUSABLE;
- if (HasState(ui::AX_STATE_FOCUSED))
- ia_state |= STATE_SYSTEM_FOCUSED;
}
break;
case ui::AX_ROLE_METER:
@@ -4616,6 +4873,7 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia2_state |= IA2_STATE_SINGLE_LINE;
ia2_state |= IA2_STATE_SELECTABLE_TEXT;
break;
+ case ui::AX_ROLE_ABBR:
case ui::AX_ROLE_TIME:
role_name = html_tag;
ia_role = ROLE_SYSTEM_TEXT;
@@ -4691,4 +4949,15 @@ void BrowserAccessibilityWin::InitRoleAndState() {
win_attributes_->ia2_state = ia2_state;
}
+BrowserAccessibilityWin* ToBrowserAccessibilityWin(BrowserAccessibility* obj) {
+ DCHECK(!obj || obj->IsNative());
+ return static_cast<BrowserAccessibilityWin*>(obj);
+}
+
+const BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(const BrowserAccessibility* obj) {
+ DCHECK(!obj || obj->IsNative());
+ return static_cast<const BrowserAccessibilityWin*>(obj);
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.h b/chromium/content/browser/accessibility/browser_accessibility_win.h
index adeb16b494b..0a4648379af 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.h
@@ -97,17 +97,17 @@ BrowserAccessibilityWin
CONTENT_EXPORT ~BrowserAccessibilityWin() override;
- // The Windows-specific unique ID, used as the child ID for MSAA methods
- // like NotifyWinEvent, and as the unique ID for IAccessible2 and ISimpleDOM.
- LONG unique_id_win() const { return unique_id_win_; }
-
// Called after an atomic tree update completes. See
// BrowserAccessibilityManagerWin::OnAtomicUpdateFinished for more
// details on what these do.
CONTENT_EXPORT void UpdateStep1ComputeWinAttributes();
CONTENT_EXPORT void UpdateStep2ComputeHypertext();
CONTENT_EXPORT void UpdateStep3FireEvents(bool is_subtree_creation);
- CONTENT_EXPORT void UpdateStep4DeleteOldWinAttributes();
+
+ // This is used to call UpdateStep1ComputeWinAttributes, ... above when
+ // a node needs to be updated for some other reason other than via
+ // OnAtomicUpdateFinished.
+ CONTENT_EXPORT void UpdatePlatformAttributes() override;
//
// BrowserAccessibility methods.
@@ -713,6 +713,10 @@ BrowserAccessibilityWin
REFIID iid,
void** object);
+ // Computes and caches the IA2 text style attributes for the text and other
+ // embedded child objects.
+ CONTENT_EXPORT void ComputeStylesIfNeeded();
+
CONTENT_EXPORT base::string16 GetText() const override;
// Accessors.
@@ -727,6 +731,10 @@ BrowserAccessibilityWin
base::string16 name() const { return win_attributes_->name; }
base::string16 description() const { return win_attributes_->description; }
base::string16 value() const { return win_attributes_->value; }
+ const std::map<int, std::vector<base::string16>>& offset_to_text_attributes()
+ const {
+ return win_attributes_->offset_to_text_attributes;
+ }
std::map<int32_t, int32_t>& hyperlink_offset_to_index() const {
return win_attributes_->hyperlink_offset_to_index;
}
@@ -735,6 +743,9 @@ BrowserAccessibilityWin
}
private:
+ // Returns the IA2 text attributes for this object.
+ std::vector<base::string16> ComputeTextAttributes() const;
+
// Add one to the reference count and return the same object. Always
// use this method when returning a BrowserAccessibilityWin object as
// an output parameter to a COM interface, never use it otherwise.
@@ -790,6 +801,9 @@ BrowserAccessibilityWin
// Returns true if the current object is an IA2 hyperlink.
bool IsHyperlink() const;
+ // Returns the hyperlink at the given text position, or nullptr if no
+ // hyperlink can be found.
+ BrowserAccessibilityWin* GetHyperlinkFromHypertextOffset(int offset) const;
// Functions for retrieving offsets for hyperlinks and hypertext.
// Return -1 in case of failure.
@@ -851,26 +865,31 @@ BrowserAccessibilityWin
LONG start_offset,
ui::TextBoundaryDirection direction);
- // Return a pointer to the object corresponding to the given id,
- // does not make a new reference.
- BrowserAccessibilityWin* GetFromID(int32_t id);
+ // Searches forward from the given offset until the start of the next style
+ // is found, or searches backward from the given offset until the start of the
+ // current style is found.
+ LONG FindStartOfStyle(LONG start_offset,
+ ui::TextBoundaryDirection direction) const;
+
+ // ID refers to the node ID in the current tree, not the globally unique ID.
+ // TODO(nektar): Could we use globally unique IDs everywhere?
+ // TODO(nektar): Rename this function to GetFromNodeID.
+ BrowserAccessibilityWin* GetFromID(int32_t id) const;
// Returns true if this is a list box option with a parent of type list box,
// or a menu list option with a parent of type menu list popup.
bool IsListBoxOptionOrMenuListOption();
- // Updates object attributes of IA2 with html attributes.
- void UpdateRequiredAttributes();
-
// Given an int list attribute containing the ids of related elements,
// add a new IAccessibleRelation for this object with the given type name.
void AddRelations(ui::AXIntListAttribute src_attr,
const base::string16& iaccessiblerelation_type);
- // Windows-specific unique ID (unique within the browser process),
- // used for get_accChild, NotifyWinEvent, and as the unique ID for
- // IAccessible2 and ISimpleDOM.
- LONG unique_id_win_;
+ // Updates object attributes of IA2 with html attributes.
+ void UpdateRequiredAttributes();
+
+ // Updates the IA2 text style attributes.
+ void UpdateTextAttributes();
struct WinAttributes {
WinAttributes();
@@ -896,6 +915,9 @@ BrowserAccessibilityWin
// Hypertext.
base::string16 hypertext;
+ // Maps each style span to its start offset in hypertext.
+ std::map<int, std::vector<base::string16>> offset_to_text_attributes;
+
// Maps the |hypertext_| embedded character offset to an index in
// |hyperlinks_|.
std::map<int32_t, int32_t> hyperlink_offset_to_index;
@@ -918,9 +940,6 @@ BrowserAccessibilityWin
int previous_scroll_x_;
int previous_scroll_y_;
- // The next unique id to use.
- static LONG next_unique_id_win_;
-
// Give BrowserAccessibility::Create access to our constructor.
friend class BrowserAccessibility;
friend class BrowserAccessibilityRelation;
@@ -928,6 +947,12 @@ BrowserAccessibilityWin
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWin);
};
+CONTENT_EXPORT BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(BrowserAccessibility* obj);
+
+CONTENT_EXPORT const BrowserAccessibilityWin*
+ToBrowserAccessibilityWin(const BrowserAccessibility* obj);
+
} // namespace content
#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
index aac1961cb1d..e8c236a5195 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -161,8 +161,7 @@ TEST_F(BrowserAccessibilityTest, TestNoLeaks) {
MakeAXTreeUpdate(root, button, checkbox),
NULL, new CountedBrowserAccessibilityFactory()));
ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
- IAccessible* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ IAccessible* root_accessible = ToBrowserAccessibilityWin(manager->GetRoot());
IDispatch* root_iaccessible = NULL;
IDispatch* child1_iaccessible = NULL;
base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -215,7 +214,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) {
// value.
base::win::ScopedVariant one(1);
base::win::ScopedComPtr<IDispatch> text_dispatch;
- HRESULT hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
+ HRESULT hr = ToBrowserAccessibilityWin(manager->GetRoot())->get_accChild(
one, text_dispatch.Receive());
ASSERT_EQ(S_OK, hr);
@@ -249,7 +248,7 @@ TEST_F(BrowserAccessibilityTest, TestChildrenChange) {
// Query for the text IAccessible and verify that it now returns "new text"
// as its value.
- hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
+ hr = ToBrowserAccessibilityWin(manager->GetRoot())->get_accChild(
one, text_dispatch.Receive());
ASSERT_EQ(S_OK, hr);
@@ -396,12 +395,12 @@ TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
BrowserAccessibilityWin* root_obj =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
ASSERT_NE(nullptr, root_obj);
ASSERT_EQ(1U, root_obj->PlatformChildCount());
BrowserAccessibilityWin* text_field_obj =
- root_obj->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_obj->PlatformGetChild(0));
ASSERT_NE(nullptr, text_field_obj);
long text_len;
@@ -516,7 +515,7 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
BrowserAccessibilityWin* root_obj =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
long text_len;
EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
@@ -637,7 +636,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
ASSERT_EQ(9, CountedBrowserAccessibility::num_instances());
BrowserAccessibilityWin* root_obj =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
long text_len;
EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
@@ -821,8 +820,8 @@ TEST_F(BrowserAccessibilityTest, EmptyDocHasUniqueIdWin) {
1 << ui::AX_STATE_ENABLED,
root->GetState());
- LONG unique_id_win = root->ToBrowserAccessibilityWin()->unique_id_win();
- ASSERT_EQ(root, manager->GetFromUniqueIdWin(unique_id_win));
+ int32_t unique_id = ToBrowserAccessibilityWin(root)->unique_id();
+ ASSERT_EQ(root, BrowserAccessibility::GetFromUniqueID(unique_id));
}
TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
@@ -855,13 +854,13 @@ TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
- ASSERT_NE(nullptr, root_accessible);
- ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+ ToBrowserAccessibilityWin(manager->GetRoot());
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(2U, root_accessible->PlatformChildCount());
- BrowserAccessibilityWin* pseudo_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
- ASSERT_NE(nullptr, pseudo_accessible);
+ BrowserAccessibilityWin* pseudo_accessible =
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
+ ASSERT_NE(nullptr, pseudo_accessible);
base::win::ScopedBstr attributes;
HRESULT hr = pseudo_accessible->get_attributes(attributes.Receive());
@@ -871,7 +870,7 @@ TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
EXPECT_EQ(L"display:none;tag:<pseudo\\:before>;", attributes_str);
BrowserAccessibilityWin* checkbox_accessible =
- root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, checkbox_accessible);
attributes.Reset();
@@ -899,7 +898,7 @@ TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
combo_box.role = ui::AX_ROLE_COMBO_BOX;
combo_box_text.role = ui::AX_ROLE_STATIC_TEXT;
combo_box.state = (1 << ui::AX_STATE_EDITABLE) |
- (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED);
+ (1 << ui::AX_STATE_FOCUSABLE);
combo_box_text.state = 1 << ui::AX_STATE_EDITABLE;
combo_box.child_ids.push_back(combo_box_text.id);
@@ -914,8 +913,7 @@ TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
search_box_text.role = ui::AX_ROLE_STATIC_TEXT;
new_line.role = ui::AX_ROLE_LINE_BREAK;
search_box.state = (1 << ui::AX_STATE_EDITABLE) |
- (1 << ui::AX_STATE_FOCUSABLE) |
- (1 << ui::AX_STATE_FOCUSED);
+ (1 << ui::AX_STATE_FOCUSABLE);
search_box_text.state = new_line.state = 1 << ui::AX_STATE_EDITABLE;
search_box.child_ids.push_back(search_box_text.id);
search_box.child_ids.push_back(new_line.id);
@@ -943,7 +941,7 @@ TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
slider_text.SetName("Slider text");
slider.role = ui::AX_ROLE_SLIDER;
slider_text.role = ui::AX_ROLE_STATIC_TEXT;
- slider_text.state = 1 << ui::AX_STATE_READ_ONLY;
+ slider.state = slider_text.state = 1 << ui::AX_STATE_READ_ONLY;
slider.child_ids.push_back(slider_text.id);
root.child_ids.push_back(2); // Combo box.
@@ -963,27 +961,27 @@ TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(5U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* combo_box_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, combo_box_accessible);
- manager->SetFocus(combo_box_accessible, false /* notify */);
+ manager->SetFocusLocallyForTesting(combo_box_accessible);
ASSERT_EQ(combo_box_accessible,
- manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetFocus()));
BrowserAccessibilityWin* search_box_accessible =
- root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, search_box_accessible);
BrowserAccessibilityWin* text_field_accessible =
- root_accessible->PlatformGetChild(2)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(2));
ASSERT_NE(nullptr, text_field_accessible);
BrowserAccessibilityWin* link_accessible =
- root_accessible->PlatformGetChild(3)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(3));
ASSERT_NE(nullptr, link_accessible);
BrowserAccessibilityWin* slider_accessible =
- root_accessible->PlatformGetChild(4)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(4));
ASSERT_NE(nullptr, slider_accessible);
base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -1125,15 +1123,15 @@ TEST_F(BrowserAccessibilityTest, TestWordBoundariesInTextControls) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(2U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* textarea_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, textarea_accessible);
BrowserAccessibilityWin* text_field_accessible =
- root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, text_field_accessible);
base::win::ScopedComPtr<IAccessibleText> textarea_object;
@@ -1196,7 +1194,7 @@ TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) {
combo_box.id = 2;
combo_box.role = ui::AX_ROLE_COMBO_BOX;
combo_box.state = (1 << ui::AX_STATE_EDITABLE) |
- (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED);
+ (1 << ui::AX_STATE_FOCUSABLE);
combo_box.SetValue("Test1");
// Place the caret between 't' and 'e'.
combo_box.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, 1);
@@ -1224,18 +1222,18 @@ TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
- ASSERT_NE(nullptr, root_accessible);
- ASSERT_EQ(2U, root_accessible->PlatformChildCount());
+ ToBrowserAccessibilityWin(manager->GetRoot());
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(2U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* combo_box_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, combo_box_accessible);
- manager->SetFocus(combo_box_accessible, false /* notify */);
+ manager->SetFocusLocallyForTesting(combo_box_accessible);
ASSERT_EQ(combo_box_accessible,
- manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetFocus()));
BrowserAccessibilityWin* text_field_accessible =
- root_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, text_field_accessible);
// -2 is never a valid offset.
@@ -1254,11 +1252,9 @@ TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) {
EXPECT_EQ(2L, caret_offset);
// Move the focus to the text field.
- combo_box.state &= ~(1 << ui::AX_STATE_FOCUSED);
- text_field.state |= 1 << ui::AX_STATE_FOCUSED;
- manager->SetFocus(text_field_accessible, false /* notify */);
+ manager->SetFocusLocallyForTesting(text_field_accessible);
ASSERT_EQ(text_field_accessible,
- manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetFocus()));
// The caret should not have moved.
hr = text_field_accessible->get_caretOffset(&caret_offset);
@@ -1346,12 +1342,12 @@ TEST_F(BrowserAccessibilityTest, TestCaretInContentEditables) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
- ASSERT_NE(nullptr, root_accessible);
- ASSERT_EQ(1U, root_accessible->PlatformChildCount());
+ ToBrowserAccessibilityWin(manager->GetRoot());
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(1U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* div_editable_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, div_editable_accessible);
ASSERT_EQ(2U, div_editable_accessible->PlatformChildCount());
@@ -1370,21 +1366,20 @@ TEST_F(BrowserAccessibilityTest, TestCaretInContentEditables) {
EXPECT_EQ(6L, caret_offset);
// Move the focus to the content editable.
- div_editable.state |= 1 << ui::AX_STATE_FOCUSED;
- manager->SetFocus(div_editable_accessible, false /* notify */);
+ manager->SetFocusLocallyForTesting(div_editable_accessible);
ASSERT_EQ(div_editable_accessible,
- manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetFocus()));
BrowserAccessibilityWin* text_accessible =
- div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, text_accessible);
BrowserAccessibilityWin* link_accessible =
- div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, link_accessible);
ASSERT_EQ(1U, link_accessible->PlatformChildCount());
BrowserAccessibilityWin* link_text_accessible =
- link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(link_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, link_text_accessible);
// The caret should not have moved.
@@ -1465,12 +1460,12 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
- ASSERT_NE(nullptr, root_accessible);
- ASSERT_EQ(1U, root_accessible->PlatformChildCount());
+ ToBrowserAccessibilityWin(manager->GetRoot());
+ ASSERT_NE(nullptr, root_accessible);
+ ASSERT_EQ(1U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* div_editable_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, div_editable_accessible);
ASSERT_EQ(2U, div_editable_accessible->PlatformChildCount());
@@ -1481,15 +1476,15 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) {
LONG selection_end = -2;
BrowserAccessibilityWin* text_accessible =
- div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, text_accessible);
BrowserAccessibilityWin* link_accessible =
- div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_editable_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, link_accessible);
ASSERT_EQ(1U, link_accessible->PlatformChildCount());
BrowserAccessibilityWin* link_text_accessible =
- link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(link_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, link_text_accessible);
// get_nSelections should work on all objects.
@@ -1537,10 +1532,9 @@ TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) {
EXPECT_EQ(7L, caret_offset);
// Move the focus to the content editable.
- div_editable.state |= 1 << ui::AX_STATE_FOCUSED;
- manager->SetFocus(div_editable_accessible, false /* notify */);
+ manager->SetFocusLocallyForTesting(div_editable_accessible);
ASSERT_EQ(div_editable_accessible,
- manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetFocus()));
// The caret should not have moved.
hr = div_editable_accessible->get_caretOffset(&caret_offset);
@@ -1602,20 +1596,20 @@ TEST_F(BrowserAccessibilityTest, TestIAccessibleHyperlink) {
ASSERT_NE(nullptr, manager->GetRoot());
BrowserAccessibilityWin* root_accessible =
- manager->GetRoot()->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(manager->GetRoot());
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(1U, root_accessible->PlatformChildCount());
BrowserAccessibilityWin* div_accessible =
- root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, div_accessible);
ASSERT_EQ(2U, div_accessible->PlatformChildCount());
BrowserAccessibilityWin* text_accessible =
- div_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_accessible->PlatformGetChild(0));
ASSERT_NE(nullptr, text_accessible);
BrowserAccessibilityWin* link_accessible =
- div_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin();
+ ToBrowserAccessibilityWin(div_accessible->PlatformGetChild(1));
ASSERT_NE(nullptr, link_accessible);
// -1 is never a valid value.
@@ -1720,25 +1714,29 @@ TEST_F(BrowserAccessibilityTest, TestIAccessibleHyperlink) {
EXPECT_EQ(7, end_index);
}
-TEST_F(BrowserAccessibilityTest, TestPlatformDeepestFirstLastChild) {
+TEST_F(BrowserAccessibilityTest, TestDeepestFirstLastChild) {
ui::AXNodeData root;
root.id = 1;
root.role = ui::AX_ROLE_ROOT_WEB_AREA;
ui::AXNodeData child1;
child1.id = 2;
+ child1.role = ui::AX_ROLE_STATIC_TEXT;
root.child_ids.push_back(2);
ui::AXNodeData child2;
child2.id = 3;
+ child2.role = ui::AX_ROLE_STATIC_TEXT;
root.child_ids.push_back(3);
ui::AXNodeData child2_child1;
child2_child1.id = 4;
+ child2_child1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
child2.child_ids.push_back(4);
ui::AXNodeData child2_child2;
child2_child2.id = 5;
+ child2_child2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
child2.child_ids.push_back(5);
scoped_ptr<BrowserAccessibilityManager> manager(
@@ -1746,32 +1744,168 @@ TEST_F(BrowserAccessibilityTest, TestPlatformDeepestFirstLastChild) {
MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
nullptr, new CountedBrowserAccessibilityFactory()));
- auto root_accessible = manager->GetRoot();
+ BrowserAccessibility* root_accessible = manager->GetRoot();
ASSERT_NE(nullptr, root_accessible);
ASSERT_EQ(2U, root_accessible->PlatformChildCount());
- auto child1_accessible = root_accessible->PlatformGetChild(0);
+ BrowserAccessibility* child1_accessible =
+ root_accessible->PlatformGetChild(0);
ASSERT_NE(nullptr, child1_accessible);
- auto child2_accessible = root_accessible->PlatformGetChild(1);
+ BrowserAccessibility* child2_accessible =
+ root_accessible->PlatformGetChild(1);
ASSERT_NE(nullptr, child2_accessible);
- ASSERT_EQ(2U, child2_accessible->PlatformChildCount());
- auto child2_child1_accessible = child2_accessible->PlatformGetChild(0);
+ ASSERT_EQ(0U, child2_accessible->PlatformChildCount());
+ ASSERT_EQ(2U, child2_accessible->InternalChildCount());
+ BrowserAccessibility* child2_child1_accessible =
+ child2_accessible->InternalGetChild(0);
ASSERT_NE(nullptr, child2_child1_accessible);
- auto child2_child2_accessible = child2_accessible->PlatformGetChild(1);
+ BrowserAccessibility* child2_child2_accessible =
+ child2_accessible->InternalGetChild(1);
ASSERT_NE(nullptr, child2_child2_accessible);
EXPECT_EQ(child1_accessible, root_accessible->PlatformDeepestFirstChild());
+ EXPECT_EQ(child1_accessible, root_accessible->InternalDeepestFirstChild());
+
+ EXPECT_EQ(child2_accessible, root_accessible->PlatformDeepestLastChild());
EXPECT_EQ(child2_child2_accessible,
- root_accessible->PlatformDeepestLastChild());
+ root_accessible->InternalDeepestLastChild());
+
EXPECT_EQ(nullptr, child1_accessible->PlatformDeepestFirstChild());
+ EXPECT_EQ(nullptr, child1_accessible->InternalDeepestFirstChild());
+
EXPECT_EQ(nullptr, child1_accessible->PlatformDeepestLastChild());
+ EXPECT_EQ(nullptr, child1_accessible->InternalDeepestLastChild());
+
+ EXPECT_EQ(nullptr, child2_accessible->PlatformDeepestFirstChild());
EXPECT_EQ(child2_child1_accessible,
- child2_accessible->PlatformDeepestFirstChild());
+ child2_accessible->InternalDeepestFirstChild());
+
+ EXPECT_EQ(nullptr, child2_accessible->PlatformDeepestLastChild());
EXPECT_EQ(child2_child2_accessible,
- child2_accessible->PlatformDeepestLastChild());
+ child2_accessible->InternalDeepestLastChild());
+
EXPECT_EQ(nullptr, child2_child1_accessible->PlatformDeepestFirstChild());
+ EXPECT_EQ(nullptr, child2_child1_accessible->InternalDeepestFirstChild());
EXPECT_EQ(nullptr, child2_child1_accessible->PlatformDeepestLastChild());
+ EXPECT_EQ(nullptr, child2_child1_accessible->InternalDeepestLastChild());
EXPECT_EQ(nullptr, child2_child2_accessible->PlatformDeepestFirstChild());
+ EXPECT_EQ(nullptr, child2_child2_accessible->InternalDeepestFirstChild());
EXPECT_EQ(nullptr, child2_child2_accessible->PlatformDeepestLastChild());
+ EXPECT_EQ(nullptr, child2_child2_accessible->InternalDeepestLastChild());
+}
+
+TEST_F(BrowserAccessibilityTest, TestInheritedStringAttributes) {
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+ root.AddStringAttribute(ui::AX_ATTR_LANGUAGE, "en-US");
+ root.AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, "Helvetica");
+
+ ui::AXNodeData child1;
+ child1.id = 2;
+ child1.role = ui::AX_ROLE_STATIC_TEXT;
+ root.child_ids.push_back(2);
+
+ ui::AXNodeData child2;
+ child2.id = 3;
+ child2.role = ui::AX_ROLE_STATIC_TEXT;
+ child2.AddStringAttribute(ui::AX_ATTR_LANGUAGE, "fr");
+ child2.AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, "Arial");
+ root.child_ids.push_back(3);
+
+ ui::AXNodeData child2_child1;
+ child2_child1.id = 4;
+ child2_child1.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ child2.child_ids.push_back(4);
+
+ ui::AXNodeData child2_child2;
+ child2_child2.id = 5;
+ child2_child2.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+ child2.child_ids.push_back(5);
+
+ scoped_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(
+ MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
+ nullptr, new CountedBrowserAccessibilityFactory()));
+
+ BrowserAccessibility* root_accessible = manager->GetRoot();
+ ASSERT_NE(nullptr, root_accessible);
+ BrowserAccessibility* child1_accessible =
+ root_accessible->PlatformGetChild(0);
+ ASSERT_NE(nullptr, child1_accessible);
+ BrowserAccessibility* child2_accessible =
+ root_accessible->PlatformGetChild(1);
+ ASSERT_NE(nullptr, child2_accessible);
+ BrowserAccessibility* child2_child1_accessible =
+ child2_accessible->InternalGetChild(0);
+ ASSERT_NE(nullptr, child2_child1_accessible);
+ BrowserAccessibility* child2_child2_accessible =
+ child2_accessible->InternalGetChild(1);
+ ASSERT_NE(nullptr, child2_child2_accessible);
+
+ // Test GetInheritedString16Attribute(attribute).
+ EXPECT_EQ(
+ base::UTF8ToUTF16("en-US"),
+ root_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE));
+ EXPECT_EQ(
+ base::UTF8ToUTF16("en-US"),
+ child1_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE));
+ EXPECT_EQ(
+ base::UTF8ToUTF16("fr"),
+ child2_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE));
+ EXPECT_EQ(base::UTF8ToUTF16("fr"),
+ child2_child1_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE));
+ EXPECT_EQ(base::UTF8ToUTF16("fr"),
+ child2_child2_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE));
+
+ // Test GetInheritedString16Attribute(attribute, out_value).
+ base::string16 value16;
+ EXPECT_TRUE(root_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE, &value16));
+ EXPECT_EQ(base::UTF8ToUTF16("en-US"), value16);
+ EXPECT_TRUE(child1_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE, &value16));
+ EXPECT_EQ(base::UTF8ToUTF16("en-US"), value16);
+ EXPECT_TRUE(child2_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE, &value16));
+ EXPECT_EQ(base::UTF8ToUTF16("fr"), value16);
+ EXPECT_TRUE(child2_child1_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE, &value16));
+ EXPECT_EQ(base::UTF8ToUTF16("fr"), value16);
+ EXPECT_TRUE(child2_child2_accessible->GetInheritedString16Attribute(
+ ui::AX_ATTR_LANGUAGE, &value16));
+ EXPECT_EQ(base::UTF8ToUTF16("fr"), value16);
+
+ // Test GetInheritedStringAttribute(attribute).
+ EXPECT_EQ("Helvetica", root_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY));
+ EXPECT_EQ("Helvetica", child1_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY));
+ EXPECT_EQ("Arial", child2_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY));
+ EXPECT_EQ("Arial", child2_child1_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY));
+ EXPECT_EQ("Arial", child2_child2_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY));
+
+ // Test GetInheritedStringAttribute(attribute, out_value).
+ std::string value;
+ EXPECT_TRUE(root_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY, &value));
+ EXPECT_EQ("Helvetica", value);
+ EXPECT_TRUE(child1_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY, &value));
+ EXPECT_EQ("Helvetica", value);
+ EXPECT_TRUE(child2_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY, &value));
+ EXPECT_EQ("Arial", value);
+ EXPECT_TRUE(child2_child1_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY, &value));
+ EXPECT_EQ("Arial", value);
+ EXPECT_TRUE(child2_child2_accessible->GetInheritedStringAttribute(
+ ui::AX_ATTR_FONT_FAMILY, &value));
+ EXPECT_EQ("Arial", value);
}
TEST_F(BrowserAccessibilityTest, TestSanitizeStringAttributeForIA2) {
@@ -1797,9 +1931,9 @@ TEST_F(BrowserAccessibilityTest, UniqueIdWinInvalidAfterDeletingTree) {
new CountedBrowserAccessibilityFactory()));
BrowserAccessibility* root = manager->GetRoot();
- LONG root_unique_id = root->ToBrowserAccessibilityWin()->unique_id_win();
+ int32_t root_unique_id = root->unique_id();
BrowserAccessibility* child = root->PlatformGetChild(0);
- LONG child_unique_id = child->ToBrowserAccessibilityWin()->unique_id_win();
+ int32_t child_unique_id = child->unique_id();
// Now destroy that original tree and create a new tree.
manager.reset(
@@ -1808,39 +1942,67 @@ TEST_F(BrowserAccessibilityTest, UniqueIdWinInvalidAfterDeletingTree) {
nullptr,
new CountedBrowserAccessibilityFactory()));
root = manager->GetRoot();
- LONG root_unique_id_2 = root->ToBrowserAccessibilityWin()->unique_id_win();
+ int32_t root_unique_id_2 = root->unique_id();
child = root->PlatformGetChild(0);
- LONG child_unique_id_2 = child->ToBrowserAccessibilityWin()->unique_id_win();
+ int32_t child_unique_id_2 = child->unique_id();
// The nodes in the new tree should not have the same ids.
EXPECT_NE(root_unique_id, root_unique_id_2);
EXPECT_NE(child_unique_id, child_unique_id_2);
// Trying to access the unique IDs of the old, deleted objects should fail.
- base::win::ScopedVariant old_root_variant(root_unique_id);
+ base::win::ScopedVariant old_root_variant(-root_unique_id);
base::win::ScopedComPtr<IDispatch> old_root_dispatch;
- HRESULT hr = root->ToBrowserAccessibilityWin()->get_accChild(
+ HRESULT hr = ToBrowserAccessibilityWin(root)->get_accChild(
old_root_variant, old_root_dispatch.Receive());
EXPECT_EQ(E_INVALIDARG, hr);
- base::win::ScopedVariant old_child_variant(child_unique_id);
+ base::win::ScopedVariant old_child_variant(-child_unique_id);
base::win::ScopedComPtr<IDispatch> old_child_dispatch;
- hr = root->ToBrowserAccessibilityWin()->get_accChild(
+ hr = ToBrowserAccessibilityWin(root)->get_accChild(
old_child_variant, old_child_dispatch.Receive());
EXPECT_EQ(E_INVALIDARG, hr);
// Trying to access the unique IDs of the new objects should succeed.
- base::win::ScopedVariant new_root_variant(root_unique_id_2);
+ base::win::ScopedVariant new_root_variant(-root_unique_id_2);
base::win::ScopedComPtr<IDispatch> new_root_dispatch;
- hr = root->ToBrowserAccessibilityWin()->get_accChild(
+ hr = ToBrowserAccessibilityWin(root)->get_accChild(
new_root_variant, new_root_dispatch.Receive());
EXPECT_EQ(S_OK, hr);
- base::win::ScopedVariant new_child_variant(child_unique_id_2);
+ base::win::ScopedVariant new_child_variant(-child_unique_id_2);
base::win::ScopedComPtr<IDispatch> new_child_dispatch;
- hr = root->ToBrowserAccessibilityWin()->get_accChild(
+ hr = ToBrowserAccessibilityWin(root)->get_accChild(
new_child_variant, new_child_dispatch.Receive());
EXPECT_EQ(S_OK, hr);
}
+TEST_F(BrowserAccessibilityTest, AccChildOnlyReturnsDescendants) {
+ ui::AXNodeData root_node;
+ root_node.id = 1;
+ root_node.role = ui::AX_ROLE_ROOT_WEB_AREA;
+
+ ui::AXNodeData child_node;
+ child_node.id = 2;
+ root_node.child_ids.push_back(2);
+
+ scoped_ptr<BrowserAccessibilityManagerWin> manager(
+ new BrowserAccessibilityManagerWin(
+ MakeAXTreeUpdate(root_node, child_node),
+ nullptr,
+ new CountedBrowserAccessibilityFactory()));
+
+ BrowserAccessibility* root = manager->GetRoot();
+ BrowserAccessibility* child = root->PlatformGetChild(0);
+
+ base::win::ScopedVariant root_unique_id_variant(-root->unique_id());
+ base::win::ScopedComPtr<IDispatch> result;
+ EXPECT_EQ(E_INVALIDARG, ToBrowserAccessibilityWin(child)->get_accChild(
+ root_unique_id_variant, result.Receive()));
+
+ base::win::ScopedVariant child_unique_id_variant(-child->unique_id());
+ EXPECT_EQ(S_OK, ToBrowserAccessibilityWin(root)->get_accChild(
+ child_unique_id_variant, result.Receive()));
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index b5dd3296ef3..986fdc063bd 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -15,21 +15,28 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/accessibility/accessibility_tree_formatter.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.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 "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/accessibility_browser_test_utils.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
namespace content {
@@ -40,6 +47,29 @@ const char kMarkSkipFile[] = "#<skip";
const char kMarkEndOfFile[] = "<-- End-of-file -->";
const char kSignalDiff[] = "*";
+// Searches recursively and returns true if an accessibility node is found
+// that represents a fully loaded web document with the given url.
+bool AccessibilityTreeContainsLoadedDocWithUrl(BrowserAccessibility* node,
+ const std::string& url) {
+ if ((node->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) &&
+ node->GetStringAttribute(ui::AX_ATTR_URL) == url) {
+ // If possible, ensure the doc has finished loading. That's currently
+ // not possible with same-process iframes until https://crbug.com/532249
+ // is fixed.
+ return (node->manager()->GetTreeData().url != url ||
+ node->manager()->GetTreeData().loaded);
+ }
+
+ for (unsigned i = 0; i < node->PlatformChildCount(); i++) {
+ if (AccessibilityTreeContainsLoadedDocWithUrl(
+ node->PlatformGetChild(i), url)) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
typedef AccessibilityTreeFormatter::Filter Filter;
@@ -50,6 +80,17 @@ DumpAccessibilityTestBase::DumpAccessibilityTestBase() {
DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {
}
+void DumpAccessibilityTestBase::SetUpCommandLine(
+ base::CommandLine* command_line) {
+ IsolateAllSitesForTesting(command_line);
+}
+
+void DumpAccessibilityTestBase::SetUpOnMainThread() {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ SetupCrossSiteRedirector(embedded_test_server());
+}
+
base::string16
DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() {
scoped_ptr<AccessibilityTreeFormatter> formatter(
@@ -95,7 +136,7 @@ std::vector<int> DumpAccessibilityTestBase::DiffLines(
void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives(
const std::string& test_html,
std::vector<Filter>* filters,
- std::string* wait_for) {
+ std::vector<std::string>* wait_for) {
for (const std::string& line :
base::SplitString(test_html, "\n", base::TRIM_WHITESPACE,
base::SPLIT_WANT_ALL)) {
@@ -120,7 +161,7 @@ void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives(
Filter::DENY));
} else if (base::StartsWith(line, wait_str,
base::CompareCase::SENSITIVE)) {
- *wait_for = line.substr(wait_str.size());
+ wait_for->push_back(line.substr(wait_str.size()));
}
}
}
@@ -193,42 +234,109 @@ void DumpAccessibilityTestBase::RunTestForPlatform(
}
// Parse filters and other directives in the test file.
- std::string wait_for;
+ std::vector<std::string> wait_for;
AddDefaultFilters(&filters_);
ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for);
- // Load the page.
- base::string16 html_contents16;
- html_contents16 = base::UTF8ToUTF16(html_contents);
- GURL url = GetTestUrl(file_dir, file_path.BaseName().MaybeAsASCII().c_str());
-
- // If there's a @WAIT-FOR directive, set up an accessibility notification
- // waiter that returns on any event; we'll stop when we get the text we're
- // waiting for, or time out. Otherwise just wait specifically for
- // the "load complete" event.
- scoped_ptr<AccessibilityNotificationWaiter> waiter;
- if (!wait_for.empty()) {
- waiter.reset(new AccessibilityNotificationWaiter(
- shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE));
- } else {
- waiter.reset(new AccessibilityNotificationWaiter(
- shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE));
+ // Load the test html and wait for the "load complete" AX event.
+ GURL url(embedded_test_server()->GetURL(
+ "/" + std::string(file_dir) + "/" + file_path.BaseName().MaybeAsASCII()));
+ AccessibilityNotificationWaiter accessibility_waiter(
+ shell(),
+ AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+ NavigateToURL(shell(), url);
+ accessibility_waiter.WaitForNotification();
+
+ // Get the url of every frame in the frame tree.
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ shell()->web_contents());
+ FrameTree* frame_tree = web_contents->GetFrameTree();
+ std::vector<std::string> all_frame_urls;
+ for (FrameTreeNode* node : frame_tree->Nodes()) {
+ // Ignore about:blank urls because of the case where a parent frame A
+ // has a child iframe B and it writes to the document using
+ // contentDocument.open() on the child frame B.
+ //
+ // In this scenario, B's contentWindow.location.href matches A's url,
+ // but B's url in the browser frame tree is still "about:blank".
+ std::string url = node->current_url().spec();
+ if (url != url::kAboutBlankURL)
+ all_frame_urls.push_back(url);
+
+ // We won't get the correct coordinate transformations for
+ // out-of-process iframes until each frame's surface is ready.
+ RenderFrameHostImpl* current_frame_host = node->current_frame_host();
+ if (!current_frame_host)
+ continue;
+ RenderWidgetHostImpl* rwh = current_frame_host->GetRenderWidgetHost();
+ if (!rwh)
+ continue;
+ RenderWidgetHostViewBase* rwhv = rwh->GetView();
+ if (rwhv && rwhv->IsChildFrameForTesting()) {
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv));
+ notifier.WaitForSurfaceReady();
+ }
}
- // Load the test html.
- NavigateToURL(shell(), url);
+ // Wait for the accessibility tree to fully load for all frames,
+ // by searching for the WEB_AREA node in the accessibility tree
+ // with the url of each frame in our frame tree. Note that this
+ // doesn't support cases where there are two iframes with the
+ // exact same url. If all frames haven't loaded yet, set up a
+ // listener for accessibility events on any frame and block
+ // until the next one is received.
+ //
+ // If the original page has a @WAIT-FOR directive, don't break until
+ // the text we're waiting for appears in the full text dump of the
+ // accessibility tree, either.
+ for (;;) {
+ VLOG(1) << "Top of loop";
+ RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+ web_contents->GetMainFrame());
+ BrowserAccessibilityManager* manager =
+ main_frame->browser_accessibility_manager();
+ if (manager) {
+ BrowserAccessibility* accessibility_root =
+ manager->GetRoot();
+
+ // Check to see if all frames have loaded.
+ bool all_frames_loaded = true;
+ for (const auto& url : all_frame_urls) {
+ if (!AccessibilityTreeContainsLoadedDocWithUrl(
+ accessibility_root, url)) {
+ VLOG(1) << "Still waiting on this frame to load: " << url;
+ all_frames_loaded = false;
+ break;
+ }
+ }
- // Wait for notifications. If there's a @WAIT-FOR directive, break when
- // the text we're waiting for appears in the dump, otherwise break after
- // the first notification, which will be a load complete.
- do {
- waiter->WaitForNotification();
- if (!wait_for.empty()) {
+ // Check to see if the @WAIT-FOR text has appeared yet.
+ bool all_wait_for_strings_found = true;
base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString();
- if (base::UTF16ToUTF8(tree_dump).find(wait_for) != std::string::npos)
- wait_for.clear();
+ for (const auto& str : wait_for) {
+ if (base::UTF16ToUTF8(tree_dump).find(str) == std::string::npos) {
+ VLOG(1) << "Still waiting on this text to be found: " << str;
+ all_wait_for_strings_found = false;
+ break;
+ }
+ }
+
+ // If all frames have loaded and the @WAIT-FOR text has appeared,
+ // we're done.
+ if (all_frames_loaded && all_wait_for_strings_found)
+ break;
}
- } while (!wait_for.empty());
+
+ // Block until the next accessibility notification in any frame.
+ VLOG(1) << "Waiting until the next accessibility event";
+ AccessibilityNotificationWaiter accessibility_waiter(main_frame,
+ ui::AX_EVENT_NONE);
+ for (FrameTreeNode* node : frame_tree->Nodes())
+ accessibility_waiter.ListenToAdditionalFrame(node->current_frame_host());
+ accessibility_waiter.WaitForNotification();
+ }
// Call the subclass to dump the output.
std::vector<std::string> actual_lines = Dump();
diff --git a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h
index 21ae32a1faf..5e93b9be562 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h
+++ b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -31,6 +31,9 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
void RunTest(const base::FilePath file_path, const char* file_dir);
protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override;
+ void SetUpOnMainThread() override;
+
//
// For subclasses to override:
//
@@ -79,11 +82,12 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
// until the given string (e.g., "text") appears in the resulting dump.
// A test can make some changes to the document, then append a magic string
// indicating that the test is done, and this framework will wait for that
- // string to appear before comparing the results.
+ // string to appear before comparing the results. There can be multiple
+ // @WAIT-FOR: directives.
void ParseHtmlForExtraDirectives(
const std::string& test_html,
std::vector<AccessibilityTreeFormatter::Filter>* filters,
- std::string* wait_for);
+ std::vector<std::string>* wait_for);
// Create the right AccessibilityTreeFormatter subclass.
AccessibilityTreeFormatter* CreateAccessibilityTreeFormatter();
diff --git a/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index e4d2fc46dd6..40d33366e90 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -202,8 +202,16 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("inner-html-change.html"));
}
+#if defined(OS_MACOSX)
+// Mac failures: http://crbug.com/598527.
+#define MAYBE_AccessibilityEventsInputTypeTextValueChanged \
+ DISABLED_AccessibilityEventsInputTypeTextValueChanged
+#else
+#define MAYBE_AccessibilityEventsInputTypeTextValueChanged \
+ AccessibilityEventsInputTypeTextValueChanged
+#endif
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
- AccessibilityEventsInputTypeTextValueChanged) {
+ MAYBE_AccessibilityEventsInputTypeTextValueChanged) {
RunEventTest(FILE_PATH_LITERAL("input-type-text-value-changed.html"));
}
@@ -213,18 +221,9 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
}
// Flaky on Windows: http://crbug.com/486861
-#if defined(OS_WIN)
-#define MAYBE_AccessibilityEventsListboxNext \
- DISABLED_AccessibilityEventsListboxNext
-#define MAYBE_AccessibilityEventsMenuListPopup \
- DISABLED_AccessibilityEventsMenuListPopup
-#else
-#define MAYBE_AccessibilityEventsListboxNext AccessibilityEventsListboxNext
-#define MAYBE_AccessibilityEventsMenuListPopup AccessibilityEventsMenuListPopup
-#endif
-
+// Flaky on Mac: http://crbug.com/588271
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
- MAYBE_AccessibilityEventsListboxNext) {
+ DISABLED_AccessibilityEventsListboxNext) {
RunEventTest(FILE_PATH_LITERAL("listbox-next.html"));
}
@@ -238,8 +237,9 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("menulist-next.html"));
}
+// Flaky on Windows: http://crbug.com/486861
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
- MAYBE_AccessibilityEventsMenuListPopup) {
+ DISABLED_AccessibilityEventsMenuListPopup) {
RunEventTest(FILE_PATH_LITERAL("menulist-popup.html"));
}
diff --git a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 9db7c77a84c..e1aa6a44d15 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -55,12 +55,14 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
void AddDefaultFilters(std::vector<Filter>* filters) override {
filters->push_back(Filter(base::ASCIIToUTF16("FOCUSABLE"), Filter::ALLOW));
filters->push_back(Filter(base::ASCIIToUTF16("READONLY"), Filter::ALLOW));
- filters->push_back(Filter(base::ASCIIToUTF16("name*"), Filter::ALLOW));
+ filters->push_back(Filter(base::ASCIIToUTF16("name=*"), Filter::ALLOW));
+ filters->push_back(Filter(base::ASCIIToUTF16("roleDescription=*"),
+ Filter::ALLOW));
filters->push_back(Filter(base::ASCIIToUTF16("*=''"), Filter::DENY));
}
void SetUpCommandLine(base::CommandLine* command_line) override {
- ContentBrowserTest::SetUpCommandLine(command_line);
+ DumpAccessibilityTestBase::SetUpCommandLine(command_line);
// Enable <dialog>, which is used in some tests.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
@@ -77,6 +79,17 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
RunTest(aria_file, "accessibility/aria");
}
+ void RunCSSTest(const base::FilePath::CharType* file_path) {
+ base::FilePath dir_test_data;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
+ base::FilePath test_path(
+ dir_test_data.AppendASCII("accessibility").AppendASCII("css"));
+ ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+
+ base::FilePath css_file = test_path.Append(base::FilePath(file_path));
+ RunTest(css_file, "accessibility/css");
+ }
+
void RunHtmlTest(const base::FilePath::CharType* file_path) {
base::FilePath dir_test_data;
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
@@ -105,6 +118,18 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
}
};
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSColor) {
+ RunCSSTest(FILE_PATH_LITERAL("color.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSFontStyle) {
+ RunCSSTest(FILE_PATH_LITERAL("font-style.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSLanguage) {
+ RunCSSTest(FILE_PATH_LITERAL("language.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) {
RunHtmlTest(FILE_PATH_LITERAL("a.html"));
}
@@ -113,6 +138,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAbbr) {
RunHtmlTest(FILE_PATH_LITERAL("abbr.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityActionVerbs) {
+ RunHtmlTest(FILE_PATH_LITERAL("action-verbs.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAddress) {
RunHtmlTest(FILE_PATH_LITERAL("address.html"));
}
@@ -554,7 +583,12 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTextbox) {
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaTextboxWithSelection) {
+ AccessibilityAriaTextboxWithRichText) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-textbox-with-rich-text.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaTextboxWithSelection) {
RunAriaTest(FILE_PATH_LITERAL("aria-textbox-with-selection.html"));
}
@@ -826,21 +860,59 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityIframe) {
RunHtmlTest(FILE_PATH_LITERAL("iframe.html"));
}
-// Flaky. See http://crbug.com/224659.
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- DISABLED_AccessibilityIframeCoordinates) {
+ AccessibilityIframeCrossProcess) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-cross-process.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeCoordinates) {
RunHtmlTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeCoordinatesCrossProcess) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-coordinates-cross-process.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityIframePresentational) {
RunHtmlTest(FILE_PATH_LITERAL("iframe-presentational.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeTransform) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-transform.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeTransformCrossProcess) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-cross-process.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeTransformNested) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-nested.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeTransformNestedCrossProcess) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-nested-cross-process.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityIframeTransformScrolled) {
+ RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-scrolled.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityImg) {
RunHtmlTest(FILE_PATH_LITERAL("img.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityImgEmptyAlt) {
+ RunHtmlTest(FILE_PATH_LITERAL("img-empty-alt.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
RunHtmlTest(FILE_PATH_LITERAL("input-button.html"));
}
@@ -1074,13 +1146,29 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-opened.html"));
}
+// Flaky on Windows and Mac: crbug.com/593846
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_AccessibilityModalDialogInIframeClosed \
+ DISABLED_AccessibilityModalDialogInIframeClosed
+#else
+#define MAYBE_AccessibilityModalDialogInIframeClosed \
+ AccessibilityModalDialogInIframeClosed
+#endif
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityModalDialogInIframeClosed) {
+ MAYBE_AccessibilityModalDialogInIframeClosed) {
RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html"));
}
+// Flaky on Windows and Mac: crbug.com/593846
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_AccessibilityModalDialogInIframeOpened \
+ DISABLED_AccessibilityModalDialogInIframeOpened
+#else
+#define MAYBE_AccessibilityModalDialogInIframeOpened \
+ AccessibilityModalDialogInIframeOpened
+#endif
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityModalDialogInIframeOpened) {
+ MAYBE_AccessibilityModalDialogInIframeOpened) {
RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html"));
}
diff --git a/chromium/content/browser/accessibility/hit_testing_browsertest.cc b/chromium/content/browser/accessibility/hit_testing_browsertest.cc
new file mode 100644
index 00000000000..7610f73da1d
--- /dev/null
+++ b/chromium/content/browser/accessibility/hit_testing_browsertest.cc
@@ -0,0 +1,171 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/accessibility_browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+bool AXTreeContainsNodeWithName(BrowserAccessibility* node,
+ const std::string& name) {
+ if (node->GetStringAttribute(ui::AX_ATTR_NAME) == name)
+ return true;
+
+ for (unsigned i = 0; i < node->PlatformChildCount(); i++) {
+ if (AXTreeContainsNodeWithName(node->PlatformGetChild(i), name))
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+class AccessibilityHitTestingBrowserTest : public ContentBrowserTest {
+ public:
+ AccessibilityHitTestingBrowserTest() {}
+ ~AccessibilityHitTestingBrowserTest() override {}
+
+ protected:
+ BrowserAccessibility* HitTestAndWaitForResult(const gfx::Point& point) {
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTree* frame_tree = web_contents->GetFrameTree();
+ BrowserAccessibilityManager* manager =
+ web_contents->GetRootBrowserAccessibilityManager();
+
+ AccessibilityNotificationWaiter hover_waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_HOVER);
+ for (FrameTreeNode* node : frame_tree->Nodes())
+ hover_waiter.ListenToAdditionalFrame(node->current_frame_host());
+ manager->delegate()->AccessibilityHitTest(point);
+ hover_waiter.WaitForNotification();
+
+ RenderFrameHostImpl* target_frame = hover_waiter.event_render_frame_host();
+ BrowserAccessibilityManager* target_manager =
+ target_frame->browser_accessibility_manager();
+ int hover_target_id = hover_waiter.event_target_id();
+ BrowserAccessibility* hovered_node =
+ target_manager->GetFromID(hover_target_id);
+ return hovered_node;
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
+ HitTestOutsideDocumentBoundsReturnsRoot) {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ // Load the page.
+ AccessibilityNotificationWaiter waiter(shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+ const char url_str[] =
+ "data:text/html,"
+ "<!doctype html>"
+ "<html><head><title>Accessibility Test</title></head>"
+ "<body>"
+ "<a href='#'>"
+ "This is some text in a link"
+ "</a>"
+ "</body></html>";
+ GURL url(url_str);
+ NavigateToURL(shell(), url);
+ waiter.WaitForNotification();
+
+ BrowserAccessibility* hovered_node =
+ HitTestAndWaitForResult(gfx::Point(-1, -1));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, hovered_node->GetRole());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityHitTestingBrowserTest,
+ HitTestingInIframes) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ AccessibilityNotificationWaiter waiter(shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+ GURL url(embedded_test_server()->GetURL(
+ "/accessibility/html/iframe-coordinates.html"));
+ NavigateToURL(shell(), url);
+ waiter.WaitForNotification();
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTree* frame_tree = web_contents->GetFrameTree();
+ BrowserAccessibilityManager* manager =
+ web_contents->GetRootBrowserAccessibilityManager();
+ BrowserAccessibility* root = manager->GetRoot();
+ while (!AXTreeContainsNodeWithName(root, "Ordinary Button") ||
+ !AXTreeContainsNodeWithName(root, "Scrolled Button")) {
+ AccessibilityNotificationWaiter waiter(shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_NONE);
+ for (FrameTreeNode* node : frame_tree->Nodes())
+ waiter.ListenToAdditionalFrame(node->current_frame_host());
+ waiter.WaitForNotification();
+ }
+
+ // Send a series of hit test requests, and for each one
+ // wait for the hover event in response, verifying we hit the
+ // correct object.
+
+ // (50, 50) -> "Button"
+ BrowserAccessibility* hovered_node;
+ hovered_node = HitTestAndWaitForResult(gfx::Point(50, 50));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_BUTTON, hovered_node->GetRole());
+ ASSERT_EQ("Button", hovered_node->GetStringAttribute(ui::AX_ATTR_NAME));
+
+ // (50, 305) -> div in first iframe
+ hovered_node = HitTestAndWaitForResult(gfx::Point(50, 305));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_DIV, hovered_node->GetRole());
+
+ // (50, 350) -> "Ordinary Button"
+ hovered_node = HitTestAndWaitForResult(gfx::Point(50, 350));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_BUTTON, hovered_node->GetRole());
+ ASSERT_EQ("Ordinary Button",
+ hovered_node->GetStringAttribute(ui::AX_ATTR_NAME));
+
+ // (50, 455) -> "Scrolled Button"
+ hovered_node = HitTestAndWaitForResult(gfx::Point(50, 455));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_BUTTON, hovered_node->GetRole());
+ ASSERT_EQ("Scrolled Button",
+ hovered_node->GetStringAttribute(ui::AX_ATTR_NAME));
+
+ // (50, 505) -> div in second iframe
+ hovered_node = HitTestAndWaitForResult(gfx::Point(50, 505));
+ ASSERT_TRUE(hovered_node != NULL);
+ ASSERT_EQ(ui::AX_ROLE_DIV, hovered_node->GetRole());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc
index 8b17f2d9fd2..1a0239eb58b 100644
--- a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc
+++ b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.cc
@@ -11,6 +11,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "ui/accessibility/ax_enums.h"
namespace content {
@@ -210,4 +211,249 @@ bool OneShotAccessibilityTreeSearch::Matches(BrowserAccessibility* node) {
return true;
}
+//
+// Predicates
+//
+
+bool AccessibilityArticlePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return node->GetRole() == ui::AX_ROLE_ARTICLE;
+}
+
+bool AccessibilityButtonPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ switch (node->GetRole()) {
+ case ui::AX_ROLE_BUTTON:
+ case ui::AX_ROLE_MENU_BUTTON:
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ case ui::AX_ROLE_SWITCH:
+ case ui::AX_ROLE_TOGGLE_BUTTON:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AccessibilityBlockquotePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return node->GetRole() == ui::AX_ROLE_BLOCKQUOTE;
+}
+
+bool AccessibilityCheckboxPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_CHECK_BOX ||
+ node->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX);
+}
+
+bool AccessibilityComboboxPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_COMBO_BOX ||
+ node->GetRole() == ui::AX_ROLE_POP_UP_BUTTON);
+}
+
+bool AccessibilityControlPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ if (node->IsControl())
+ return true;
+ if (node->HasState(ui::AX_STATE_FOCUSABLE) &&
+ node->GetRole() != ui::AX_ROLE_IFRAME &&
+ node->GetRole() != ui::AX_ROLE_IFRAME_PRESENTATIONAL &&
+ node->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK &&
+ node->GetRole() != ui::AX_ROLE_LINK &&
+ node->GetRole() != ui::AX_ROLE_WEB_AREA &&
+ node->GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) {
+ return true;
+ }
+ return false;
+}
+
+bool AccessibilityFocusablePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ bool focusable = node->HasState(ui::AX_STATE_FOCUSABLE);
+ if (node->GetRole() == ui::AX_ROLE_IFRAME ||
+ node->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL ||
+ node->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+ focusable = false;
+ }
+ return focusable;
+}
+
+bool AccessibilityGraphicPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return node->GetRole() == ui::AX_ROLE_IMAGE;
+}
+
+bool AccessibilityHeadingPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING);
+}
+
+bool AccessibilityH1Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1);
+}
+
+bool AccessibilityH2Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2);
+}
+
+bool AccessibilityH3Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3);
+}
+
+bool AccessibilityH4Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4);
+}
+
+bool AccessibilityH5Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5);
+}
+
+bool AccessibilityH6Predicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6);
+}
+
+bool AccessibilityHeadingSameLevelPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_HEADING &&
+ start->GetRole() == ui::AX_ROLE_HEADING &&
+ (node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) ==
+ start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)));
+}
+
+bool AccessibilityFramePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ if (node->IsWebAreaForPresentationalIframe())
+ return false;
+ if (!node->GetParent())
+ return false;
+ return (node->GetRole() == ui::AX_ROLE_WEB_AREA ||
+ node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+}
+
+bool AccessibilityLandmarkPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ switch (node->GetRole()) {
+ case ui::AX_ROLE_APPLICATION:
+ case ui::AX_ROLE_ARTICLE:
+ case ui::AX_ROLE_BANNER:
+ case ui::AX_ROLE_COMPLEMENTARY:
+ case ui::AX_ROLE_CONTENT_INFO:
+ case ui::AX_ROLE_MAIN:
+ case ui::AX_ROLE_NAVIGATION:
+ case ui::AX_ROLE_SEARCH:
+ case ui::AX_ROLE_REGION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AccessibilityLinkPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_LINK ||
+ node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK);
+}
+
+bool AccessibilityListPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_LIST_BOX ||
+ node->GetRole() == ui::AX_ROLE_LIST ||
+ node->GetRole() == ui::AX_ROLE_DESCRIPTION_LIST);
+}
+
+bool AccessibilityListItemPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_LIST_ITEM ||
+ node->GetRole() == ui::AX_ROLE_DESCRIPTION_LIST_TERM ||
+ node->GetRole() == ui::AX_ROLE_LIST_BOX_OPTION);
+}
+
+bool AccessibilityLiveRegionPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return node->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS);
+}
+
+bool AccessibilityMainPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_MAIN);
+}
+
+bool AccessibilityMediaPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ const std::string& tag = node->GetStringAttribute(ui::AX_ATTR_HTML_TAG);
+ return tag == "audio" || tag == "video";
+}
+
+bool AccessibilityRadioButtonPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_RADIO_BUTTON ||
+ node->GetRole() == ui::AX_ROLE_MENU_ITEM_RADIO);
+}
+
+bool AccessibilityRadioGroupPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return node->GetRole() == ui::AX_ROLE_RADIO_GROUP;
+}
+
+bool AccessibilityTablePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->GetRole() == ui::AX_ROLE_TABLE ||
+ node->GetRole() == ui::AX_ROLE_GRID);
+}
+
+bool AccessibilityTextfieldPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->IsSimpleTextControl() || node->IsRichTextControl());
+}
+
+bool AccessibilityTextStyleBoldPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+ return 0 != (style & ui::AX_TEXT_STYLE_BOLD);
+}
+
+bool AccessibilityTextStyleItalicPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+ return 0 != (style & ui::AX_TEXT_STYLE_BOLD);
+}
+
+bool AccessibilityTextStyleUnderlinePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+ return 0 != (style & ui::AX_TEXT_STYLE_UNDERLINE);
+}
+
+bool AccessibilityTreePredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return (node->IsSimpleTextControl() || node->IsRichTextControl());
+}
+
+bool AccessibilityUnvisitedLinkPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return ((node->GetRole() == ui::AX_ROLE_LINK ||
+ node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK) &&
+ !node->HasState(ui::AX_STATE_VISITED));
+}
+
+bool AccessibilityVisitedLinkPredicate(
+ BrowserAccessibility* start, BrowserAccessibility* node) {
+ return ((node->GetRole() == ui::AX_ROLE_LINK ||
+ node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK) &&
+ node->HasState(ui::AX_STATE_VISITED));
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h
index 2538bb8aee0..df79eb94e02 100644
--- a/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h
+++ b/chromium/content/browser/accessibility/one_shot_accessibility_tree_search.h
@@ -24,6 +24,47 @@ typedef bool (*AccessibilityMatchPredicate)(
BrowserAccessibility* start_element,
BrowserAccessibility* this_element);
+#define DECLARE_ACCESSIBILITY_PREDICATE(PredicateName) \
+ bool PredicateName(BrowserAccessibility* start_element, \
+ BrowserAccessibility* this_element);
+
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityArticlePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityBlockquotePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityButtonPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityCheckboxPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityComboboxPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityControlPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityFocusablePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityGraphicPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityHeadingPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH1Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH2Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH3Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH4Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH5Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH6Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityHeadingSameLevelPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityFramePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLandmarkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityListPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityListItemPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLiveRegionPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityMainPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityMediaPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityRadioButtonPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityRadioGroupPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTablePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextfieldPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleBoldPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleItalicPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleUnderlinePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTreePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityUnvisitedLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityVisitedLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleBoldPredicate);
+
+
// This class provides an interface for searching the accessibility tree from
// a given starting node, with a few built-in options and allowing an arbitrary
// number of predicates that can be used to restrict the search.
diff --git a/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc b/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
index 37107702569..75833ff9aa8 100644
--- a/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
+++ b/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
@@ -58,15 +58,6 @@ bool AccessibilityTreeContainsText(BrowserAccessibility* node,
return false;
}
-// Helper function to be used with FrameTree::ForEach, so that
-// AccessibilityNotificationWaiter can listen for accessibility
-// events in all frames.
-bool ListenToFrame(AccessibilityNotificationWaiter* waiter,
- FrameTreeNode* frame_tree_node) {
- waiter->ListenToAdditionalFrame(frame_tree_node->current_frame_host());
- return true;
-}
-
} // namespace
class MAYBE_SitePerProcessAccessibilityBrowserTest
@@ -113,7 +104,10 @@ class MAYBE_SitePerProcessAccessibilityBrowserTest
main_frame_manager->GetRoot(), text)) {
AccessibilityNotificationWaiter accessibility_waiter(main_frame,
ui::AX_EVENT_NONE);
- frame_tree->ForEach(base::Bind(ListenToFrame, &accessibility_waiter));
+ for (FrameTreeNode* node : frame_tree->Nodes())
+ accessibility_waiter.ListenToAdditionalFrame(
+ node->current_frame_host());
+
accessibility_waiter.WaitForNotification();
}
}
diff --git a/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc b/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
index da6201f5b6b..7dc177d8e5d 100644
--- a/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
@@ -9,6 +9,9 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
@@ -39,6 +42,19 @@ class AXTreeSnapshotWaiter {
DISALLOW_COPY_AND_ASSIGN(AXTreeSnapshotWaiter);
};
+void DumpRolesAndNamesAsText(const ui::AXNode* node,
+ int indent,
+ std::string* dst) {
+ for (int i = 0; i < indent; i++)
+ *dst += " ";
+ *dst += ui::ToString(node->data().role);
+ if (node->data().HasStringAttribute(ui::AX_ATTR_NAME))
+ *dst += " '" + node->data().GetStringAttribute(ui::AX_ATTR_NAME) + "'";
+ *dst += "\n";
+ for (int i = 0; i < node->child_count(); ++i)
+ DumpRolesAndNamesAsText(node->children()[i], indent + 1, dst);
+}
+
} // namespace
class SnapshotAXTreeBrowserTest : public ContentBrowserTest {
@@ -75,4 +91,54 @@ IN_PROC_BROWSER_TEST_F(SnapshotAXTreeBrowserTest,
ASSERT_EQ(ui::AX_ROLE_BUTTON, button->data().role);
}
+IN_PROC_BROWSER_TEST_F(SnapshotAXTreeBrowserTest,
+ SnapshotAccessibilityTreeFromMultipleFrames) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL(
+ "/accessibility/snapshot/outer.html"));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root_frame = web_contents->GetFrameTree()->root();
+
+ NavigateFrameToURL(root_frame->child_at(0), GURL("data:text/plain,Alpha"));
+ NavigateFrameToURL(root_frame->child_at(1), embedded_test_server()->GetURL(
+ "/accessibility/snapshot/inner.html"));
+
+ AXTreeSnapshotWaiter waiter;
+ web_contents->RequestAXTreeSnapshot(
+ base::Bind(&AXTreeSnapshotWaiter::ReceiveSnapshot,
+ base::Unretained(&waiter)));
+ waiter.Wait();
+
+ // Dump the whole tree if one of the assertions below fails
+ // to aid in debugging why it failed.
+ SCOPED_TRACE(waiter.snapshot().ToString());
+
+ ui::AXTree tree(waiter.snapshot());
+ ui::AXNode* root = tree.root();
+ std::string dump;
+ DumpRolesAndNamesAsText(root, 0, &dump);
+ EXPECT_EQ(
+ "rootWebArea\n"
+ " group\n"
+ " button 'Before'\n"
+ " iframe\n"
+ " group\n"
+ " pre\n"
+ " staticText 'Alpha'\n"
+ " button 'Middle'\n"
+ " iframe\n"
+ " group\n"
+ " group\n"
+ " button 'Inside Before'\n"
+ " iframe\n"
+ " group\n"
+ " button 'Inside After'\n"
+ " button 'After'\n",
+ dump);
+}
+
} // namespace content
diff --git a/chromium/content/browser/android/browser_surface_texture_manager.h b/chromium/content/browser/android/browser_surface_texture_manager.h
index f9fb74cccb5..639ce28b0e5 100644
--- a/chromium/content/browser/android/browser_surface_texture_manager.h
+++ b/chromium/content/browser/android/browser_surface_texture_manager.h
@@ -5,18 +5,18 @@
#ifndef CONTENT_BROWSER_ANDROID_BROWSER_SURFACE_TEXTURE_MANAGER_H_
#define CONTENT_BROWSER_ANDROID_BROWSER_SURFACE_TEXTURE_MANAGER_H_
-#include "content/common/android/surface_texture_manager.h"
+#include "gpu/ipc/common/android/surface_texture_manager.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "content/common/android/surface_texture_peer.h"
#include "content/common/content_export.h"
+#include "gpu/ipc/common/android/surface_texture_peer.h"
namespace content {
class CONTENT_EXPORT BrowserSurfaceTextureManager
- : public SurfaceTextureManager,
- public SurfaceTexturePeer {
+ : public gpu::SurfaceTextureManager,
+ public gpu::SurfaceTexturePeer {
public:
static BrowserSurfaceTextureManager* GetInstance();
diff --git a/chromium/content/browser/android/child_process_launcher_android.cc b/chromium/content/browser/android/child_process_launcher_android.cc
index 471ce31d91c..94765fbeeba 100644
--- a/chromium/content/browser/android/child_process_launcher_android.cc
+++ b/chromium/content/browser/android/child_process_launcher_android.cc
@@ -13,12 +13,16 @@
#include "base/android/jni_array.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "content/browser/file_descriptor_info_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/media/android/media_web_contents_observer_android.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/child_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "jni/ChildProcessLauncher_jni.h"
#include "media/base/android/media_player_android.h"
@@ -41,7 +45,6 @@ static void SetSurfacePeer(
base::ProcessHandle render_process_handle,
int render_frame_id,
int player_id) {
-#if !defined(USE_AURA)
int render_process_id = 0;
RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
while (!it.IsAtEnd()) {
@@ -83,9 +86,21 @@ static void SetSurfacePeer(
gfx::ScopedJavaSurface scoped_surface(surface);
player->SetVideoSurface(std::move(scoped_surface));
}
-#else
- NOTREACHED();
-#endif
+}
+
+void LaunchDownloadProcess(base::CommandLine* cmd_line) {
+ scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
+
+ JNIEnv* env = AttachCurrentThread();
+ DCHECK(env);
+
+ // Create the Command line String[]
+ ScopedJavaLocalRef<jobjectArray> j_argv =
+ ToJavaArrayOfStrings(env, cmd_line->argv());
+
+ // TODO(qinmin): pass download parameters here.
+ Java_ChildProcessLauncher_startDownloadProcessIfNecessary(
+ env, base::android::GetApplicationContext(), j_argv.obj());
}
} // anonymous namespace
@@ -107,6 +122,32 @@ static void OnChildProcessStarted(JNIEnv*,
delete callback;
}
+void StartDownloadProcessIfNecessary() {
+ base::FilePath exe_path = content::ChildProcessHost::GetChildPath(
+ content::ChildProcessHost::CHILD_NORMAL);
+ if (exe_path.empty()) {
+ NOTREACHED() << "Unable to get download process binary name.";
+ return;
+ }
+ base::CommandLine* cmd_line = new base::CommandLine(exe_path);
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kDownloadProcess);
+ cmd_line->AppendSwitch(switches::kNoSandbox);
+
+ const base::CommandLine browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ static const char* kForwardSwitches[] = {
+ switches::kDisableLogging,
+ switches::kEnableLogging,
+ switches::kLoggingLevel,
+ };
+ cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
+ arraysize(kForwardSwitches));
+ CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
+ BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&LaunchDownloadProcess, cmd_line));
+}
+
void StartChildProcess(
const base::CommandLine::StringVector& argv,
int child_process_id,
@@ -205,6 +246,13 @@ void UnregisterViewSurface(int surface_id) {
Java_ChildProcessLauncher_unregisterViewSurface(env, surface_id);
}
+gfx::ScopedJavaSurface GetViewSurface(int surface_id) {
+ JNIEnv* env = AttachCurrentThread();
+ DCHECK(env);
+ return gfx::ScopedJavaSurface::AcquireExternalSurface(
+ Java_ChildProcessLauncher_getViewSurface(env, surface_id).obj());
+}
+
void CreateSurfaceTextureSurface(int surface_texture_id,
int client_id,
gfx::SurfaceTexture* surface_texture) {
diff --git a/chromium/content/browser/android/child_process_launcher_android.h b/chromium/content/browser/android/child_process_launcher_android.h
index ea806ac5571..41cf4535704 100644
--- a/chromium/content/browser/android/child_process_launcher_android.h
+++ b/chromium/content/browser/android/child_process_launcher_android.h
@@ -6,11 +6,13 @@
#define CONTENT_BROWSER_ANDROID_CHILD_PROCESS_LAUNCHER_ANDROID_H_
#include <jni.h>
+
#include <map>
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/memory_mapped_file.h"
+#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "content/public/browser/file_descriptor_info.h"
#include "ui/gl/android/scoped_java_surface.h"
@@ -29,6 +31,10 @@ void StartChildProcess(
const std::map<int, base::MemoryMappedFile::Region>& regions,
const StartChildProcessCallback& callback);
+// Starts the background download process if it hasn't been started.
+// TODO(qinmin): pass the download parameters here and pass it to java side.
+void StartDownloadProcessIfNecessary();
+
// Stops a child process based on the handle returned form
// StartChildProcess.
void StopChildProcess(base::ProcessHandle handle);
@@ -42,6 +48,8 @@ void RegisterViewSurface(int surface_id, jobject j_surface);
void UnregisterViewSurface(int surface_id);
+gfx::ScopedJavaSurface GetViewSurface(int surface_id);
+
void CreateSurfaceTextureSurface(int surface_texture_id,
int client_id,
gfx::SurfaceTexture* surface_texture);
diff --git a/chromium/content/browser/android/composited_touch_handle_drawable.cc b/chromium/content/browser/android/composited_touch_handle_drawable.cc
index 235e2eef3b4..16974e1afcc 100644
--- a/chromium/content/browser/android/composited_touch_handle_drawable.cc
+++ b/chromium/content/browser/android/composited_touch_handle_drawable.cc
@@ -96,7 +96,7 @@ CompositedTouchHandleDrawable::CompositedTouchHandleDrawable(
jobject context)
: dpi_scale_(dpi_scale),
orientation_(ui::TouchHandleOrientation::UNDEFINED),
- layer_(cc::UIResourceLayer::Create(Compositor::LayerSettings())) {
+ layer_(cc::UIResourceLayer::Create()) {
g_selection_resources.Get().LoadIfNecessary(context);
drawable_horizontal_padding_ratio_ =
g_selection_resources.Get().GetDrawableHorizontalPaddingRatio();
diff --git a/chromium/content/browser/android/content_startup_flags.cc b/chromium/content/browser/android/content_startup_flags.cc
index acda33ee494..b588deda0c9 100644
--- a/chromium/content/browser/android/content_startup_flags.cc
+++ b/chromium/content/browser/android/content_startup_flags.cc
@@ -10,7 +10,6 @@
#include "base/logging.h"
#include "base/sys_info.h"
#include "cc/base/switches.h"
-#include "cc/layers/layer_settings.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
@@ -79,14 +78,6 @@ void SetContentCommandLineFlags(bool single_process,
parsed_command_line->AppendSwitchASCII(
switches::kProfilerTiming, switches::kProfilerTimingDisabledValue);
}
-
-#if !defined(USE_AURA)
- cc::LayerSettings layer_settings;
- layer_settings.use_compositor_animation_timelines =
- !parsed_command_line->HasSwitch(
- switches::kDisableAndroidCompositorAnimationTimelines);
- Compositor::SetLayerSettings(layer_settings);
-#endif
}
} // namespace content
diff --git a/chromium/content/browser/android/content_video_view.cc b/chromium/content/browser/android/content_video_view.cc
index b107377c34c..4b14959ba5f 100644
--- a/chromium/content/browser/android/content_video_view.cc
+++ b/chromium/content/browser/android/content_video_view.cc
@@ -4,21 +4,15 @@
#include "content/browser/android/content_video_view.h"
-#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "content/browser/android/content_view_core_impl.h"
#include "content/browser/media/android/browser_media_player_manager.h"
-#include "content/browser/power_save_blocker_impl.h"
-#include "content/common/android/surface_texture_peer.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "jni/ContentVideoView_jni.h"
-#if !defined(USE_AURA)
-#include "content/browser/android/content_view_core_impl.h"
-#endif
-
using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::ScopedJavaGlobalRef;
@@ -51,12 +45,11 @@ ContentVideoView* ContentVideoView::GetInstance() {
return g_content_video_view;
}
-ContentVideoView::ContentVideoView(
- BrowserMediaPlayerManager* manager)
- : manager_(manager),
- weak_factory_(this) {
+ContentVideoView::ContentVideoView(Client* client,
+ ContentViewCore* content_view_core)
+ : client_(client), weak_factory_(this) {
DCHECK(!g_content_video_view);
- j_content_video_view_ = CreateJavaObject();
+ j_content_video_view_ = CreateJavaObject(content_view_core);
g_content_video_view = this;
}
@@ -85,7 +78,7 @@ void ContentVideoView::OnMediaPlayerError(int error_type) {
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
if (!content_video_view.is_null()) {
Java_ContentVideoView_onMediaPlayerError(env, content_video_view.obj(),
- error_type);
+ error_type);
}
}
@@ -94,23 +87,35 @@ void ContentVideoView::OnVideoSizeChanged(int width, int height) {
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
if (!content_video_view.is_null()) {
Java_ContentVideoView_onVideoSizeChanged(env, content_video_view.obj(),
- width, height);
+ width, height);
}
}
-void ContentVideoView::OnPlaybackComplete() {
+void ContentVideoView::ExitFullscreen() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
- if (!content_video_view.is_null()) {
- Java_ContentVideoView_onPlaybackComplete(env, content_video_view.obj());
- }
+ bool release_media_player = false;
+ if (!content_video_view.is_null())
+ Java_ContentVideoView_exitFullscreen(env, content_video_view.obj(),
+ release_media_player);
}
-void ContentVideoView::OnExitFullscreen() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
- if (!content_video_view.is_null())
- Java_ContentVideoView_onExitFullscreen(env, content_video_view.obj());
+ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
+ return j_content_video_view_.get(env);
+}
+
+void ContentVideoView::SetSurface(JNIEnv*,
+ const JavaParamRef<jobject>&,
+ const JavaParamRef<jobject>& surface) {
+ client_->SetVideoSurface(
+ gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
+}
+
+void ContentVideoView::DidExitFullscreen(JNIEnv*,
+ const JavaParamRef<jobject>&,
+ jboolean release_media_player) {
+ j_content_video_view_.reset();
+ client_->DidExitFullscreen(release_media_player);
}
void ContentVideoView::RecordFullscreenPlayback(JNIEnv*,
@@ -151,63 +156,11 @@ void ContentVideoView::RecordExitFullscreenPlayback(
}
}
-void ContentVideoView::UpdateMediaMetadata() {
+JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject(
+ ContentViewCore* content_view_core) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
- if (content_video_view.is_null())
- return;
-
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- if (player && player->IsPlayerReady()) {
- Java_ContentVideoView_onUpdateMediaMetadata(
- env, content_video_view.obj(), player->GetVideoWidth(),
- player->GetVideoHeight(),
- static_cast<int>(player->GetDuration().InMilliseconds()),
- player->CanPause(),player->CanSeekForward(), player->CanSeekBackward());
- }
-}
-
-bool ContentVideoView::IsPlaying(JNIEnv*, const JavaParamRef<jobject>& obj) {
- media::MediaPlayerAndroid* player = manager_->GetFullscreenPlayer();
- return player ? player->IsPlaying() : false;
-}
-
-void ContentVideoView::ExitFullscreen(JNIEnv*,
- const JavaParamRef<jobject>&,
- jboolean release_media_player) {
- j_content_video_view_.reset();
- manager_->ExitFullscreen(release_media_player);
-}
-
-void ContentVideoView::SetSurface(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- const JavaParamRef<jobject>& surface) {
- manager_->SetVideoSurface(
- gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
-}
-
-void ContentVideoView::RequestMediaMetadata(JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&ContentVideoView::UpdateMediaMetadata,
- weak_factory_.GetWeakPtr()));
-}
-
-ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
- return j_content_video_view_.get(env);
-}
-
-JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject() {
-
- JNIEnv* env = AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jobject> j_content_view_core;
-
-#if !defined(USE_AURA)
- ContentViewCore* content_view_core = manager_->GetContentViewCore();
- j_content_view_core = content_view_core->GetJavaObject();
-#endif
-
+ base::android::ScopedJavaLocalRef<jobject> j_content_view_core =
+ content_view_core->GetJavaObject();
if (j_content_view_core.is_null())
return JavaObjectWeakGlobalRef(env, nullptr);
diff --git a/chromium/content/browser/android/content_video_view.h b/chromium/content/browser/android/content_video_view.h
index 7959cd60880..292f818d927 100644
--- a/chromium/content/browser/android/content_video_view.h
+++ b/chromium/content/browser/android/content_video_view.h
@@ -10,60 +10,69 @@
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "ui/gfx/native_widget_types.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "ui/gl/android/scoped_java_surface.h"
namespace content {
-class BrowserMediaPlayerManager;
-
// Native mirror of ContentVideoView.java. This class is responsible for
-// creating the Java video view and pass all the player status change to
-// it. It accepts media control from Java class, and forwards it to
-// MediaPlayerManagerImpl.
+// creating the Java video view and passing changes in player status to it.
+// This class must be used on the UI thread.
class ContentVideoView {
public:
- // Construct a ContentVideoView object. The |manager| will handle all the
- // playback controls from the Java class.
- explicit ContentVideoView(BrowserMediaPlayerManager* manager);
+ static bool RegisterContentVideoView(JNIEnv* env);
+
+ // Returns the singleton object or NULL.
+ static ContentVideoView* GetInstance();
+
+ class Client {
+ public:
+ Client() {}
+ // For receiving notififcations when the SurfaceView surface is created and
+ // destroyed. When |surface.IsEmpty()| the surface was destroyed and
+ // the client should not hold any references to it once this returns.
+ virtual void SetVideoSurface(gfx::ScopedJavaSurface surface) = 0;
+ // Called after the ContentVideoView has been hidden because we're exiting
+ // fullscreen.
+ virtual void DidExitFullscreen(bool release_media_player) = 0;
+
+ protected:
+ ~Client() {}
+
+ DISALLOW_COPY_AND_ASSIGN(Client);
+ };
+
+ explicit ContentVideoView(Client* client, ContentViewCore* content_view_core);
~ContentVideoView();
// To open another video on existing ContentVideoView.
void OpenVideo();
- static bool RegisterContentVideoView(JNIEnv* env);
- static void KeepScreenOn(bool screen_on);
+ // Display an error dialog to the user.
+ void OnMediaPlayerError(int error_type);
- // Return the singleton object or NULL.
- static ContentVideoView* GetInstance();
+ // Update the video size. The video will not be visible until this is called.
+ void OnVideoSizeChanged(int width, int height);
- // Getter method called by the Java class to get the media information.
- bool IsPlaying(JNIEnv*, const base::android::JavaParamRef<jobject>& obj);
- void RequestMediaMetadata(JNIEnv*,
- const base::android::JavaParamRef<jobject>& obj);
+ // Exit fullscreen and notify |client_| with |DidExitFullscreen|.
+ void ExitFullscreen();
- // Called when the Java fullscreen view is destroyed. If
- // |release_media_player| is true, |manager_| needs to release the player
- // as we are quitting the app.
- void ExitFullscreen(JNIEnv*,
- const base::android::JavaParamRef<jobject>&,
- jboolean release_media_player);
+ // Returns the corresponding ContentVideoView Java object if any.
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject(JNIEnv* env);
- // Called by the Java class to pass the surface object to the player.
- void SetSurface(JNIEnv*,
+ // Called by the Java class when the surface changes.
+ void SetSurface(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& surface);
- // Method called by |manager_| to inform the Java class about player status
- // change.
- void UpdateMediaMetadata();
- void OnMediaPlayerError(int errorType);
- void OnVideoSizeChanged(int width, int height);
- void OnPlaybackComplete();
- void OnExitFullscreen();
+ // Called when the Java fullscreen view is destroyed. If
+ // |release_media_player| is true, |client_| needs to release the player
+ // as we are quitting the app.
+ void DidExitFullscreen(JNIEnv*,
+ const base::android::JavaParamRef<jobject>&,
+ jboolean release_media_player);
// Functions called to record fullscreen playback UMA metrics.
void RecordFullscreenPlayback(JNIEnv*,
@@ -77,18 +86,13 @@ class ContentVideoView {
long playback_duration_in_milliseconds_before_orientation_change,
long playback_duration_in_milliseconds_after_orientation_change);
- // Return the corresponing ContentVideoView Java object if any.
- base::android::ScopedJavaLocalRef<jobject> GetJavaObject(JNIEnv* env);
-
private:
// Creates the corresponding ContentVideoView Java object.
- JavaObjectWeakGlobalRef CreateJavaObject();
+ JavaObjectWeakGlobalRef CreateJavaObject(ContentViewCore* content_view_core);
- // Object that manages the fullscreen media player. It is responsible for
- // handling all the playback controls.
- BrowserMediaPlayerManager* manager_;
+ Client* client_;
- // Weak reference of corresponding Java object.
+ // Weak reference to corresponding Java object.
JavaObjectWeakGlobalRef j_content_video_view_;
// Weak pointer for posting tasks.
diff --git a/chromium/content/browser/android/content_view_core_impl.cc b/chromium/content/browser/android/content_view_core_impl.cc
index 965c21e95f0..2322e763408 100644
--- a/chromium/content/browser/android/content_view_core_impl.cc
+++ b/chromium/content/browser/android/content_view_core_impl.cc
@@ -19,6 +19,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/output/viewport_selection_bound.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/android/gesture_event_type.h"
#include "content/browser/android/interstitial_page_delegate_android.h"
@@ -55,6 +56,7 @@
#include "ui/android/view_android.h"
#include "ui/android/window_android.h"
#include "ui/events/android/motion_event_android.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -212,7 +214,7 @@ ContentViewCoreImpl::ContentViewCoreImpl(
: WebContentsObserver(web_contents),
java_ref_(env, obj),
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
- root_layer_(cc::SolidColorLayer::Create(Compositor::LayerSettings())),
+ root_layer_(cc::SolidColorLayer::Create()),
page_scale_(1),
dpi_scale_(ui::GetScaleFactorForNativeView(this)),
window_android_(window_android),
@@ -247,8 +249,22 @@ ContentViewCoreImpl::ContentViewCoreImpl(
InitWebContents();
}
+void ContentViewCoreImpl::AddObserver(
+ ContentViewCoreImplObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ContentViewCoreImpl::RemoveObserver(
+ ContentViewCoreImplObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
ContentViewCoreImpl::~ContentViewCoreImpl() {
root_layer_->RemoveFromParent();
+ FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
+ observer_list_,
+ OnContentViewCoreDestroyed());
+ observer_list_.Clear();
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
@@ -259,6 +275,24 @@ ContentViewCoreImpl::~ContentViewCoreImpl() {
}
}
+void ContentViewCoreImpl::UpdateWindowAndroid(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jlong window_android) {
+ if (window_android) {
+ DCHECK(!window_android_);
+ window_android_ = reinterpret_cast<ui::WindowAndroid*>(window_android);
+ FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
+ observer_list_,
+ OnAttachedToWindow());
+ } else {
+ FOR_EACH_OBSERVER(ContentViewCoreImplObserver,
+ observer_list_,
+ OnDetachedFromWindow());
+ window_android_ = NULL;
+ }
+}
+
base::android::ScopedJavaLocalRef<jobject>
ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
@@ -387,10 +421,11 @@ void ContentViewCoreImpl::UpdateFrameInfo(
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
const gfx::Vector2dF& content_offset,
- bool is_mobile_optimized_hint) {
+ bool is_mobile_optimized_hint,
+ const cc::ViewportSelectionBound& selection_start) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
+ if (obj.is_null() || !window_android_)
return;
window_android_->set_content_offset(
@@ -398,6 +433,18 @@ void ContentViewCoreImpl::UpdateFrameInfo(
page_scale_ = page_scale_factor;
+ // The CursorAnchorInfo API in Android only supports zero width selection
+ // bounds.
+ const jboolean has_insertion_marker =
+ selection_start.type == cc::SELECTION_BOUND_CENTER;
+ const jboolean is_insertion_marker_visible = selection_start.visible;
+ const jfloat insertion_marker_horizontal =
+ has_insertion_marker ? selection_start.edge_top.x() : 0.0f;
+ const jfloat insertion_marker_top =
+ has_insertion_marker ? selection_start.edge_top.y() : 0.0f;
+ const jfloat insertion_marker_bottom =
+ has_insertion_marker ? selection_start.edge_bottom.y() : 0.0f;
+
Java_ContentViewCore_updateFrameInfo(
env, obj.obj(),
scroll_offset.x(),
@@ -411,7 +458,12 @@ void ContentViewCoreImpl::UpdateFrameInfo(
viewport_size.height(),
controls_offset.y(),
content_offset.y(),
- is_mobile_optimized_hint);
+ is_mobile_optimized_hint,
+ has_insertion_marker,
+ is_insertion_marker_visible,
+ insertion_marker_horizontal,
+ insertion_marker_top,
+ insertion_marker_bottom);
}
void ContentViewCoreImpl::SetTitle(const base::string16& title) {
@@ -718,6 +770,22 @@ ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() const {
return Java_ContentViewCore_getContext(env, obj.obj());
}
+gfx::Size ContentViewCoreImpl::GetViewSizeWithOSKHidden() const {
+ gfx::Size size_pix;
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
+ if (j_obj.is_null())
+ return size_pix = gfx::Size();
+ size_pix = gfx::Size(
+ Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
+ Java_ContentViewCore_getViewportHeightWithOSKHiddenPix(env, j_obj.obj()));
+
+ gfx::Size size_dip = gfx::ScaleToCeiledSize(size_pix, 1.0f / dpi_scale());
+ if (DoTopControlsShrinkBlinkSize())
+ size_dip.Enlarge(0, -GetTopControlsHeightDip());
+ return size_dip;
+}
+
gfx::Size ContentViewCoreImpl::GetViewSize() const {
gfx::Size size = GetViewportSizeDip();
if (DoTopControlsShrinkBlinkSize())
@@ -949,7 +1017,8 @@ jboolean ContentViewCoreImpl::SendMouseMoveEvent(
const JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
- jfloat y) {
+ jfloat y,
+ jint tool_type) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (!rwhv)
return false;
@@ -957,7 +1026,8 @@ jboolean ContentViewCoreImpl::SendMouseMoveEvent(
blink::WebMouseEvent event = WebMouseEventBuilder::Build(
WebInputEvent::MouseMove,
blink::WebMouseEvent::ButtonNone,
- time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1);
+ time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1,
+ ui::ToWebPointerType(static_cast<ui::MotionEvent::ToolType>(tool_type)));
rwhv->SendMouseEvent(event);
return true;
@@ -1154,15 +1224,6 @@ void ContentViewCoreImpl::SelectBetweenCoordinates(
gfx::PointF(x2 / dpi_scale(), y2 / dpi_scale()));
}
-void ContentViewCoreImpl::MoveCaret(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jfloat x,
- jfloat y) {
- RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
- if (rwhv)
- rwhv->MoveCaret(gfx::Point(x / dpi_scale_, y / dpi_scale_));
-}
-
void ContentViewCoreImpl::DismissTextHandles(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
@@ -1239,9 +1300,7 @@ void ContentViewCoreImpl::WasResized(JNIEnv* env,
root_layer_->SetBounds(physical_size);
if (view) {
- RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
- view->GetRenderWidgetHost());
- host->SendScreenRects();
+ web_contents_->SendScreenRects();
view->WasResized();
}
}
@@ -1431,10 +1490,6 @@ void ContentViewCoreImpl::OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip) {
static_cast<jint>(y_dip * dpi_scale()));
}
-float ContentViewCoreImpl::GetScaleFactor() const {
- return page_scale_ * dpi_scale_;
-}
-
void ContentViewCoreImpl::OnSmartClipDataExtracted(
const base::string16& text,
const base::string16& html,
diff --git a/chromium/content/browser/android/content_view_core_impl.h b/chromium/content/browser/android/content_view_core_impl.h
index 2e0b22694ee..31635faca33 100644
--- a/chromium/content/browser/android/content_view_core_impl.h
+++ b/chromium/content/browser/android/content_view_core_impl.h
@@ -16,6 +16,7 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
+#include "content/browser/android/content_view_core_impl_observer.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/android/content_view_core.h"
@@ -27,6 +28,10 @@
#include "ui/gfx/geometry/rect_f.h"
#include "url/gurl.h"
+namespace cc {
+struct ViewportSelectionBound;
+}
+
namespace ui {
class WindowAndroid;
}
@@ -69,6 +74,9 @@ class ContentViewCoreImpl : public ContentViewCore,
int start_offset,
int end_offset)>& callback) override;
+ void AddObserver(ContentViewCoreImplObserver* observer);
+ void RemoveObserver(ContentViewCoreImplObserver* observer);
+
// ViewAndroid implementation
base::android::ScopedJavaLocalRef<jobject> GetViewAndroidDelegate()
const override;
@@ -84,6 +92,9 @@ class ContentViewCoreImpl : public ContentViewCore,
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
+ void UpdateWindowAndroid(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jlong window_android);
void OnJavaContentViewCoreDestroyed(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
@@ -134,7 +145,8 @@ class ContentViewCoreImpl : public ContentViewCore,
const base::android::JavaParamRef<jobject>& obj,
jlong time_ms,
jfloat x,
- jfloat y);
+ jfloat y,
+ jint tool_type);
jboolean SendMouseWheelEvent(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jlong time_ms,
@@ -207,10 +219,6 @@ class ContentViewCoreImpl : public ContentViewCore,
jfloat y1,
jfloat x2,
jfloat y2);
- void MoveCaret(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jfloat x,
- jfloat y);
void DismissTextHandles(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void SetTextHandlesTemporarilyHidden(
@@ -236,7 +244,6 @@ class ContentViewCoreImpl : public ContentViewCore,
jboolean focused);
jint GetBackgroundColor(JNIEnv* env, jobject obj);
- void SetBackgroundColor(JNIEnv* env, jobject obj, jint color);
void SetAllowJavascriptInterfacesInspection(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
@@ -313,7 +320,8 @@ class ContentViewCoreImpl : public ContentViewCore,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
const gfx::Vector2dF& content_offset,
- bool is_mobile_optimized_hint);
+ bool is_mobile_optimized_hint,
+ const cc::ViewportSelectionBound& selection_start);
void ForceUpdateImeAdapter(long native_ime_adapter);
void UpdateImeAdapter(long native_ime_adapter,
@@ -363,6 +371,8 @@ class ContentViewCoreImpl : public ContentViewCore,
// Returns the viewport size after accounting for the viewport offset.
gfx::Size GetViewSize() const;
+ gfx::Size GetViewSizeWithOSKHidden() const;
+
void SetAccessibilityEnabledInternal(bool enabled);
bool IsFullscreenRequiredForOrientationLock() const;
@@ -386,8 +396,6 @@ class ContentViewCoreImpl : public ContentViewCore,
void OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip);
- // returns page density (dpi) X page scale
- float GetScaleFactor() const;
private:
class ContentViewUserData;
@@ -454,6 +462,9 @@ class ContentViewCoreImpl : public ContentViewCore,
// The owning window that has a hold of main application activity.
ui::WindowAndroid* window_android_;
+ // Observer to notify of lifecyle changes.
+ base::ObserverList<ContentViewCoreImplObserver> observer_list_;
+
// The cache of device's current orientation set from Java side, this value
// will be sent to Renderer once it is ready.
int device_orientation_;
diff --git a/chromium/content/browser/android/content_view_core_impl_observer.h b/chromium/content/browser/android/content_view_core_impl_observer.h
new file mode 100644
index 00000000000..d27735e9dc0
--- /dev/null
+++ b/chromium/content/browser/android/content_view_core_impl_observer.h
@@ -0,0 +1,22 @@
+// 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 CONTENT_BROWSER_ANDROID_CONTENT_VIEW_CORE_IMPL_OBSERVER_H
+#define CONTENT_BROWSER_ANDROID_CONTENT_VIEW_CORE_IMPL_OBSERVER_H
+
+namespace content {
+
+class ContentViewCoreImplObserver {
+ public:
+ virtual void OnContentViewCoreDestroyed() = 0;
+ virtual void OnAttachedToWindow() = 0;
+ virtual void OnDetachedFromWindow() = 0;
+
+ protected:
+ virtual ~ContentViewCoreImplObserver() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_CONTENT_VIEW_CORE_IMPL_OBSERVER_H
diff --git a/chromium/content/browser/android/content_view_render_view.cc b/chromium/content/browser/android/content_view_render_view.cc
index 24fdbc2f020..be3064e05eb 100644
--- a/chromium/content/browser/android/content_view_render_view.cc
+++ b/chromium/content/browser/android/content_view_render_view.cc
@@ -99,14 +99,7 @@ void ContentViewRenderView::SetOverlayVideoMode(
const JavaParamRef<jobject>& obj,
bool enabled) {
compositor_->SetHasTransparentBackground(enabled);
- SetNeedsComposite(env, obj);
-}
-
-void ContentViewRenderView::SetNeedsComposite(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- if (compositor_)
- compositor_->SetNeedsComposite();
+ compositor_->SetNeedsComposite();
}
void ContentViewRenderView::UpdateLayerTreeHost() {
@@ -124,11 +117,4 @@ void ContentViewRenderView::InitCompositor() {
compositor_.reset(Compositor::Create(this, root_window_));
}
-jlong ContentViewRenderView::GetUIResourceProvider(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- if (!compositor_)
- return 0;
- return reinterpret_cast<intptr_t>(&compositor_->GetUIResourceProvider());
-}
} // namespace content
diff --git a/chromium/content/browser/android/content_view_render_view.h b/chromium/content/browser/android/content_view_render_view.h
index c571de0fd4e..50f3b9c4f83 100644
--- a/chromium/content/browser/android/content_view_render_view.h
+++ b/chromium/content/browser/android/content_view_render_view.h
@@ -48,13 +48,6 @@ class ContentViewRenderView : public CompositorClient {
void SetOverlayVideoMode(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
bool enabled);
- void SetNeedsComposite(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
-
- // TODO(yusufo): Remove this once the compositor code is
- // refactored to use a unified system.
- jlong GetUIResourceProvider(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
// CompositorClient implementation
void UpdateLayerTreeHost() override;
diff --git a/chromium/content/browser/android/download_controller_android_impl.cc b/chromium/content/browser/android/download_controller_android_impl.cc
index feb8de30152..768a599f6bd 100644
--- a/chromium/content/browser/android/download_controller_android_impl.cc
+++ b/chromium/content/browser/android/download_controller_android_impl.cc
@@ -32,6 +32,7 @@
#include "content/public/common/content_client.h"
#include "content/public/common/referrer.h"
#include "jni/DownloadController_jni.h"
+#include "net/base/filename_util.h"
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_content_disposition.h"
@@ -97,6 +98,17 @@ void CreateContextMenuDownload(int render_process_id,
dlm->DownloadUrl(std::move(dl_params));
}
+// Check if an interrupted download item can be auto resumed.
+bool IsInterruptedDownloadAutoResumable(content::DownloadItem* download_item) {
+ int interrupt_reason = download_item->GetLastReason();
+ DCHECK_NE(interrupt_reason, content::DOWNLOAD_INTERRUPT_REASON_NONE);
+ return
+ interrupt_reason == content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT ||
+ interrupt_reason == content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED ||
+ interrupt_reason ==
+ content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED;
+}
+
} // namespace
namespace content {
@@ -211,6 +223,11 @@ void DownloadControllerAndroidImpl::AcquireFileAccessPermission(
env, GetJavaObject()->Controller(env).obj(), view.obj(), callback_id);
}
+void DownloadControllerAndroidImpl::SetDefaultDownloadFileName(
+ const std::string& file_name) {
+ default_file_name_ = file_name;
+}
+
bool DownloadControllerAndroidImpl::HasFileAccessPermission(
ScopedJavaLocalRef<jobject> j_content_view_core) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -222,7 +239,8 @@ bool DownloadControllerAndroidImpl::HasFileAccessPermission(
}
void DownloadControllerAndroidImpl::CreateGETDownload(
- int render_process_id, int render_view_id, int request_id) {
+ int render_process_id, int render_view_id, int request_id,
+ bool must_download) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
GlobalRequestID global_id(render_process_id, request_id);
@@ -232,7 +250,7 @@ void DownloadControllerAndroidImpl::CreateGETDownload(
GetDownloadInfoCB cb = base::Bind(
&DownloadControllerAndroidImpl::StartAndroidDownload,
base::Unretained(this), render_process_id,
- render_view_id);
+ render_view_id, must_download);
PrepareDownloadInfo(
global_id,
@@ -326,7 +344,7 @@ void DownloadControllerAndroidImpl::StartDownloadOnUIThread(
}
void DownloadControllerAndroidImpl::StartAndroidDownload(
- int render_process_id, int render_view_id,
+ int render_process_id, int render_view_id, bool must_download,
const DownloadInfoAndroid& info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -346,7 +364,7 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
web_contents,
base::Bind(&DownloadControllerAndroidImpl::StartAndroidDownload,
base::Unretained(this), render_process_id, render_view_id,
- info)));
+ must_download, info)));
return;
}
@@ -354,11 +372,11 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
web_contents,
base::Bind(&DownloadControllerAndroidImpl::StartAndroidDownloadInternal,
base::Unretained(this), render_process_id, render_view_id,
- info));
+ must_download, info));
}
void DownloadControllerAndroidImpl::StartAndroidDownloadInternal(
- int render_process_id, int render_view_id,
+ int render_process_id, int render_view_id, bool must_download,
const DownloadInfoAndroid& info, bool allowed) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!allowed)
@@ -388,17 +406,20 @@ void DownloadControllerAndroidImpl::StartAndroidDownloadInternal(
ScopedJavaLocalRef<jstring> jreferer =
ConvertUTF8ToJavaString(env, info.referer);
- // Try parsing the content disposition header to get a
- // explicitly specified filename if available.
- net::HttpContentDisposition header(info.content_disposition, "");
+ // net::GetSuggestedFilename will fallback to "download" as filename.
ScopedJavaLocalRef<jstring> jfilename =
- ConvertUTF8ToJavaString(env, header.filename());
+ base::android::ConvertUTF16ToJavaString(
+ env, net::GetSuggestedFilename(info.url, info.content_disposition,
+ std::string(), // referrer_charset
+ std::string(), // suggested_name
+ info.original_mime_type,
+ default_file_name_));
Java_DownloadController_newHttpGetDownload(
env, GetJavaObject()->Controller(env).obj(), view.obj(), jurl.obj(),
juser_agent.obj(), jcontent_disposition.obj(), jmime_type.obj(),
jcookie.obj(), jreferer.obj(), info.has_user_gesture, jfilename.obj(),
- info.total_bytes);
+ info.total_bytes, must_download);
}
void DownloadControllerAndroidImpl::OnDownloadStarted(
@@ -433,6 +454,8 @@ void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) {
OnDangerousDownload(item);
JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> jguid =
+ ConvertUTF8ToJavaString(env, item->GetGuid());
ScopedJavaLocalRef<jstring> jurl =
ConvertUTF8ToJavaString(env, item->GetURL().spec());
ScopedJavaLocalRef<jstring> jmime_type =
@@ -441,17 +464,22 @@ void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) {
ConvertUTF8ToJavaString(env, item->GetTargetFilePath().value());
ScopedJavaLocalRef<jstring> jfilename = ConvertUTF8ToJavaString(
env, item->GetTargetFilePath().BaseName().value());
+ ScopedJavaLocalRef<jstring> joriginal_url =
+ ConvertUTF8ToJavaString(env, item->GetOriginalUrl().spec());
+ ScopedJavaLocalRef<jstring> jreferrer_url =
+ ConvertUTF8ToJavaString(env, item->GetReferrerUrl().spec());
switch (item->GetState()) {
case DownloadItem::IN_PROGRESS: {
base::TimeDelta time_delta;
item->TimeRemaining(&time_delta);
Java_DownloadController_onDownloadUpdated(
- env, GetJavaObject()->Controller(env).obj(),
- base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(),
- jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true,
- item->GetId(), item->PercentComplete(), time_delta.InMilliseconds(),
- item->HasUserGesture());
+ env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
+ jmime_type.obj(), jfilename.obj(), jpath.obj(),
+ item->GetReceivedBytes(), item->GetId(), jguid.obj(),
+ item->PercentComplete(), time_delta.InMilliseconds(),
+ item->HasUserGesture(), item->IsPaused(),
+ item->GetBrowserContext()->IsOffTheRecord());
break;
}
case DownloadItem::COMPLETE:
@@ -461,22 +489,27 @@ void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) {
// Call onDownloadCompleted
Java_DownloadController_onDownloadCompleted(
- env, GetJavaObject()->Controller(env).obj(),
- base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(),
- jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true,
- item->GetId(), item->HasUserGesture());
+ env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
+ jmime_type.obj(), jfilename.obj(), jpath.obj(),
+ item->GetReceivedBytes(), item->GetId(), jguid.obj(),
+ joriginal_url.obj(), jreferrer_url.obj(), item->HasUserGesture());
break;
case DownloadItem::CANCELLED:
- // TODO(shashishekhar): An interrupted download can be resumed. Android
- // currently does not support resumable downloads. Add handling for
- // interrupted case based on item->CanResume().
+ Java_DownloadController_onDownloadCancelled(
+ env, GetJavaObject()->Controller(env).obj(), item->GetId(),
+ jguid.obj());
+ break;
case DownloadItem::INTERRUPTED:
- // Call onDownloadCompleted with success = false.
- Java_DownloadController_onDownloadCompleted(
- env, GetJavaObject()->Controller(env).obj(),
- base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(),
- jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), false,
- item->GetId(), item->HasUserGesture());
+ // When device loses/changes network, we get a NETWORK_TIMEOUT,
+ // NETWORK_FAILED or NETWORK_DISCONNECTED error. Download should auto
+ // resume in this case.
+ Java_DownloadController_onDownloadInterrupted(
+ env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
+ jmime_type.obj(), jfilename.obj(), jpath.obj(),
+ item->GetReceivedBytes(), item->GetId(), jguid.obj(),
+ item->CanResume(), IsInterruptedDownloadAutoResumable(item),
+ item->GetBrowserContext()->IsOffTheRecord());
+ item->RemoveObserver(this);
break;
case DownloadItem::MAX_DOWNLOAD_STATE:
NOTREACHED();
@@ -487,12 +520,14 @@ void DownloadControllerAndroidImpl::OnDangerousDownload(DownloadItem* item) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> jfilename = ConvertUTF8ToJavaString(
env, item->GetTargetFilePath().BaseName().value());
+ ScopedJavaLocalRef<jstring> jguid =
+ ConvertUTF8ToJavaString(env, item->GetGuid());
ScopedJavaLocalRef<jobject> view_core = GetContentViewCoreFromWebContents(
item->GetWebContents());
if (!view_core.is_null()) {
Java_DownloadController_onDangerousDownload(
env, GetJavaObject()->Controller(env).obj(), view_core.obj(),
- jfilename.obj(), item->GetId());
+ jfilename.obj(), jguid.obj());
}
}
@@ -532,12 +567,14 @@ void DownloadControllerAndroidImpl::StartContextMenuDownload(
}
void DownloadControllerAndroidImpl::DangerousDownloadValidated(
- WebContents* web_contents, int download_id, bool accept) {
+ WebContents* web_contents,
+ const std::string& download_guid,
+ bool accept) {
if (!web_contents)
return;
DownloadManagerImpl* dlm = static_cast<DownloadManagerImpl*>(
BrowserContext::GetDownloadManager(web_contents->GetBrowserContext()));
- DownloadItem* item = dlm->GetDownload(download_id);
+ DownloadItem* item = dlm->GetDownloadByGuid(download_guid);
if (!item)
return;
if (accept)
diff --git a/chromium/content/browser/android/download_controller_android_impl.h b/chromium/content/browser/android/download_controller_android_impl.h
index 36c108e349d..157f306300d 100644
--- a/chromium/content/browser/android/download_controller_android_impl.h
+++ b/chromium/content/browser/android/download_controller_android_impl.h
@@ -30,7 +30,6 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/singleton.h"
#include "content/public/browser/android/download_controller_android.h"
-#include "content/public/browser/download_item.h"
#include "net/cookies/cookie_monster.h"
#include "url/gurl.h"
@@ -44,8 +43,7 @@ class DeferredDownloadObserver;
class RenderViewHost;
class WebContents;
-class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
- public DownloadItem::Observer {
+class DownloadControllerAndroidImpl : public DownloadControllerAndroid {
public:
static DownloadControllerAndroidImpl* GetInstance();
@@ -61,6 +59,7 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
void AcquireFileAccessPermission(
WebContents* web_contents,
const AcquireFileAccessPermissionCallback& callback) override;
+ void SetDefaultDownloadFileName(const std::string& file_name) override;
private:
// Used to store all the information about an Android download.
@@ -96,14 +95,15 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
// DownloadControllerAndroid implementation.
void CreateGETDownload(int render_process_id,
int render_view_id,
- int request_id) override;
+ int request_id,
+ bool must_download) override;
void OnDownloadStarted(DownloadItem* download_item) override;
void StartContextMenuDownload(const ContextMenuParams& params,
WebContents* web_contents,
bool is_link,
const std::string& extra_headers) override;
void DangerousDownloadValidated(WebContents* web_contents,
- int download_id,
+ const std::string& download_guid,
bool accept) override;
// DownloadItem::Observer interface.
@@ -127,9 +127,11 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
const DownloadInfoAndroid& info);
void StartAndroidDownload(int render_process_id,
int render_view_id,
+ bool must_download,
const DownloadInfoAndroid& info);
void StartAndroidDownloadInternal(int render_process_id,
int render_view_id,
+ bool must_download,
const DownloadInfoAndroid& info,
bool allowed);
@@ -144,6 +146,8 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
JavaObject* java_object_;
+ std::string default_file_name_;
+
ScopedVector<DeferredDownloadObserver> deferred_downloads_;
DISALLOW_COPY_AND_ASSIGN(DownloadControllerAndroidImpl);
diff --git a/chromium/content/browser/android/in_process/context_provider_in_process.cc b/chromium/content/browser/android/in_process/context_provider_in_process.cc
index 9f4fbc2d827..e7cbb65e0f2 100644
--- a/chromium/content/browser/android/in_process/context_provider_in_process.cc
+++ b/chromium/content/browser/android/in_process/context_provider_in_process.cc
@@ -11,7 +11,7 @@
#include "base/callback_helpers.h"
#include "base/strings/stringprintf.h"
#include "cc/output/managed_memory_policy.h"
-#include "content/common/gpu/client/grcontext_for_webgraphicscontext3d.h"
+#include "content/common/gpu/client/grcontext_for_gles2_interface.h"
#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "third_party/skia/include/gpu/GrContext.h"
@@ -25,11 +25,11 @@ class ContextProviderInProcess::LostContextCallbackProxy
public:
explicit LostContextCallbackProxy(ContextProviderInProcess* provider)
: provider_(provider) {
- provider_->WebContext3DImpl()->setContextLostCallback(this);
+ provider_->context3d_->setContextLostCallback(this);
}
~LostContextCallbackProxy() override {
- provider_->WebContext3DImpl()->setContextLostCallback(NULL);
+ provider_->context3d_->setContextLostCallback(nullptr);
}
void onContextLost() override {
@@ -45,19 +45,16 @@ scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
const std::string& debug_name) {
if (!context3d)
- return NULL;
+ return nullptr;
return new ContextProviderInProcess(std::move(context3d), debug_name);
}
ContextProviderInProcess::ContextProviderInProcess(
scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
const std::string& debug_name)
- : debug_name_(debug_name) {
+ : context3d_(std::move(context3d)), debug_name_(debug_name) {
DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK(context3d);
- gr_interface_ = skia::AdoptRef(
- new GrGLInterfaceForWebGraphicsContext3D(std::move(context3d)));
- DCHECK(gr_interface_->WebContext3D());
+ DCHECK(context3d_);
context_thread_checker_.DetachFromThread();
}
@@ -70,20 +67,11 @@ blink::WebGraphicsContext3D* ContextProviderInProcess::WebContext3D() {
DCHECK(lost_context_callback_proxy_); // Is bound to thread.
DCHECK(context_thread_checker_.CalledOnValidThread());
- return WebContext3DImpl();
-}
-
-gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
- ContextProviderInProcess::WebContext3DImpl() {
- DCHECK(gr_interface_->WebContext3D());
-
- return
- static_cast<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*>(
- gr_interface_->WebContext3D());
+ return context3d_.get();
}
bool ContextProviderInProcess::BindToCurrentThread() {
- DCHECK(WebContext3DImpl());
+ DCHECK(context3d_);
// This is called on the thread the context will be used.
DCHECK(context_thread_checker_.CalledOnValidThread());
@@ -91,16 +79,14 @@ bool ContextProviderInProcess::BindToCurrentThread() {
if (lost_context_callback_proxy_)
return true;
- if (!WebContext3DImpl()->InitializeOnCurrentThread())
+ if (!context3d_->InitializeOnCurrentThread())
return false;
- gr_interface_->BindToCurrentThread();
InitializeCapabilities();
const std::string unique_context_name =
- base::StringPrintf("%s-%p", debug_name_.c_str(), WebContext3DImpl());
- WebContext3DImpl()->traceBeginCHROMIUM("gpu_toplevel",
- unique_context_name.c_str());
+ base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
+ ContextGL()->TraceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str());
lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
return true;
@@ -111,9 +97,9 @@ void ContextProviderInProcess::DetachFromThread() {
}
void ContextProviderInProcess::InitializeCapabilities() {
- capabilities_.gpu = WebContext3DImpl()->GetImplementation()->capabilities();
+ capabilities_.gpu = context3d_->GetImplementation()->capabilities();
- size_t mapped_memory_limit = WebContext3DImpl()->GetMappedMemoryLimit();
+ size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
capabilities_.max_transfer_buffer_usage_bytes =
mapped_memory_limit ==
WebGraphicsContext3DInProcessCommandBufferImpl::kNoLimit
@@ -129,21 +115,21 @@ ContextProviderInProcess::ContextCapabilities() {
}
::gpu::gles2::GLES2Interface* ContextProviderInProcess::ContextGL() {
- DCHECK(WebContext3DImpl());
+ DCHECK(context3d_);
DCHECK(lost_context_callback_proxy_); // Is bound to thread.
DCHECK(context_thread_checker_.CalledOnValidThread());
- return WebContext3DImpl()->GetGLInterface();
+ return context3d_->GetGLInterface();
}
::gpu::ContextSupport* ContextProviderInProcess::ContextSupport() {
- DCHECK(WebContext3DImpl());
+ DCHECK(context3d_);
if (!lost_context_callback_proxy_)
return NULL; // Not bound to anything.
DCHECK(context_thread_checker_.CalledOnValidThread());
- return WebContext3DImpl()->GetContextSupport();
+ return context3d_->GetContextSupport();
}
class GrContext* ContextProviderInProcess::GrContext() {
@@ -153,7 +139,8 @@ class GrContext* ContextProviderInProcess::GrContext() {
if (gr_context_)
return gr_context_->get();
- gr_context_.reset(new GrContextForWebGraphicsContext3D(gr_interface_));
+ gr_context_.reset(
+ new GrContextForGLES2Interface(context3d_->GetGLInterface()));
return gr_context_->get();
}
@@ -166,7 +153,7 @@ void ContextProviderInProcess::InvalidateGrContext(uint32_t state) {
}
void ContextProviderInProcess::SetupLock() {
- WebContext3DImpl()->SetLock(&context_lock_);
+ context3d_->SetLock(&context_lock_);
}
base::Lock* ContextProviderInProcess::GetLock() {
diff --git a/chromium/content/browser/android/in_process/context_provider_in_process.h b/chromium/content/browser/android/in_process/context_provider_in_process.h
index fe24f945003..37f494afcb1 100644
--- a/chromium/content/browser/android/in_process/context_provider_in_process.h
+++ b/chromium/content/browser/android/in_process/context_provider_in_process.h
@@ -14,7 +14,6 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "cc/blink/context_provider_web_context.h"
-#include "skia/ext/refptr.h"
namespace blink { class WebGraphicsContext3D; }
@@ -24,8 +23,7 @@ class WebGraphicsContext3DInProcessCommandBufferImpl;
namespace content {
-class GrContextForWebGraphicsContext3D;
-class GrGLInterfaceForWebGraphicsContext3D;
+class GrContextForGLES2Interface;
class ContextProviderInProcess
: NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
@@ -45,8 +43,6 @@ class ContextProviderInProcess
// cc_blink::ContextProviderWebContext:
blink::WebGraphicsContext3D* WebContext3D() override;
- gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl* WebContext3DImpl();
-
// cc::ContextProvider:
bool BindToCurrentThread() override;
void DetachFromThread() override;
@@ -67,8 +63,9 @@ class ContextProviderInProcess
base::ThreadChecker main_thread_checker_;
base::ThreadChecker context_thread_checker_;
- skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface_;
- scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_;
+ scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
+ context3d_;
+ scoped_ptr<GrContextForGLES2Interface> gr_context_;
LostContextCallback lost_context_callback_;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc b/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
index 628bfccf6a2..4e5f3f132ea 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
@@ -17,7 +17,6 @@
#include "content/browser/android/in_process/synchronous_compositor_registry_in_proc.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
@@ -29,6 +28,7 @@
#include "gpu/command_buffer/client/gl_in_process_context.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_stub.h"
@@ -46,30 +46,15 @@ struct ContextHolder {
gpu::GLInProcessContext* gl_in_process_context;
};
-blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
- blink::WebGraphicsContext3D::Attributes attributes;
- attributes.antialias = false;
- attributes.depth = false;
- attributes.stencil = false;
- attributes.shareResources = true;
- attributes.noAutomaticFlushes = true;
-
- return attributes;
-}
-
ContextHolder CreateContextHolder(
- const blink::WebGraphicsContext3D::Attributes& attributes,
+ const gpu::gles2::ContextCreationAttribHelper& attributes,
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
- const gpu::GLInProcessContextSharedMemoryLimits& mem_limits,
- bool is_offscreen) {
- gpu::gles2::ContextCreationAttribHelper in_process_attribs;
- WebGraphicsContext3DImpl::ConvertAttributes(attributes, &in_process_attribs);
- in_process_attribs.lose_context_when_out_of_memory = true;
-
+ const gpu::GLInProcessContextSharedMemoryLimits& mem_limits) {
+ bool is_offscreen = true;
scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
- service, NULL /* surface */, is_offscreen, gfx::kNullAcceleratedWidget,
- gfx::Size(1, 1), NULL /* share_context */, attributes.shareResources,
- in_process_attribs, gfx::PreferDiscreteGpu, mem_limits,
+ service, nullptr /* surface */, is_offscreen, gfx::kNullAcceleratedWidget,
+ gfx::Size(1, 1), nullptr /* share_context */, attributes,
+ gfx::PreferDiscreteGpu, mem_limits,
BrowserGpuMemoryBufferManager::current(), nullptr));
gpu::GLInProcessContext* context_ptr = context.get();
@@ -86,12 +71,58 @@ ContextHolder CreateContextHolder(
} // namespace
-class SynchronousCompositorFactoryImpl::VideoContextProvider
+SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess)) {
+ // TODO(boliu): Figure out how to deal with this more nicely.
+ SynchronousCompositorFactory::SetInstance(this);
+ }
+}
+
+SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+SynchronousCompositorFactoryImpl::GetCompositorTaskRunner() {
+ return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
+}
+
+scoped_ptr<cc::OutputSurface>
+SynchronousCompositorFactoryImpl::CreateOutputSurface(
+ int routing_id,
+ uint32_t output_surface_id,
+ const scoped_refptr<FrameSwapMessageQueue>& frame_swap_message_queue,
+ const scoped_refptr<cc::ContextProvider>& onscreen_context,
+ const scoped_refptr<cc::ContextProvider>& worker_context) {
+ return make_scoped_ptr(new SynchronousCompositorOutputSurface(
+ onscreen_context, worker_context, routing_id, output_surface_id,
+ SynchronousCompositorRegistryInProc::GetInstance(),
+ frame_swap_message_queue));
+}
+
+InputHandlerManagerClient*
+SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
+ return synchronous_input_event_filter();
+}
+
+SynchronousInputHandlerProxyClient*
+SynchronousCompositorFactoryImpl::GetSynchronousInputHandlerProxyClient() {
+ return synchronous_input_event_filter();
+}
+
+scoped_ptr<cc::BeginFrameSource>
+SynchronousCompositorFactoryImpl::CreateExternalBeginFrameSource(
+ int routing_id) {
+ return make_scoped_ptr(new SynchronousCompositorExternalBeginFrameSource(
+ routing_id, SynchronousCompositorRegistryInProc::GetInstance()));
+}
+
+// SynchronousCompositorStreamTextureFactoryImpl.
+
+class SynchronousCompositorStreamTextureFactoryImpl::VideoContextProvider
: public StreamTextureFactorySynchronousImpl::ContextProvider {
public:
- VideoContextProvider(
- scoped_refptr<cc::ContextProvider> context_provider,
- gpu::GLInProcessContext* gl_in_process_context)
+ VideoContextProvider(scoped_refptr<cc::ContextProvider> context_provider,
+ gpu::GLInProcessContext* gl_in_process_context)
: context_provider_(context_provider),
gl_in_process_context_(gl_in_process_context) {
context_provider_->BindToCurrentThread();
@@ -119,8 +150,7 @@ class SynchronousCompositorFactoryImpl::VideoContextProvider
}
void RestoreContext() {
- FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
- observer_list_,
+ FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver, observer_list_,
ResetStreamTextureProxy());
}
@@ -135,87 +165,62 @@ class SynchronousCompositorFactoryImpl::VideoContextProvider
DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
};
-SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
- : num_hardware_compositors_(0) {
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kSingleProcess)) {
- // TODO(boliu): Figure out how to deal with this more nicely.
- SynchronousCompositorFactory::SetInstance(this);
- }
-}
-
-SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-SynchronousCompositorFactoryImpl::GetCompositorTaskRunner() {
- return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
-}
-
-scoped_ptr<cc::OutputSurface>
-SynchronousCompositorFactoryImpl::CreateOutputSurface(
- int routing_id,
- const scoped_refptr<FrameSwapMessageQueue>& frame_swap_message_queue,
- const scoped_refptr<cc::ContextProvider>& onscreen_context,
- const scoped_refptr<cc::ContextProvider>& worker_context) {
- return make_scoped_ptr(new SynchronousCompositorOutputSurface(
- onscreen_context, worker_context, routing_id,
- SynchronousCompositorRegistryInProc::GetInstance(),
- frame_swap_message_queue));
-}
+namespace {
+base::LazyInstance<SynchronousCompositorStreamTextureFactoryImpl>::Leaky
+ g_stream_texture_factory = LAZY_INSTANCE_INITIALIZER;
+} // namespace
-InputHandlerManagerClient*
-SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
- return synchronous_input_event_filter();
+// static
+SynchronousCompositorStreamTextureFactoryImpl*
+SynchronousCompositorStreamTextureFactoryImpl::GetInstance() {
+ return g_stream_texture_factory.Pointer();
}
-scoped_ptr<cc::BeginFrameSource>
-SynchronousCompositorFactoryImpl::CreateExternalBeginFrameSource(
- int routing_id) {
- return make_scoped_ptr(new SynchronousCompositorExternalBeginFrameSource(
- routing_id, SynchronousCompositorRegistryInProc::GetInstance()));
-}
+SynchronousCompositorStreamTextureFactoryImpl::
+ SynchronousCompositorStreamTextureFactoryImpl()
+ : num_hardware_compositors_(0) {}
scoped_refptr<StreamTextureFactory>
-SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) {
- scoped_refptr<StreamTextureFactorySynchronousImpl> factory(
- StreamTextureFactorySynchronousImpl::Create(
- base::Bind(
- &SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory,
- base::Unretained(this)),
- frame_id));
- return factory;
+SynchronousCompositorStreamTextureFactoryImpl::CreateStreamTextureFactory() {
+ return StreamTextureFactorySynchronousImpl::Create(
+ base::Bind(&SynchronousCompositorStreamTextureFactoryImpl::
+ TryCreateStreamTextureFactory,
+ base::Unretained(this)));
}
-void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() {
+void SynchronousCompositorStreamTextureFactoryImpl::
+ CompositorInitializedHardwareDraw() {
base::AutoLock lock(num_hardware_compositor_lock_);
num_hardware_compositors_++;
if (num_hardware_compositors_ == 1 && main_thread_task_runner_.get()) {
main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &SynchronousCompositorFactoryImpl::RestoreContextOnMainThread,
- base::Unretained(this)));
+ FROM_HERE, base::Bind(&SynchronousCompositorStreamTextureFactoryImpl::
+ RestoreContextOnMainThread,
+ base::Unretained(this)));
}
}
-void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
+void SynchronousCompositorStreamTextureFactoryImpl::
+ CompositorReleasedHardwareDraw() {
base::AutoLock lock(num_hardware_compositor_lock_);
DCHECK_GT(num_hardware_compositors_, 0u);
num_hardware_compositors_--;
}
-void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
+void SynchronousCompositorStreamTextureFactoryImpl::
+ RestoreContextOnMainThread() {
if (CanCreateMainThreadContext() && video_context_provider_.get())
video_context_provider_->RestoreContext();
}
-bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
+bool SynchronousCompositorStreamTextureFactoryImpl::
+ CanCreateMainThreadContext() {
base::AutoLock lock(num_hardware_compositor_lock_);
return num_hardware_compositors_ > 0;
}
scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
-SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
+SynchronousCompositorStreamTextureFactoryImpl::TryCreateStreamTextureFactory() {
{
base::AutoLock lock(num_hardware_compositor_lock_);
main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
@@ -226,20 +231,29 @@ SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
// |video_context_provider_| to null is also not safe since it makes
// synchronous destruction uncontrolled and possibly deadlock.
if (!CanCreateMainThreadContext()) {
- return
- scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>();
+ return scoped_refptr<
+ StreamTextureFactorySynchronousImpl::ContextProvider>();
}
if (!video_context_provider_.get()) {
DCHECK(android_view_service_.get());
- blink::WebGraphicsContext3D::Attributes attributes = GetDefaultAttribs();
- attributes.shareResources = false;
+ // This is for an offscreen context, so the default framebuffer doesn't need
+ // any alpha, depth, stencil, antialiasing.
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = -1;
+ attributes.depth_size = 0;
+ attributes.stencil_size = 0;
+ attributes.samples = 0;
+ attributes.sample_buffers = 0;
+ attributes.bind_generates_resource = false;
+ attributes.lose_context_when_out_of_memory = true;
+
// This needs to run in on-screen |android_view_service_| context due to
// SurfaceTexture limitations.
ContextHolder holder =
CreateContextHolder(attributes, android_view_service_,
- gpu::GLInProcessContextSharedMemoryLimits(), false);
+ gpu::GLInProcessContextSharedMemoryLimits());
video_context_provider_ = new VideoContextProvider(
ContextProviderInProcess::Create(std::move(holder.command_buffer),
"Video-Offscreen-main-thread"),
@@ -248,10 +262,15 @@ SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
return video_context_provider_;
}
-void SynchronousCompositorFactoryImpl::SetDeferredGpuService(
+void SynchronousCompositorStreamTextureFactoryImpl::SetDeferredGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
DCHECK(!android_view_service_.get());
android_view_service_ = service;
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess)) {
+ RenderThreadImpl::SetStreamTextureFactory(CreateStreamTextureFactory());
+ }
}
} // namespace content
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h b/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h
index 03533444a3e..4842e85f30e 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_FACTORY_IMPL_H_
#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_FACTORY_IMPL_H_
+#include "base/lazy_instance.h"
#include "base/synchronization/lock.h"
#include "cc/blink/context_provider_web_context.h"
#include "content/browser/android/in_process/synchronous_input_event_filter.h"
@@ -40,34 +41,46 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
override;
scoped_ptr<cc::OutputSurface> CreateOutputSurface(
int routing_id,
+ uint32_t output_surface_id,
const scoped_refptr<FrameSwapMessageQueue>& frame_swap_message_queue,
const scoped_refptr<cc::ContextProvider>& onscreen_context,
const scoped_refptr<cc::ContextProvider>& worker_context) override;
InputHandlerManagerClient* GetInputHandlerManagerClient() override;
+ SynchronousInputHandlerProxyClient* GetSynchronousInputHandlerProxyClient()
+ override;
scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
int routing_id) override;
- scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
- int frame_id) override;
SynchronousInputEventFilter* synchronous_input_event_filter() {
return &synchronous_input_event_filter_;
}
+ private:
+ SynchronousInputEventFilter synchronous_input_event_filter_;
+};
+
+class SynchronousCompositorStreamTextureFactoryImpl {
+ public:
+ static SynchronousCompositorStreamTextureFactoryImpl* GetInstance();
+
+ scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory();
void SetDeferredGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service);
void CompositorInitializedHardwareDraw();
void CompositorReleasedHardwareDraw();
-
private:
- scoped_refptr<cc::ContextProvider> GetSharedWorkerContextProvider();
+ friend struct base::DefaultLazyInstanceTraits<
+ SynchronousCompositorStreamTextureFactoryImpl>;
+
+ SynchronousCompositorStreamTextureFactoryImpl();
+ ~SynchronousCompositorStreamTextureFactoryImpl();
+
bool CanCreateMainThreadContext();
scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
TryCreateStreamTextureFactory();
void RestoreContextOnMainThread();
- SynchronousInputEventFilter synchronous_input_event_filter_;
-
scoped_refptr<gpu::InProcessCommandBuffer::Service> android_view_service_;
class VideoContextProvider;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc b/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
index e1791374ed2..f1829890a09 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -108,12 +108,6 @@ void SynchronousCompositorImpl::RegisterWithClient() {
synchronous_input_handler_proxy_->SetOnlySynchronouslyAnimateRootFlings(this);
}
-// static
-void SynchronousCompositorImpl::SetGpuServiceInProc(
- scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
- g_factory.Get().SetDeferredGpuService(service);
-}
-
void SynchronousCompositorImpl::DidInitializeRendererObjects(
SynchronousCompositorOutputSurface* output_surface,
SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
@@ -156,7 +150,7 @@ void SynchronousCompositorImpl::DidDestroyRendererObjects() {
need_animate_input_ = false;
}
-scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
+SynchronousCompositor::Frame SynchronousCompositorImpl::DemandDrawHw(
const gfx::Size& surface_size,
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -166,45 +160,48 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
DCHECK(begin_frame_source_);
- DCHECK(!frame_holder_);
+ DCHECK(!frame_holder_.frame);
output_surface_->DemandDrawHw(surface_size, transform, viewport, clip,
viewport_rect_for_tile_priority,
transform_for_tile_priority);
- if (frame_holder_)
- UpdateFrameMetaData(frame_holder_->metadata);
+ if (frame_holder_.frame)
+ UpdateFrameMetaData(frame_holder_.frame->metadata);
return std::move(frame_holder_);
}
void SynchronousCompositorImpl::ReturnResources(
+ uint32_t output_surface_id,
const cc::CompositorFrameAck& frame_ack) {
DCHECK(CalledOnValidThread());
- output_surface_->ReturnResources(frame_ack);
+ output_surface_->ReturnResources(output_surface_id, frame_ack);
}
bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
DCHECK(begin_frame_source_);
- DCHECK(!frame_holder_);
+ DCHECK(!frame_holder_.frame);
output_surface_->DemandDrawSw(canvas);
- bool success = !!frame_holder_;
- if (frame_holder_) {
- UpdateFrameMetaData(frame_holder_->metadata);
- frame_holder_.reset();
+ bool success = !!frame_holder_.frame;
+ if (frame_holder_.frame) {
+ UpdateFrameMetaData(frame_holder_.frame->metadata);
+ frame_holder_.frame.reset();
}
return success;
}
-void SynchronousCompositorImpl::SwapBuffers(cc::CompositorFrame* frame) {
- DCHECK(!frame_holder_);
- frame_holder_.reset(new cc::CompositorFrame);
- frame->AssignTo(frame_holder_.get());
+void SynchronousCompositorImpl::SwapBuffers(uint32_t output_surface_id,
+ cc::CompositorFrame* frame) {
+ DCHECK(!frame_holder_.frame);
+ frame_holder_.output_surface_id = output_surface_id;
+ frame_holder_.frame.reset(new cc::CompositorFrame);
+ frame->AssignTo(frame_holder_.frame.get());
}
void SynchronousCompositorImpl::UpdateFrameMetaData(
@@ -221,9 +218,11 @@ void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
output_surface_->SetMemoryPolicy(bytes_limit);
if (bytes_limit && !current_bytes_limit) {
- g_factory.Get().CompositorInitializedHardwareDraw();
+ SynchronousCompositorStreamTextureFactoryImpl::GetInstance()
+ ->CompositorInitializedHardwareDraw();
} else if (!bytes_limit && current_bytes_limit) {
- g_factory.Get().CompositorReleasedHardwareDraw();
+ SynchronousCompositorStreamTextureFactoryImpl::GetInstance()
+ ->CompositorReleasedHardwareDraw();
}
}
@@ -242,6 +241,14 @@ void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset(
root_offset);
}
+void SynchronousCompositorImpl::SynchronouslyZoomBy(float zoom_delta,
+ const gfx::Point& anchor) {
+ DCHECK(CalledOnValidThread());
+ if (!synchronous_input_handler_proxy_)
+ return;
+ synchronous_input_handler_proxy_->SynchronouslyZoomBy(zoom_delta, anchor);
+}
+
void SynchronousCompositorImpl::SetIsActive(bool is_active) {
TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
is_active);
@@ -283,7 +290,7 @@ void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
rwhva_->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_);
}
-void SynchronousCompositorImpl::DidOverscroll(
+void SynchronousCompositorImpl::DidOverscrollInProcess(
const DidOverscrollParams& params) {
if (registered_with_client_) {
compositor_client_->DidOverscroll(params.accumulated_overscroll,
@@ -307,6 +314,13 @@ InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
routing_id_, input_event);
}
+void SynchronousCompositorImpl::DidOverscroll(
+ const DidOverscrollParams& params) {
+ // SynchronousCompositorImpl uses synchronous DidOverscrollInProcess for
+ // overscroll instead of this async path.
+ NOTREACHED();
+}
+
bool SynchronousCompositorImpl::OnMessageReceived(const IPC::Message& message) {
NOTREACHED();
return false;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_impl.h b/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
index e5a14611d8c..29f48d2a707 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -43,9 +43,6 @@ class SynchronousCompositorImpl
// is implicitly that of the in-process renderer.
static SynchronousCompositorImpl* FromRoutingID(int routing_id);
- static void SetGpuServiceInProc(
- scoped_refptr<gpu::InProcessCommandBuffer::Service> service);
-
~SynchronousCompositorImpl() override;
// Called by SynchronousCompositorRegistry.
@@ -60,10 +57,11 @@ class SynchronousCompositorImpl
// SynchronousCompositorOutputSurfaceClient overrides.
void Invalidate() override;
- void SwapBuffers(cc::CompositorFrame* frame) override;
+ void SwapBuffers(uint32_t output_surface_id,
+ cc::CompositorFrame* frame) override;
// SynchronousCompositor overrides.
- scoped_ptr<cc::CompositorFrame> DemandDrawHw(
+ SynchronousCompositor::Frame DemandDrawHw(
const gfx::Size& surface_size,
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -71,10 +69,12 @@ class SynchronousCompositorImpl
const gfx::Rect& viewport_rect_for_tile_priority,
const gfx::Transform& transform_for_tile_priority) override;
bool DemandDrawSw(SkCanvas* canvas) override;
- void ReturnResources(const cc::CompositorFrameAck& frame_ack) override;
+ void ReturnResources(uint32_t output_surface_id,
+ const cc::CompositorFrameAck& frame_ack) override;
void SetMemoryPolicy(size_t bytes_limit) override;
void DidChangeRootLayerScrollOffset(
const gfx::ScrollOffset& root_offset) override;
+ void SynchronouslyZoomBy(float zoom_delta, const gfx::Point& anchor) override;
void SetIsActive(bool is_active) override;
void OnComputeScroll(base::TimeTicks animation_time) override;
@@ -82,6 +82,7 @@ class SynchronousCompositorImpl
void BeginFrame(const cc::BeginFrameArgs& args) override;
InputEventAckState HandleInputEvent(
const blink::WebInputEvent& input_event) override;
+ void DidOverscroll(const DidOverscrollParams& params) override;
bool OnMessageReceived(const IPC::Message& message) override;
void DidBecomeCurrent() override;
@@ -94,7 +95,7 @@ class SynchronousCompositorImpl
float min_page_scale_factor,
float max_page_scale_factor) override;
- void DidOverscroll(const DidOverscrollParams& params);
+ void DidOverscrollInProcess(const DidOverscrollParams& params);
void DidStopFlinging();
private:
@@ -118,7 +119,7 @@ class SynchronousCompositorImpl
bool is_active_;
bool renderer_needs_begin_frames_;
bool need_animate_input_;
- scoped_ptr<cc::CompositorFrame> frame_holder_;
+ SynchronousCompositor::Frame frame_holder_;
base::WeakPtrFactory<SynchronousCompositorImpl> weak_ptr_factory_;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.cc b/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.cc
new file mode 100644
index 00000000000..38056fbd7ac
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.cc
@@ -0,0 +1,15 @@
+// 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 "content/browser/android/in_process/synchronous_compositor_renderer_statics.h"
+
+#include "content/renderer/android/synchronous_compositor_proxy.h"
+
+namespace content {
+
+void SynchronousCompositorSetSkCanvas(SkCanvas* canvas) {
+ SynchronousCompositorProxy::SetSkCanvasForDraw(canvas);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.h b/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.h
new file mode 100644
index 00000000000..80823671758
--- /dev/null
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_renderer_statics.h
@@ -0,0 +1,16 @@
+// 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 CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_RENDERER_STATICS_H_
+#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_RENDERER_STATICS_H_
+
+class SkCanvas;
+
+namespace content {
+
+void SynchronousCompositorSetSkCanvas(SkCanvas* canvas);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_RENDERER_STATICS_H_
diff --git a/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc b/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
index 3ce1c61eb4f..b4d9f7fa82b 100644
--- a/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
+++ b/chromium/content/browser/android/in_process/synchronous_input_event_filter.cc
@@ -40,26 +40,15 @@ void SynchronousInputEventFilter::SetBoundHandler(const Handler& handler) {
base::Unretained(this), handler));
}
+void SynchronousInputEventFilter::DidAddInputHandler(int routing_id) {}
+void SynchronousInputEventFilter::DidRemoveInputHandler(int routing_id) {}
+
void SynchronousInputEventFilter::SetBoundHandlerOnUIThread(
const Handler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
handler_ = handler;
}
-void SynchronousInputEventFilter::DidAddInputHandler(
- int routing_id,
- ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- SynchronousCompositorRegistryInProc::GetInstance()->RegisterInputHandler(
- routing_id, synchronous_input_handler_proxy);
-}
-
-void SynchronousInputEventFilter::DidRemoveInputHandler(int routing_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- SynchronousCompositorRegistryInProc::GetInstance()->UnregisterInputHandler(
- routing_id);
-}
-
void SynchronousInputEventFilter::DidOverscroll(
int routing_id,
const DidOverscrollParams& params) {
@@ -68,7 +57,7 @@ void SynchronousInputEventFilter::DidOverscroll(
SynchronousCompositorImpl* compositor =
SynchronousCompositorImpl::FromRoutingID(routing_id);
if (compositor)
- compositor->DidOverscroll(params);
+ compositor->DidOverscrollInProcess(params);
}
void SynchronousInputEventFilter::DidStopFlinging(int routing_id) {
@@ -80,4 +69,23 @@ void SynchronousInputEventFilter::DidStopFlinging(int routing_id) {
compositor->DidStopFlinging();
}
+void SynchronousInputEventFilter::NotifyInputEventHandled(
+ int routing_id,
+ blink::WebInputEvent::Type type) {}
+
+void SynchronousInputEventFilter::DidAddSynchronousHandlerProxy(
+ int routing_id,
+ ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ SynchronousCompositorRegistryInProc::GetInstance()->RegisterInputHandler(
+ routing_id, synchronous_input_handler_proxy);
+}
+
+void SynchronousInputEventFilter::DidRemoveSynchronousHandlerProxy(
+ int routing_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ SynchronousCompositorRegistryInProc::GetInstance()->UnregisterInputHandler(
+ routing_id);
+}
+
} // namespace content
diff --git a/chromium/content/browser/android/in_process/synchronous_input_event_filter.h b/chromium/content/browser/android/in_process/synchronous_input_event_filter.h
index 98375d73bf8..9ecb400ff02 100644
--- a/chromium/content/browser/android/in_process/synchronous_input_event_filter.h
+++ b/chromium/content/browser/android/in_process/synchronous_input_event_filter.h
@@ -26,7 +26,9 @@ namespace content {
// The provided |handler| process WebInputEvents synchronously on the merged
// UI and compositing thread. If the event goes unhandled, that is reflected in
// the InputEventAckState; no forwarding is performed.
-class SynchronousInputEventFilter : public InputHandlerManagerClient {
+class SynchronousInputEventFilter
+ : public InputHandlerManagerClient,
+ public SynchronousInputHandlerProxyClient {
public:
SynchronousInputEventFilter();
~SynchronousInputEventFilter() override;
@@ -36,14 +38,20 @@ class SynchronousInputEventFilter : public InputHandlerManagerClient {
// InputHandlerManagerClient implementation.
void SetBoundHandler(const Handler& handler) override;
- void DidAddInputHandler(
- int routing_id,
- ui::SynchronousInputHandlerProxy*
- synchronous_input_handler_proxy) override;
+ void DidAddInputHandler(int routing_id) override;
void DidRemoveInputHandler(int routing_id) override;
void DidOverscroll(int routing_id,
const DidOverscrollParams& params) override;
void DidStopFlinging(int routing_id) override;
+ void NotifyInputEventHandled(int routing_id,
+ blink::WebInputEvent::Type type) override;
+
+ // SynchronousInputHandlerProxyClient overrides.
+ void DidAddSynchronousHandlerProxy(
+ int routing_id,
+ ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy)
+ override;
+ void DidRemoveSynchronousHandlerProxy(int routing_id) override;
private:
void SetBoundHandlerOnUIThread(const Handler& handler);
diff --git a/chromium/content/browser/android/in_process_surface_texture_manager.h b/chromium/content/browser/android/in_process_surface_texture_manager.h
index 24e951c7b2f..8cf4d2eebdd 100644
--- a/chromium/content/browser/android/in_process_surface_texture_manager.h
+++ b/chromium/content/browser/android/in_process_surface_texture_manager.h
@@ -5,22 +5,22 @@
#ifndef CONTENT_BROWSER_ANDROID_IN_PROCESS_SURFACE_TEXTURE_MANAGER_H_
#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SURFACE_TEXTURE_MANAGER_H_
-#include "content/common/android/surface_texture_manager.h"
+#include "gpu/ipc/common/android/surface_texture_manager.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
-#include "content/common/android/surface_texture_peer.h"
#include "content/common/content_export.h"
+#include "gpu/ipc/common/android/surface_texture_peer.h"
#include "ui/gl/android/scoped_java_surface.h"
namespace content {
class CONTENT_EXPORT InProcessSurfaceTextureManager
- : public SurfaceTextureManager,
- public SurfaceTexturePeer {
+ : public gpu::SurfaceTextureManager,
+ public gpu::SurfaceTexturePeer {
public:
static InProcessSurfaceTextureManager* GetInstance();
diff --git a/chromium/content/browser/android/java/OWNERS b/chromium/content/browser/android/java/OWNERS
index 0cebb68c10c..ce79cad30e2 100644
--- a/chromium/content/browser/android/java/OWNERS
+++ b/chromium/content/browser/android/java/OWNERS
@@ -1,2 +1,2 @@
-mnaganov@chromium.org
+michaelbai@chromium.org
torne@chromium.org
diff --git a/chromium/content/browser/mojo/service_registry_android.cc b/chromium/content/browser/android/service_registry_android_impl.cc
index 0e80e0842b5..e54c3610a29 100644
--- a/chromium/content/browser/mojo/service_registry_android.cc
+++ b/chromium/content/browser/android/service_registry_android_impl.cc
@@ -1,16 +1,18 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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 "content/browser/mojo/service_registry_android.h"
+#include "content/browser/android/service_registry_android_impl.h"
#include <utility>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/callback.h"
-#include "content/common/mojo/service_registry_impl.h"
+#include "base/memory/ptr_util.h"
+#include "content/public/common/service_registry.h"
#include "jni/ServiceRegistry_jni.h"
+#include "mojo/public/cpp/system/message_pipe.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
@@ -28,23 +30,31 @@ void CreateImplAndAttach(
const ScopedJavaGlobalRef<jobject>& j_scoped_factory,
mojo::ScopedMessagePipeHandle handle) {
JNIEnv* env = AttachCurrentThread();
- Java_ServiceRegistry_createImplAndAttach(env,
- j_scoped_service_registry.obj(),
- handle.release().value(),
- j_scoped_manager.obj(),
- j_scoped_factory.obj());
+ Java_ServiceRegistry_createImplAndAttach(
+ env, j_scoped_service_registry.obj(), handle.release().value(),
+ j_scoped_manager.obj(), j_scoped_factory.obj());
}
} // namespace
// static
-bool ServiceRegistryAndroid::Register(JNIEnv* env) {
+std::unique_ptr<ServiceRegistryAndroid> ServiceRegistryAndroid::Create(
+ ServiceRegistry* registry) {
+ return base::WrapUnique(new ServiceRegistryAndroidImpl(registry));
+}
+
+// static
+bool ServiceRegistryAndroidImpl::Register(JNIEnv* env) {
return RegisterNativesImpl(env);
}
+ServiceRegistryAndroidImpl::~ServiceRegistryAndroidImpl() {
+ Java_ServiceRegistry_destroy(AttachCurrentThread(), obj_.obj());
+}
+
// Constructor and destructor call into Java.
-ServiceRegistryAndroid::ServiceRegistryAndroid(
- ServiceRegistryImpl* service_registry)
+ServiceRegistryAndroidImpl::ServiceRegistryAndroidImpl(
+ ServiceRegistry* service_registry)
: service_registry_(service_registry) {
JNIEnv* env = AttachCurrentThread();
obj_.Reset(
@@ -52,12 +62,13 @@ ServiceRegistryAndroid::ServiceRegistryAndroid(
Java_ServiceRegistry_create(env, reinterpret_cast<intptr_t>(this)).obj());
}
-ServiceRegistryAndroid::~ServiceRegistryAndroid() {
- Java_ServiceRegistry_destroy(AttachCurrentThread(), obj_.obj());
+const base::android::ScopedJavaGlobalRef<jobject>&
+ServiceRegistryAndroidImpl::GetObj() {
+ return obj_;
}
// Methods called from Java.
-void ServiceRegistryAndroid::AddService(
+void ServiceRegistryAndroidImpl::AddService(
JNIEnv* env,
const JavaParamRef<jobject>& j_service_registry,
const JavaParamRef<jobject>& j_manager,
@@ -74,14 +85,12 @@ void ServiceRegistryAndroid::AddService(
ScopedJavaGlobalRef<jobject> j_scoped_factory;
j_scoped_factory.Reset(env, j_factory);
- service_registry_->AddService(name,
- base::Bind(&CreateImplAndAttach,
- j_scoped_service_registry,
- j_scoped_manager,
- j_scoped_factory));
+ service_registry_->AddService(
+ name, base::Bind(&CreateImplAndAttach, j_scoped_service_registry,
+ j_scoped_manager, j_scoped_factory));
}
-void ServiceRegistryAndroid::RemoveService(
+void ServiceRegistryAndroidImpl::RemoveService(
JNIEnv* env,
const JavaParamRef<jobject>& j_service_registry,
const JavaParamRef<jstring>& j_name) {
@@ -89,7 +98,7 @@ void ServiceRegistryAndroid::RemoveService(
service_registry_->RemoveService(name);
}
-void ServiceRegistryAndroid::ConnectToRemoteService(
+void ServiceRegistryAndroidImpl::ConnectToRemoteService(
JNIEnv* env,
const JavaParamRef<jobject>& j_service_registry,
const JavaParamRef<jstring>& j_name,
diff --git a/chromium/content/browser/android/service_registry_android_impl.h b/chromium/content/browser/android/service_registry_android_impl.h
new file mode 100644
index 00000000000..2620313c801
--- /dev/null
+++ b/chromium/content/browser/android/service_registry_android_impl.h
@@ -0,0 +1,53 @@
+// 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 CONTENT_BROWSER_ANDROID_SERVICE_REGISTRY_ANDROID_IMPL_H_
+#define CONTENT_BROWSER_ANDROID_SERVICE_REGISTRY_ANDROID_IMPL_H_
+
+#include <jni.h>
+
+#include "base/macros.h"
+#include "content/public/browser/android/service_registry_android.h"
+
+namespace content {
+
+class ServiceRegistryAndroidImpl : public ServiceRegistryAndroid {
+ public:
+ static bool Register(JNIEnv* env);
+
+ ~ServiceRegistryAndroidImpl() override;
+
+ private:
+ friend class ServiceRegistryAndroid;
+
+ // Use ServiceRegistryAndroid::Create() to create an instance.
+ explicit ServiceRegistryAndroidImpl(ServiceRegistry* service_registry);
+
+ // ServiceRegistryAndroid implementation:
+ void AddService(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& j_service_registry,
+ const base::android::JavaParamRef<jobject>& j_manager,
+ const base::android::JavaParamRef<jobject>& j_factory,
+ const base::android::JavaParamRef<jstring>& j_name) override;
+ void RemoveService(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& j_service_registry,
+ const base::android::JavaParamRef<jstring>& j_name) override;
+ void ConnectToRemoteService(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& j_service_registry,
+ const base::android::JavaParamRef<jstring>& j_name,
+ jint handle) override;
+ const base::android::ScopedJavaGlobalRef<jobject>& GetObj() override;
+
+ ServiceRegistry* service_registry_;
+ base::android::ScopedJavaGlobalRef<jobject> obj_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceRegistryAndroidImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_SERVICE_REGISTRY_ANDROID_IMPL_H_
diff --git a/chromium/content/browser/android/synchronous_compositor_base.cc b/chromium/content/browser/android/synchronous_compositor_base.cc
index acc5e349f99..0d085095b91 100644
--- a/chromium/content/browser/android/synchronous_compositor_base.cc
+++ b/chromium/content/browser/android/synchronous_compositor_base.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/supports_user_data.h"
+#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/android/synchronous_compositor_host.h"
#include "content/browser/gpu/gpu_process_host.h"
@@ -20,27 +21,25 @@ class SynchronousCompositorClient;
namespace {
-gpu::SyncPointManager* g_sync_point_manager = nullptr;
+base::LazyInstance<scoped_refptr<gpu::InProcessCommandBuffer::Service>>
+ g_gpu_service = LAZY_INSTANCE_INITIALIZER;
base::Thread* CreateInProcessGpuThreadForSynchronousCompositor(
- const InProcessChildThreadParams& params) {
- DCHECK(g_sync_point_manager);
- return new InProcessGpuThread(params, g_sync_point_manager);
+ const InProcessChildThreadParams& params,
+ const gpu::GpuPreferences& gpu_preferences) {
+ DCHECK(g_gpu_service.Get());
+ return new InProcessGpuThread(params, gpu_preferences,
+ g_gpu_service.Get()->sync_point_manager());
}
} // namespace
void SynchronousCompositor::SetGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
- DCHECK(!g_sync_point_manager);
- g_sync_point_manager = service->sync_point_manager();
+ DCHECK(!g_gpu_service.Get());
+ g_gpu_service.Get() = service;
GpuProcessHost::RegisterGpuMainThreadFactory(
CreateInProcessGpuThreadForSynchronousCompositor);
-
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIPCSyncCompositing)) {
- SynchronousCompositorImpl::SetGpuServiceInProc(service);
- }
}
// static
@@ -65,10 +64,15 @@ scoped_ptr<SynchronousCompositorBase> SynchronousCompositorBase::Create(
if (!web_contents_android->synchronous_compositor_client())
return nullptr; // Not using sync compositing.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIPCSyncCompositing)) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kIPCSyncCompositing)) {
+ bool async_input =
+ !command_line->HasSwitch(switches::kSyncInputForSyncCompositor);
+ bool use_in_proc_software_draw =
+ command_line->HasSwitch(switches::kSingleProcess);
return make_scoped_ptr(new SynchronousCompositorHost(
- rwhva, web_contents_android->synchronous_compositor_client()));
+ rwhva, web_contents_android->synchronous_compositor_client(),
+ async_input, use_in_proc_software_draw));
}
return make_scoped_ptr(new SynchronousCompositorImpl(
rwhva, web_contents_android->synchronous_compositor_client()));
diff --git a/chromium/content/browser/android/synchronous_compositor_base.h b/chromium/content/browser/android/synchronous_compositor_base.h
index 6bd41bb24d4..218e82199da 100644
--- a/chromium/content/browser/android/synchronous_compositor_base.h
+++ b/chromium/content/browser/android/synchronous_compositor_base.h
@@ -24,7 +24,9 @@ struct BeginFrameArgs;
namespace content {
class RenderWidgetHostViewAndroid;
+class SynchronousCompositorStreamTextureFactoryImpl;
class WebContents;
+struct DidOverscrollParams;
class SynchronousCompositorBase : public SynchronousCompositor {
public:
@@ -37,6 +39,7 @@ class SynchronousCompositorBase : public SynchronousCompositor {
virtual void BeginFrame(const cc::BeginFrameArgs& args) = 0;
virtual InputEventAckState HandleInputEvent(
const blink::WebInputEvent& input_event) = 0;
+ virtual void DidOverscroll(const DidOverscrollParams& over_scroll_params) = 0;
virtual bool OnMessageReceived(const IPC::Message& message) = 0;
virtual void DidBecomeCurrent() = 0;
diff --git a/chromium/content/browser/android/synchronous_compositor_host.cc b/chromium/content/browser/android/synchronous_compositor_host.cc
index 83dd85fead4..7f6cdfc5fb3 100644
--- a/chromium/content/browser/android/synchronous_compositor_host.cc
+++ b/chromium/content/browser/android/synchronous_compositor_host.cc
@@ -10,6 +10,8 @@
#include "base/memory/shared_memory.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/output/compositor_frame_ack.h"
+#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
+#include "content/browser/android/in_process/synchronous_compositor_renderer_statics.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/android/sync_compositor_messages.h"
@@ -27,21 +29,26 @@ namespace content {
SynchronousCompositorHost::SynchronousCompositorHost(
RenderWidgetHostViewAndroid* rwhva,
- SynchronousCompositorClient* client)
+ SynchronousCompositorClient* client,
+ bool async_input,
+ bool use_in_proc_software_draw)
: rwhva_(rwhva),
client_(client),
ui_task_runner_(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)),
routing_id_(rwhva_->GetRenderWidgetHost()->GetRoutingID()),
sender_(rwhva_->GetRenderWidgetHost()),
+ async_input_(async_input),
+ use_in_process_zero_copy_software_draw_(use_in_proc_software_draw),
is_active_(false),
bytes_limit_(0u),
+ output_surface_id_from_last_draw_(0u),
root_scroll_offset_updated_by_browser_(false),
renderer_param_version_(0u),
need_animate_scroll_(false),
- need_invalidate_(false),
+ need_invalidate_count_(0u),
need_begin_frame_(false),
- did_activate_pending_tree_(false),
+ did_activate_pending_tree_count_(0u),
weak_ptr_factory_(this) {
client_->DidInitializeCompositor(this);
}
@@ -66,7 +73,7 @@ void SynchronousCompositorHost::DidBecomeCurrent() {
client_->DidBecomeCurrent(this);
}
-scoped_ptr<cc::CompositorFrame> SynchronousCompositorHost::DemandDrawHw(
+SynchronousCompositor::Frame SynchronousCompositorHost::DemandDrawHw(
const gfx::Size& surface_size,
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -76,22 +83,27 @@ scoped_ptr<cc::CompositorFrame> SynchronousCompositorHost::DemandDrawHw(
SyncCompositorDemandDrawHwParams params(surface_size, transform, viewport,
clip, viewport_rect_for_tile_priority,
transform_for_tile_priority);
- scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
+ SynchronousCompositor::Frame frame;
+ frame.frame.reset(new cc::CompositorFrame);
SyncCompositorCommonBrowserParams common_browser_params;
PopulateCommonParams(&common_browser_params);
SyncCompositorCommonRendererParams common_renderer_params;
if (!sender_->Send(new SyncCompositorMsg_DemandDrawHw(
routing_id_, common_browser_params, params, &common_renderer_params,
- frame.get()))) {
- return nullptr;
+ &frame.output_surface_id, frame.frame.get()))) {
+ return SynchronousCompositor::Frame();
}
ProcessCommonParams(common_renderer_params);
- if (!frame->delegated_frame_data) {
+ if (!frame.frame->delegated_frame_data) {
// This can happen if compositor did not swap in this draw.
- frame.reset();
+ frame.frame.reset();
+ }
+ if (frame.frame) {
+ UpdateFrameMetaData(frame.frame->metadata);
+ if (output_surface_id_from_last_draw_ != frame.output_surface_id)
+ returned_resources_.clear();
+ output_surface_id_from_last_draw_ = frame.output_surface_id;
}
- if (frame)
- UpdateFrameMetaData(frame->metadata);
return frame;
}
@@ -100,6 +112,44 @@ void SynchronousCompositorHost::UpdateFrameMetaData(
rwhva_->SynchronousFrameMetadata(frame_metadata);
}
+namespace {
+
+class ScopedSetSkCanvas {
+ public:
+ explicit ScopedSetSkCanvas(SkCanvas* canvas) {
+ SynchronousCompositorSetSkCanvas(canvas);
+ }
+
+ ~ScopedSetSkCanvas() {
+ SynchronousCompositorSetSkCanvas(nullptr);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetSkCanvas);
+};
+
+}
+
+bool SynchronousCompositorHost::DemandDrawSwInProc(SkCanvas* canvas) {
+ SyncCompositorCommonBrowserParams common_browser_params;
+ PopulateCommonParams(&common_browser_params);
+ SyncCompositorCommonRendererParams common_renderer_params;
+ bool success = false;
+ scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
+ ScopedSetSkCanvas set_sk_canvas(canvas);
+ SyncCompositorDemandDrawSwParams params; // Unused.
+ if (!sender_->Send(new SyncCompositorMsg_DemandDrawSw(
+ routing_id_, common_browser_params, params, &success,
+ &common_renderer_params, frame.get()))) {
+ return false;
+ }
+ if (!success)
+ return false;
+ ProcessCommonParams(common_renderer_params);
+ UpdateFrameMetaData(frame->metadata);
+ return true;
+}
+
class SynchronousCompositorHost::ScopedSendZeroMemory {
public:
ScopedSendZeroMemory(SynchronousCompositorHost* host) : host_(host) {}
@@ -124,6 +174,9 @@ struct SynchronousCompositorHost::SharedMemoryWithSize {
};
bool SynchronousCompositorHost::DemandDrawSw(SkCanvas* canvas) {
+ if (use_in_process_zero_copy_software_draw_)
+ return DemandDrawSwInProc(canvas);
+
SyncCompositorDemandDrawSwParams params;
params.size = gfx::Size(canvas->getBaseLayerSize().width(),
canvas->getBaseLayerSize().height());
@@ -222,7 +275,13 @@ void SynchronousCompositorHost::SendZeroMemory() {
}
void SynchronousCompositorHost::ReturnResources(
+ uint32_t output_surface_id,
const cc::CompositorFrameAck& frame_ack) {
+ // If output_surface_id does not match, then renderer side has switched
+ // to a new OutputSurface, so dropping resources for old OutputSurface
+ // is allowed.
+ if (output_surface_id_from_last_draw_ != output_surface_id)
+ return;
returned_resources_.insert(returned_resources_.end(),
frame_ack.resources.begin(),
frame_ack.resources.end());
@@ -231,8 +290,17 @@ void SynchronousCompositorHost::ReturnResources(
void SynchronousCompositorHost::SetMemoryPolicy(size_t bytes_limit) {
if (bytes_limit_ == bytes_limit)
return;
+ size_t current_bytes_limit = bytes_limit_;
bytes_limit_ = bytes_limit;
SendAsyncCompositorStateIfNeeded();
+
+ if (bytes_limit && !current_bytes_limit) {
+ SynchronousCompositorStreamTextureFactoryImpl::GetInstance()
+ ->CompositorInitializedHardwareDraw();
+ } else if (!bytes_limit && current_bytes_limit) {
+ SynchronousCompositorStreamTextureFactoryImpl::GetInstance()
+ ->CompositorReleasedHardwareDraw();
+ }
}
void SynchronousCompositorHost::DidChangeRootLayerScrollOffset(
@@ -261,6 +329,19 @@ void SynchronousCompositorHost::UpdateStateTask() {
DCHECK(!weak_ptr_factory_.HasWeakPtrs());
}
+void SynchronousCompositorHost::SynchronouslyZoomBy(float zoom_delta,
+ const gfx::Point& anchor) {
+ SyncCompositorCommonBrowserParams common_browser_params;
+ PopulateCommonParams(&common_browser_params);
+ SyncCompositorCommonRendererParams common_renderer_params;
+ if (!sender_->Send(new SyncCompositorMsg_ZoomBy(
+ routing_id_, common_browser_params, zoom_delta, anchor,
+ &common_renderer_params))) {
+ return;
+ }
+ ProcessCommonParams(common_renderer_params);
+}
+
void SynchronousCompositorHost::SetIsActive(bool is_active) {
if (is_active_ == is_active)
return;
@@ -278,16 +359,14 @@ void SynchronousCompositorHost::OnComputeScroll(
SyncCompositorCommonBrowserParams common_browser_params;
PopulateCommonParams(&common_browser_params);
SyncCompositorCommonRendererParams common_renderer_params;
- if (!sender_->Send(new SyncCompositorMsg_ComputeScroll(
- routing_id_, common_browser_params, animation_time,
- &common_renderer_params))) {
- return;
- }
- ProcessCommonParams(common_renderer_params);
+ sender_->Send(new SyncCompositorMsg_ComputeScroll(
+ routing_id_, common_browser_params, animation_time));
}
InputEventAckState SynchronousCompositorHost::HandleInputEvent(
const blink::WebInputEvent& input_event) {
+ if (async_input_)
+ return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
SyncCompositorCommonBrowserParams common_browser_params;
PopulateCommonParams(&common_browser_params);
SyncCompositorCommonRendererParams common_renderer_params;
@@ -301,8 +380,15 @@ InputEventAckState SynchronousCompositorHost::HandleInputEvent(
return ack;
}
+void SynchronousCompositorHost::DidOverscroll(
+ const DidOverscrollParams& over_scroll_params) {
+ client_->DidOverscroll(over_scroll_params.accumulated_overscroll,
+ over_scroll_params.latest_overscroll_delta,
+ over_scroll_params.current_fling_velocity);
+}
+
void SynchronousCompositorHost::BeginFrame(const cc::BeginFrameArgs& args) {
- if (!is_active_ || !need_begin_frame_)
+ if (!is_active_)
return;
SyncCompositorCommonBrowserParams common_browser_params;
@@ -320,9 +406,7 @@ void SynchronousCompositorHost::OnOverScroll(
const SyncCompositorCommonRendererParams& params,
const DidOverscrollParams& over_scroll_params) {
ProcessCommonParams(params);
- client_->DidOverscroll(over_scroll_params.accumulated_overscroll,
- over_scroll_params.latest_overscroll_delta,
- over_scroll_params.current_fling_velocity);
+ DidOverscroll(over_scroll_params);
}
void SynchronousCompositorHost::PopulateCommonParams(
@@ -330,6 +414,8 @@ void SynchronousCompositorHost::PopulateCommonParams(
DCHECK(params);
DCHECK(params->ack.resources.empty());
params->bytes_limit = bytes_limit_;
+ params->output_surface_id_for_returned_resources =
+ output_surface_id_from_last_draw_;
params->ack.resources.swap(returned_resources_);
if (root_scroll_offset_updated_by_browser_) {
params->root_scroll_offset = root_scroll_offset_;
@@ -354,18 +440,16 @@ void SynchronousCompositorHost::ProcessCommonParams(
need_begin_frame_ = params.need_begin_frame;
UpdateNeedsBeginFrames();
}
- need_invalidate_ = need_invalidate_ || params.need_invalidate;
- did_activate_pending_tree_ =
- did_activate_pending_tree_ || params.did_activate_pending_tree;
root_scroll_offset_ = params.total_scroll_offset;
- if (need_invalidate_) {
- need_invalidate_ = false;
+ if (need_invalidate_count_ != params.need_invalidate_count) {
+ need_invalidate_count_ = params.need_invalidate_count;
client_->PostInvalidate();
}
- if (did_activate_pending_tree_) {
- did_activate_pending_tree_ = false;
+ if (did_activate_pending_tree_count_ !=
+ params.did_activate_pending_tree_count) {
+ did_activate_pending_tree_count_ = params.did_activate_pending_tree_count;
client_->DidUpdateContent();
}
diff --git a/chromium/content/browser/android/synchronous_compositor_host.h b/chromium/content/browser/android/synchronous_compositor_host.h
index 8c60071db59..b9b1598602f 100644
--- a/chromium/content/browser/android/synchronous_compositor_host.h
+++ b/chromium/content/browser/android/synchronous_compositor_host.h
@@ -33,7 +33,7 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
~SynchronousCompositorHost() override;
// SynchronousCompositor overrides.
- scoped_ptr<cc::CompositorFrame> DemandDrawHw(
+ SynchronousCompositor::Frame DemandDrawHw(
const gfx::Size& surface_size,
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -41,16 +41,19 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
const gfx::Rect& viewport_rect_for_tile_priority,
const gfx::Transform& transform_for_tile_priority) override;
bool DemandDrawSw(SkCanvas* canvas) override;
- void ReturnResources(const cc::CompositorFrameAck& frame_ack) override;
+ void ReturnResources(uint32_t output_surface_id,
+ const cc::CompositorFrameAck& frame_ack) override;
void SetMemoryPolicy(size_t bytes_limit) override;
void DidChangeRootLayerScrollOffset(
const gfx::ScrollOffset& root_offset) override;
+ void SynchronouslyZoomBy(float zoom_delta, const gfx::Point& anchor) override;
void SetIsActive(bool is_active) override;
void OnComputeScroll(base::TimeTicks animation_time) override;
// SynchronousCompositorBase overrides.
InputEventAckState HandleInputEvent(
const blink::WebInputEvent& input_event) override;
+ void DidOverscroll(const DidOverscrollParams& over_scroll_params) override;
void BeginFrame(const cc::BeginFrameArgs& args) override;
bool OnMessageReceived(const IPC::Message& message) override;
void DidBecomeCurrent() override;
@@ -62,7 +65,9 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
friend class SynchronousCompositorBase;
SynchronousCompositorHost(RenderWidgetHostViewAndroid* rwhva,
- SynchronousCompositorClient* client);
+ SynchronousCompositorClient* client,
+ bool async_input,
+ bool use_in_proc_software_draw);
void PopulateCommonParams(SyncCompositorCommonBrowserParams* params);
void ProcessCommonParams(const SyncCompositorCommonRendererParams& params);
void UpdateNeedsBeginFrames();
@@ -71,6 +76,7 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
const DidOverscrollParams& over_scroll_params);
void SendAsyncCompositorStateIfNeeded();
void UpdateStateTask();
+ bool DemandDrawSwInProc(SkCanvas* canvas);
void SetSoftwareDrawSharedMemoryIfNeeded(size_t stride, size_t buffer_size);
void SendZeroMemory();
@@ -79,9 +85,12 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
const int routing_id_;
IPC::Sender* const sender_;
+ const bool async_input_;
+ const bool use_in_process_zero_copy_software_draw_;
bool is_active_;
size_t bytes_limit_;
+ uint32_t output_surface_id_from_last_draw_;
cc::ReturnedResourceArray returned_resources_;
scoped_ptr<SharedMemoryWithSize> software_draw_shm_;
@@ -92,9 +101,9 @@ class SynchronousCompositorHost : public SynchronousCompositorBase {
// From renderer.
uint32_t renderer_param_version_;
bool need_animate_scroll_;
- bool need_invalidate_;
+ uint32_t need_invalidate_count_;
bool need_begin_frame_;
- bool did_activate_pending_tree_;
+ uint32_t did_activate_pending_tree_count_;
base::WeakPtrFactory<SynchronousCompositorHost> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorHost);
diff --git a/chromium/content/browser/android/web_contents_observer_proxy.cc b/chromium/content/browser/android/web_contents_observer_proxy.cc
index d176f61f21b..dfa52cfb211 100644
--- a/chromium/content/browser/android/web_contents_observer_proxy.cc
+++ b/chromium/content/browser/android/web_contents_observer_proxy.cc
@@ -11,8 +11,10 @@
#include "base/android/scoped_java_ref.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/android/media_metadata_android.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
#include "jni/WebContentsObserverProxy_jni.h"
using base::android::AttachCurrentThread;
@@ -76,6 +78,17 @@ void WebContentsObserverProxy::RenderProcessGone(
was_oom_protected);
}
+void WebContentsObserverProxy::DidFinishNavigation(
+ NavigationHandle* navigation_handle) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, web_contents()->GetVisibleURL().spec()));
+ Java_WebContentsObserverProxy_didFinishNavigation(
+ env, obj.obj(), navigation_handle->IsInMainFrame(),
+ navigation_handle->IsErrorPage(), navigation_handle->HasCommitted());
+}
+
void WebContentsObserverProxy::DidStartLoading() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(java_observer_);
@@ -144,6 +157,7 @@ void WebContentsObserverProxy::DidNavigateMainFrame(
// that would also be valid for a fragment navigation.
bool is_fragment_navigation =
urls_same_ignoring_fragment && details.is_in_page;
+
Java_WebContentsObserverProxy_didNavigateMainFrame(
env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
details.is_navigation_to_different_page(), is_fragment_navigation,
@@ -294,14 +308,18 @@ void WebContentsObserverProxy::DidStartNavigationToPendingEntry(
env, obj.obj(), jstring_url.obj());
}
-void WebContentsObserverProxy::MediaSessionStateChanged(bool is_controllable,
- bool is_suspended) {
+void WebContentsObserverProxy::MediaSessionStateChanged(
+ bool is_controllable,
+ bool is_suspended,
+ const MediaMetadata& metadata) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(java_observer_);
+ ScopedJavaLocalRef<jobject> j_metadata =
+ MediaMetadataAndroid::CreateJavaObject(env, metadata);
Java_WebContentsObserverProxy_mediaSessionStateChanged(
- env, obj.obj(), is_controllable, is_suspended);
+ env, obj.obj(), is_controllable, is_suspended, j_metadata.obj());
}
void WebContentsObserverProxy::SetToBaseURLForDataURLIfNeeded(
diff --git a/chromium/content/browser/android/web_contents_observer_proxy.h b/chromium/content/browser/android/web_contents_observer_proxy.h
index e22edbbdf84..af0895dc669 100644
--- a/chromium/content/browser/android/web_contents_observer_proxy.h
+++ b/chromium/content/browser/android/web_contents_observer_proxy.h
@@ -32,6 +32,7 @@ class WebContentsObserverProxy : public WebContentsObserver {
private:
void RenderViewReady() override;
void RenderProcessGone(base::TerminationStatus termination_status) override;
+ void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void DidStartLoading() override;
void DidStopLoading() override;
void DidFailProvisionalLoad(RenderFrameHost* render_frame_host,
@@ -72,7 +73,8 @@ class WebContentsObserverProxy : public WebContentsObserver {
const GURL& url,
NavigationController::ReloadType reload_type) override;
void MediaSessionStateChanged(bool is_controllable,
- bool is_suspended) override;
+ bool is_suspended,
+ const MediaMetadata& metadata) override;
void SetToBaseURLForDataURLIfNeeded(std::string* url);
void DidFailLoadInternal(bool is_provisional_load,
diff --git a/chromium/content/browser/appcache/appcache_database.cc b/chromium/content/browser/appcache/appcache_database.cc
index f9e83ac91b7..f3053c7d258 100644
--- a/chromium/content/browser/appcache/appcache_database.cc
+++ b/chromium/content/browser/appcache/appcache_database.cc
@@ -191,6 +191,8 @@ AppCacheDatabase::GroupRecord::GroupRecord()
: group_id(0) {
}
+AppCacheDatabase::GroupRecord::GroupRecord(const GroupRecord& other) = default;
+
AppCacheDatabase::GroupRecord::~GroupRecord() {
}
diff --git a/chromium/content/browser/appcache/appcache_database.h b/chromium/content/browser/appcache/appcache_database.h
index a6f017e48d0..e2b265d56f1 100644
--- a/chromium/content/browser/appcache/appcache_database.h
+++ b/chromium/content/browser/appcache/appcache_database.h
@@ -51,6 +51,7 @@ class CONTENT_EXPORT AppCacheDatabase {
public:
struct CONTENT_EXPORT GroupRecord {
GroupRecord();
+ GroupRecord(const GroupRecord& other);
~GroupRecord();
int64_t group_id;
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.cc b/chromium/content/browser/appcache/appcache_disk_cache.cc
index 49030f000a9..da5475d03d2 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.cc
+++ b/chromium/content/browser/appcache/appcache_disk_cache.cc
@@ -336,6 +336,8 @@ AppCacheDiskCache::PendingCall::PendingCall(
const net::CompletionCallback& callback)
: call_type(call_type), key(key), entry(entry), callback(callback) {}
+AppCacheDiskCache::PendingCall::PendingCall(const PendingCall& other) = default;
+
AppCacheDiskCache::PendingCall::~PendingCall() {}
int AppCacheDiskCache::Init(
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.h b/chromium/content/browser/appcache/appcache_disk_cache.h
index 2b8c29993b4..d06bcf50f5b 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.h
+++ b/chromium/content/browser/appcache/appcache_disk_cache.h
@@ -89,6 +89,8 @@ class CONTENT_EXPORT AppCacheDiskCache
Entry** entry,
const net::CompletionCallback& callback);
+ PendingCall(const PendingCall& other);
+
~PendingCall();
};
typedef std::vector<PendingCall> PendingCalls;
diff --git a/chromium/content/browser/appcache/appcache_interceptor.cc b/chromium/content/browser/appcache/appcache_interceptor.cc
index 81985fe704a..050e66aee18 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.cc
+++ b/chromium/content/browser/appcache/appcache_interceptor.cc
@@ -9,6 +9,9 @@
#include "content/browser/appcache/appcache_request_handler.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/appcache_url_request_job.h"
+#include "content/browser/appcache/chrome_appcache_service.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/loader/resource_message_filter.h"
#include "content/common/appcache_interfaces.h"
#include "net/url_request/url_request.h"
@@ -76,10 +79,16 @@ void AppCacheInterceptor::PrepareForCrossSiteTransfer(
void AppCacheInterceptor::CompleteCrossSiteTransfer(
net::URLRequest* request,
int new_process_id,
- int new_host_id) {
+ int new_host_id,
+ ResourceMessageFilter* filter) {
AppCacheRequestHandler* handler = GetHandler(request);
if (!handler)
return;
+ if (!handler->SanityCheckIsSameService(filter->appcache_service())) {
+ bad_message::ReceivedBadMessage(filter,
+ bad_message::ACI_WRONG_STORAGE_PARTITION);
+ return;
+ }
DCHECK_NE(kAppCacheNoHostId, new_host_id);
handler->CompleteCrossSiteTransfer(new_process_id,
new_host_id);
diff --git a/chromium/content/browser/appcache/appcache_interceptor.h b/chromium/content/browser/appcache/appcache_interceptor.h
index 0e50983ba21..9d1abc31b6a 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.h
+++ b/chromium/content/browser/appcache/appcache_interceptor.h
@@ -21,6 +21,7 @@ class URLRequest;
namespace content {
class AppCacheRequestHandler;
class AppCacheServiceImpl;
+class ResourceMessageFilter;
// An interceptor to hijack requests and potentially service them out of
// the appcache.
@@ -45,7 +46,8 @@ class CONTENT_EXPORT AppCacheInterceptor : public net::URLRequestInterceptor {
int old_process_id);
static void CompleteCrossSiteTransfer(net::URLRequest* request,
int new_process_id,
- int new_host_id);
+ int new_host_id,
+ ResourceMessageFilter* filter);
static void MaybeCompleteCrossSiteTransferInOldProcess(
net::URLRequest* request,
int old_process_id);
diff --git a/chromium/content/browser/appcache/appcache_internals_ui.cc b/chromium/content/browser/appcache/appcache_internals_ui.cc
index 3abd692603a..0c402129b60 100644
--- a/chromium/content/browser/appcache/appcache_internals_ui.cc
+++ b/chromium/content/browser/appcache/appcache_internals_ui.cc
@@ -462,7 +462,7 @@ void AppCacheInternalsUI::OnFileDetailsReady(
response_info->http_response_info()->headers->GetStatusLine()));
headers.push_back('\n');
- void* iter = nullptr;
+ size_t iter = 0;
std::string name, value;
while (response_info->http_response_info()->headers->EnumerateHeaderLines(
&iter, &name, &value)) {
diff --git a/chromium/content/browser/appcache/appcache_request_handler.cc b/chromium/content/browser/appcache/appcache_request_handler.cc
index c02223752af..0a00878df3c 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.cc
+++ b/chromium/content/browser/appcache/appcache_request_handler.cc
@@ -187,6 +187,7 @@ void AppCacheRequestHandler::PrepareForCrossSiteTransfer(int old_process_id) {
if (!host_)
return;
AppCacheBackendImpl* backend = host_->service()->GetBackend(old_process_id);
+ DCHECK(backend) << "appcache detected likely storage partition mismatch";
old_process_id_ = old_process_id;
old_host_id_ = host_->host_id();
host_for_cross_site_transfer_ = backend->TransferHostOut(host_->host_id());
@@ -199,6 +200,7 @@ void AppCacheRequestHandler::CompleteCrossSiteTransfer(
return;
DCHECK_EQ(host_, host_for_cross_site_transfer_.get());
AppCacheBackendImpl* backend = host_->service()->GetBackend(new_process_id);
+ DCHECK(backend) << "appcache detected likely storage partition mismatch";
backend->TransferHostIn(new_host_id,
std::move(host_for_cross_site_transfer_));
}
diff --git a/chromium/content/browser/appcache/appcache_request_handler.h b/chromium/content/browser/appcache/appcache_request_handler.h
index d7b55e5a96b..7665d10e0b8 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.h
+++ b/chromium/content/browser/appcache/appcache_request_handler.h
@@ -25,6 +25,7 @@ class URLRequestJob;
namespace content {
class AppCacheRequestHandlerTest;
+class AppCacheService;
class AppCacheURLRequestJob;
// An instance is created for each net::URLRequest. The instance survives all
@@ -58,6 +59,12 @@ class CONTENT_EXPORT AppCacheRequestHandler
void CompleteCrossSiteTransfer(int new_process_id, int new_host_id);
void MaybeCompleteCrossSiteTransferInOldProcess(int old_process_id);
+ // Useful for detecting storage partition mismatches in the context
+ // of cross site transfer navigations.
+ bool SanityCheckIsSameService(AppCacheService* service) {
+ return !host_ || (host_->service() == service);
+ }
+
static bool IsMainResourceType(ResourceType type) {
return IsResourceTypeFrame(type) ||
type == RESOURCE_TYPE_SHARED_WORKER;
diff --git a/chromium/content/browser/appcache/appcache_response.cc b/chromium/content/browser/appcache/appcache_response.cc
index 20a8b8a36d0..b5df22dea85 100644
--- a/chromium/content/browser/appcache/appcache_response.cc
+++ b/chromium/content/browser/appcache/appcache_response.cc
@@ -78,11 +78,24 @@ HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer(net::HttpResponseInfo* info)
HttpResponseInfoIOBuffer::~HttpResponseInfoIOBuffer() {}
+// AppCacheDiskCacheInterface ----------------------------------------
+
+AppCacheDiskCacheInterface::AppCacheDiskCacheInterface()
+ : weak_factory_(this) {}
+
+base::WeakPtr<AppCacheDiskCacheInterface>
+AppCacheDiskCacheInterface::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+AppCacheDiskCacheInterface::~AppCacheDiskCacheInterface() {}
+
// AppCacheResponseIO ----------------------------------------------
-AppCacheResponseIO::AppCacheResponseIO(int64_t response_id,
- int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache)
+AppCacheResponseIO::AppCacheResponseIO(
+ int64_t response_id,
+ int64_t group_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: response_id_(response_id),
group_id_(group_id),
disk_cache_(disk_cache),
@@ -177,7 +190,7 @@ void AppCacheResponseIO::OpenEntryCallback(
AppCacheResponseReader::AppCacheResponseReader(
int64_t response_id,
int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseIO(response_id, group_id, disk_cache),
range_offset_(0),
range_length_(std::numeric_limits<int32_t>::max()),
@@ -302,7 +315,7 @@ void AppCacheResponseReader::OnOpenEntryComplete() {
AppCacheResponseWriter::AppCacheResponseWriter(
int64_t response_id,
int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseIO(response_id, group_id, disk_cache),
info_size_(0),
write_position_(0),
@@ -404,7 +417,10 @@ void AppCacheResponseWriter::OnCreateEntryComplete(
AppCacheDiskCacheInterface::Entry** entry, int rv) {
DCHECK(info_buffer_.get() || buffer_.get());
- if (creation_phase_ == INITIAL_ATTEMPT) {
+ if (!disk_cache_) {
+ ScheduleIOCompletionCallback(net::ERR_FAILED);
+ return;
+ } else if (creation_phase_ == INITIAL_ATTEMPT) {
if (rv != net::OK) {
// We may try to overwrite existing entries.
creation_phase_ = DOOM_EXISTING;
@@ -444,7 +460,7 @@ void AppCacheResponseWriter::OnCreateEntryComplete(
AppCacheResponseMetadataWriter::AppCacheResponseMetadataWriter(
int64_t response_id,
int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseIO(response_id, group_id, disk_cache),
write_amount_(0),
weak_factory_(this) {}
diff --git a/chromium/content/browser/appcache/appcache_response.h b/chromium/content/browser/appcache/appcache_response.h
index 8543b2b902f..0b709b91068 100644
--- a/chromium/content/browser/appcache/appcache_response.h
+++ b/chromium/content/browser/appcache/appcache_response.h
@@ -93,6 +93,8 @@ class CONTENT_EXPORT AppCacheDiskCacheInterface {
virtual ~Entry() {}
};
+ AppCacheDiskCacheInterface();
+
virtual int CreateEntry(int64_t key,
Entry** entry,
const net::CompletionCallback& callback) = 0;
@@ -102,9 +104,12 @@ class CONTENT_EXPORT AppCacheDiskCacheInterface {
virtual int DoomEntry(int64_t key,
const net::CompletionCallback& callback) = 0;
+ base::WeakPtr<AppCacheDiskCacheInterface> GetWeakPtr();
+
protected:
- friend class base::RefCounted<AppCacheDiskCacheInterface>;
- virtual ~AppCacheDiskCacheInterface() {}
+ virtual ~AppCacheDiskCacheInterface();
+
+ base::WeakPtrFactory<AppCacheDiskCacheInterface> weak_factory_;
};
// Common base class for response reader and writer.
@@ -114,9 +119,10 @@ class CONTENT_EXPORT AppCacheResponseIO {
int64_t response_id() const { return response_id_; }
protected:
- AppCacheResponseIO(int64_t response_id,
- int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache);
+ AppCacheResponseIO(
+ int64_t response_id,
+ int64_t group_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
virtual void OnIOComplete(int result) = 0;
virtual void OnOpenEntryComplete() {}
@@ -130,7 +136,7 @@ class CONTENT_EXPORT AppCacheResponseIO {
const int64_t response_id_;
const int64_t group_id_;
- AppCacheDiskCacheInterface* disk_cache_;
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache_;
AppCacheDiskCacheInterface::Entry* entry_;
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
scoped_refptr<net::IOBuffer> buffer_;
@@ -190,9 +196,10 @@ class CONTENT_EXPORT AppCacheResponseReader
friend class content::MockAppCacheStorage;
// Should only be constructed by the storage class and derivatives.
- AppCacheResponseReader(int64_t response_id,
- int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache);
+ AppCacheResponseReader(
+ int64_t response_id,
+ int64_t group_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
void OnIOComplete(int result) override;
void OnOpenEntryComplete() override;
@@ -247,9 +254,10 @@ class CONTENT_EXPORT AppCacheResponseWriter
protected:
// Should only be constructed by the storage class and derivatives.
- AppCacheResponseWriter(int64_t response_id,
- int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache);
+ AppCacheResponseWriter(
+ int64_t response_id,
+ int64_t group_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
private:
friend class AppCacheStorageImpl;
@@ -304,10 +312,12 @@ class CONTENT_EXPORT AppCacheResponseMetadataWriter
protected:
friend class AppCacheStorageImpl;
friend class content::MockAppCacheStorage;
+
// Should only be constructed by the storage class and derivatives.
- AppCacheResponseMetadataWriter(int64_t response_id,
- int64_t group_id,
- AppCacheDiskCacheInterface* disk_cache);
+ AppCacheResponseMetadataWriter(
+ int64_t response_id,
+ int64_t group_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
private:
void OnIOComplete(int result) override;
diff --git a/chromium/content/browser/appcache/appcache_service_impl.cc b/chromium/content/browser/appcache/appcache_service_impl.cc
index 2fc5d949d2e..537ca8e81e6 100644
--- a/chromium/content/browser/appcache/appcache_service_impl.cc
+++ b/chromium/content/browser/appcache/appcache_service_impl.cc
@@ -412,9 +412,8 @@ AppCacheServiceImpl::AppCacheServiceImpl(
AppCacheServiceImpl::~AppCacheServiceImpl() {
DCHECK(backends_.empty());
- std::for_each(pending_helpers_.begin(),
- pending_helpers_.end(),
- std::mem_fun(&AsyncHelper::Cancel));
+ for (auto* helper : pending_helpers_)
+ helper->Cancel();
STLDeleteElements(&pending_helpers_);
if (quota_client_)
quota_client_->NotifyAppCacheDestroyed();
diff --git a/chromium/content/browser/appcache/appcache_service_unittest.cc b/chromium/content/browser/appcache/appcache_service_unittest.cc
index 79febf7675a..5c29d50ee5f 100644
--- a/chromium/content/browser/appcache/appcache_service_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_service_unittest.cc
@@ -42,7 +42,9 @@ class MockResponseReader : public AppCacheResponseReader {
int info_size,
const char* data,
int data_size)
- : AppCacheResponseReader(response_id, 0, NULL),
+ : AppCacheResponseReader(response_id,
+ 0,
+ base::WeakPtr<AppCacheDiskCacheInterface>()),
info_(info),
info_size_(info_size),
data_(data),
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.cc b/chromium/content/browser/appcache/appcache_storage_impl.cc
index b144eb69f51..ceb52271fd8 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl.cc
+++ b/chromium/content/browser/appcache/appcache_storage_impl.cc
@@ -837,11 +837,7 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() {
// Helpers for FindMainResponseTask::Run()
namespace {
-class SortByCachePreference
- : public std::binary_function<
- AppCacheDatabase::EntryRecord,
- AppCacheDatabase::EntryRecord,
- bool> {
+class SortByCachePreference {
public:
SortByCachePreference(int64_t preferred_id,
const std::set<int64_t>& in_use_ids)
@@ -1423,12 +1419,10 @@ AppCacheStorageImpl::AppCacheStorageImpl(AppCacheServiceImpl* service)
}
AppCacheStorageImpl::~AppCacheStorageImpl() {
- std::for_each(pending_quota_queries_.begin(),
- pending_quota_queries_.end(),
- std::mem_fun(&DatabaseTask::CancelCompletion));
- std::for_each(scheduled_database_tasks_.begin(),
- scheduled_database_tasks_.end(),
- std::mem_fun(&DatabaseTask::CancelCompletion));
+ for (auto* task : pending_quota_queries_)
+ task->CancelCompletion();
+ for (auto* task : scheduled_database_tasks_)
+ task->CancelCompletion();
if (database_ &&
!db_thread_->PostTask(
@@ -1742,20 +1736,22 @@ AppCacheResponseReader* AppCacheStorageImpl::CreateResponseReader(
const GURL& manifest_url,
int64_t group_id,
int64_t response_id) {
- return new AppCacheResponseReader(response_id, group_id, disk_cache());
+ return new AppCacheResponseReader(response_id, group_id,
+ disk_cache()->GetWeakPtr());
}
AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
const GURL& manifest_url,
int64_t group_id) {
- return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
+ return new AppCacheResponseWriter(NewResponseId(), group_id,
+ disk_cache()->GetWeakPtr());
}
AppCacheResponseMetadataWriter*
AppCacheStorageImpl::CreateResponseMetadataWriter(int64_t group_id,
int64_t response_id) {
return new AppCacheResponseMetadataWriter(response_id, group_id,
- disk_cache());
+ disk_cache()->GetWeakPtr());
}
void AppCacheStorageImpl::DoomResponses(
diff --git a/chromium/content/browser/appcache/appcache_update_job.cc b/chromium/content/browser/appcache/appcache_update_job.cc
index b6ab3fb7318..7c922f868a7 100644
--- a/chromium/content/browser/appcache/appcache_update_job.cc
+++ b/chromium/content/browser/appcache/appcache_update_job.cc
@@ -140,6 +140,8 @@ AppCacheUpdateJob::UrlToFetch::UrlToFetch(const GURL& url,
existing_response_info(info) {
}
+AppCacheUpdateJob::UrlToFetch::UrlToFetch(const UrlToFetch& other) = default;
+
AppCacheUpdateJob::UrlToFetch::~UrlToFetch() {
}
@@ -279,7 +281,7 @@ void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders(
// Add If-Modified-Since header if response info has Last-Modified header.
const std::string last_modified = "Last-Modified";
std::string last_modified_value;
- headers->EnumerateHeader(NULL, last_modified, &last_modified_value);
+ headers->EnumerateHeader(nullptr, last_modified, &last_modified_value);
if (!last_modified_value.empty()) {
extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
last_modified_value);
@@ -288,7 +290,7 @@ void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders(
// Add If-None-Match header if response info has ETag header.
const std::string etag = "ETag";
std::string etag_value;
- headers->EnumerateHeader(NULL, etag, &etag_value);
+ headers->EnumerateHeader(nullptr, etag, &etag_value);
if (!etag_value.empty()) {
extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
etag_value);
@@ -1474,7 +1476,7 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
// Responses with a "vary" header get treated as expired.
const std::string name = "vary";
std::string value;
- void* iter = NULL;
+ size_t iter = 0;
if (!http_info->headers.get() ||
http_info->headers->RequiresValidation(http_info->request_time,
http_info->response_time,
diff --git a/chromium/content/browser/appcache/appcache_update_job.h b/chromium/content/browser/appcache/appcache_update_job.h
index f1c7af03bd5..4fa15885c88 100644
--- a/chromium/content/browser/appcache/appcache_update_job.h
+++ b/chromium/content/browser/appcache/appcache_update_job.h
@@ -101,6 +101,7 @@ class CONTENT_EXPORT AppCacheUpdateJob
struct UrlToFetch {
UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info);
+ UrlToFetch(const UrlToFetch& other);
~UrlToFetch();
GURL url;
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.cc b/chromium/content/browser/appcache/appcache_url_request_job.cc
index 05fe008b54e..35728e66de5 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job.cc
@@ -433,6 +433,12 @@ int AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
return net::ERR_IO_PENDING;
}
+net::HostPortPair AppCacheURLRequestJob::GetSocketAddress() const {
+ if (!http_info())
+ return net::HostPortPair();
+ return http_info()->socket_address;
+}
+
void AppCacheURLRequestJob::SetExtraRequestHeaders(
const net::HttpRequestHeaders& headers) {
std::string value;
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.h b/chromium/content/browser/appcache/appcache_url_request_job.h
index 057c13b98e4..5b8723761a5 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job.h
+++ b/chromium/content/browser/appcache/appcache_url_request_job.h
@@ -152,6 +152,7 @@ class CONTENT_EXPORT AppCacheURLRequestJob
bool GetCharset(std::string* charset) override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int ReadRawData(net::IOBuffer* buf, int buf_size) override;
+ net::HostPortPair GetSocketAddress() const override;
// Sets extra request headers for Job types that support request headers.
// This is how we get informed of range-requests.
diff --git a/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc b/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
index 0eca5fe0cfb..a23bde6f0e5 100644
--- a/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -102,14 +102,11 @@ ChromeAppCacheServiceTest::CreateAppCacheServiceImpl(
browser_context_.GetResourceContext()->GetRequestContext(),
message_loop_.task_runner().get());
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(&ChromeAppCacheService::InitializeOnIOThread,
- appcache_service.get(),
- appcache_path,
+ appcache_service.get(), appcache_path,
browser_context_.GetResourceContext(),
- mock_request_context_getter,
- mock_policy));
+ base::RetainedRef(mock_request_context_getter), mock_policy));
// Steps needed to initialize the storage of AppCache data.
message_loop_.RunUntilIdle();
if (init_storage) {
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.cc b/chromium/content/browser/appcache/mock_appcache_storage.cc
index 09bdf03c2ac..5d7cd8d19d9 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.cc
+++ b/chromium/content/browser/appcache/mock_appcache_storage.cc
@@ -169,20 +169,22 @@ AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader(
int64_t response_id) {
if (simulated_reader_)
return simulated_reader_.release();
- return new AppCacheResponseReader(response_id, group_id, disk_cache());
+ return new AppCacheResponseReader(response_id, group_id,
+ disk_cache()->GetWeakPtr());
}
AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter(
const GURL& manifest_url,
int64_t group_id) {
- return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
+ return new AppCacheResponseWriter(NewResponseId(), group_id,
+ disk_cache()->GetWeakPtr());
}
AppCacheResponseMetadataWriter*
MockAppCacheStorage::CreateResponseMetadataWriter(int64_t group_id,
int64_t response_id) {
return new AppCacheResponseMetadataWriter(response_id, group_id,
- disk_cache());
+ disk_cache()->GetWeakPtr());
}
void MockAppCacheStorage::DoomResponses(
diff --git a/chromium/content/browser/background_sync/background_sync.proto b/chromium/content/browser/background_sync/background_sync.proto
index 11adc3133c3..62dbe72b359 100644
--- a/chromium/content/browser/background_sync/background_sync.proto
+++ b/chromium/content/browser/background_sync/background_sync.proto
@@ -14,23 +14,13 @@ enum SyncNetworkState {
NETWORK_STATE_ONLINE = 2;
}
-enum SyncPowerState {
- POWER_STATE_AUTO = 0;
- POWER_STATE_AVOID_DRAINING = 1;
-}
-
-enum SyncPeriodicity {
- SYNC_PERIODIC = 0;
- SYNC_ONE_SHOT = 1;
-}
-
message BackgroundSyncRegistrationProto {
required int64 id = 1;
required string tag = 2;
- required SyncPeriodicity periodicity = 3;
- required int64 min_period = 4;
+ // required SyncPeriodicity periodicity = 3;
+ // required int64 min_period = 4;
required SyncNetworkState network_state = 5;
- required SyncPowerState power_state = 6;
+ // required SyncPowerState power_state = 6;
required int32 num_attempts = 7;
required int64 delay_until = 8;
}
diff --git a/chromium/content/browser/background_sync/background_sync_browsertest.cc b/chromium/content/browser/background_sync/background_sync_browsertest.cc
index a5de6ada408..4113137ef62 100644
--- a/chromium/content/browser/background_sync/background_sync_browsertest.cc
+++ b/chromium/content/browser/background_sync/background_sync_browsertest.cc
@@ -15,7 +15,6 @@
#include "base/task_runner_util.h"
#include "content/browser/background_sync/background_sync_manager.h"
#include "content/browser/background_sync/background_sync_network_observer.h"
-#include "content/browser/background_sync/background_sync_registration_handle.h"
#include "content/browser/background_sync/background_sync_status.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
@@ -42,7 +41,10 @@ namespace {
const char kDefaultTestURL[] = "/background_sync/test.html";
const char kEmptyURL[] = "/background_sync/empty.html";
-const char kRegisterSyncURL[] = "/background_sync/register_sync.html";
+const char kRegisterSyncFromIFrameURL[] =
+ "/background_sync/register_sync_from_iframe.html";
+const char kRegisterSyncFromSWURL[] =
+ "/background_sync/register_sync_from_sw.html";
const char kSuccessfulOperationPrefix[] = "ok - ";
@@ -57,7 +59,7 @@ std::string BuildExpectedResult(const std::string& tag,
action.c_str());
}
-void OneShotPendingCallback(
+void RegistrationPendingCallback(
const base::Closure& quit,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
bool* result_out,
@@ -66,16 +68,24 @@ void OneShotPendingCallback(
task_runner->PostTask(FROM_HERE, quit);
}
-void OneShotPendingDidGetSyncRegistration(
+void RegistrationPendingDidGetSyncRegistration(
+ const std::string& tag,
const base::Callback<void(bool)>& callback,
BackgroundSyncStatus error_type,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle) {
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> registrations) {
ASSERT_EQ(BACKGROUND_SYNC_STATUS_OK, error_type);
- callback.Run(registration_handle->sync_state() ==
- BACKGROUND_SYNC_STATE_PENDING);
+ // Find the right registration in the list and check its status.
+ for (const BackgroundSyncRegistration* registration : *registrations) {
+ if (registration->options()->tag == tag) {
+ callback.Run(registration->sync_state() ==
+ mojom::BackgroundSyncState::PENDING);
+ return;
+ }
+ }
+ ADD_FAILURE() << "Registration should exist";
}
-void OneShotPendingDidGetSWRegistration(
+void RegistrationPendingDidGetSWRegistration(
const scoped_refptr<BackgroundSyncContext> sync_context,
const std::string& tag,
const base::Callback<void(bool)>& callback,
@@ -84,20 +94,20 @@ void OneShotPendingDidGetSWRegistration(
ASSERT_EQ(SERVICE_WORKER_OK, status);
int64_t service_worker_id = registration->id();
BackgroundSyncManager* sync_manager = sync_context->background_sync_manager();
- sync_manager->GetRegistration(
- service_worker_id, tag, SYNC_ONE_SHOT,
- base::Bind(&OneShotPendingDidGetSyncRegistration, callback));
+ sync_manager->GetRegistrations(
+ service_worker_id,
+ base::Bind(&RegistrationPendingDidGetSyncRegistration, tag, callback));
}
-void OneShotPendingOnIOThread(
+void RegistrationPendingOnIOThread(
const scoped_refptr<BackgroundSyncContext> sync_context,
const scoped_refptr<ServiceWorkerContextWrapper> sw_context,
const std::string& tag,
const GURL& url,
const base::Callback<void(bool)>& callback) {
sw_context->FindReadyRegistrationForDocument(
- url, base::Bind(&OneShotPendingDidGetSWRegistration, sync_context, tag,
- callback));
+ url, base::Bind(&RegistrationPendingDidGetSWRegistration, sync_context,
+ tag, callback));
}
void SetMaxSyncAttemptsOnIOThread(
@@ -169,9 +179,9 @@ class BackgroundSyncBrowserTest : public ContentBrowserTest {
result);
}
- // Returns true if the one-shot sync with tag is currently pending. Fails
+ // Returns true if the registration with tag |tag| is currently pending. Fails
// (assertion failure) if the tag isn't registered.
- bool OneShotPending(const std::string& tag);
+ bool RegistrationPending(const std::string& tag);
// Sets the BackgroundSyncManager's max sync attempts per registration.
void SetMaxSyncAttempts(int max_sync_attempts);
@@ -181,17 +191,18 @@ class BackgroundSyncBrowserTest : public ContentBrowserTest {
std::string PopConsoleString();
bool PopConsole(const std::string& expected_msg);
bool RegisterServiceWorker();
- bool RegisterOneShot(const std::string& tag);
- bool RegisterOneShotFromServiceWorker(const std::string& tag);
- bool GetRegistrationOneShot(const std::string& tag);
- bool GetRegistrationOneShotFromServiceWorker(const std::string& tag);
- bool MatchRegistrations(const std::string& script_result,
- const std::vector<std::string>& expected_tags);
- bool GetRegistrationsOneShot(const std::vector<std::string>& expected_tags);
- bool GetRegistrationsOneShotFromServiceWorker(
- const std::vector<std::string>& expected_tags);
- bool CompleteDelayedOneShot();
- bool RejectDelayedOneShot();
+ bool Register(const std::string& tag);
+ bool RegisterFromServiceWorker(const std::string& tag);
+ bool RegisterFromCrossOriginFrame(const std::string& frame_url,
+ std::string* script_result);
+ bool HasTag(const std::string& tag);
+ bool HasTagFromServiceWorker(const std::string& tag);
+ bool MatchTags(const std::string& script_result,
+ const std::vector<std::string>& expected_tags);
+ bool GetTags(const std::vector<std::string>& expected_tags);
+ bool GetTagsFromServiceWorker(const std::vector<std::string>& expected_tags);
+ bool CompleteDelayedSyncEvent();
+ bool RejectDelayedSyncEvent();
net::EmbeddedTestServer* https_server() { return https_server_.get(); }
@@ -202,7 +213,7 @@ class BackgroundSyncBrowserTest : public ContentBrowserTest {
DISALLOW_COPY_AND_ASSIGN(BackgroundSyncBrowserTest);
};
-bool BackgroundSyncBrowserTest::OneShotPending(const std::string& tag) {
+bool BackgroundSyncBrowserTest::RegistrationPending(const std::string& tag) {
bool is_pending;
base::RunLoop run_loop;
@@ -213,12 +224,13 @@ bool BackgroundSyncBrowserTest::OneShotPending(const std::string& tag) {
storage->GetServiceWorkerContext());
base::Callback<void(bool)> callback =
- base::Bind(&OneShotPendingCallback, run_loop.QuitClosure(),
+ base::Bind(&RegistrationPendingCallback, run_loop.QuitClosure(),
base::ThreadTaskRunnerHandle::Get(), &is_pending);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&OneShotPendingOnIOThread, make_scoped_refptr(sync_context),
+ base::Bind(&RegistrationPendingOnIOThread,
+ make_scoped_refptr(sync_context),
make_scoped_refptr(service_worker_context), tag,
https_server_->GetURL(kDefaultTestURL), callback));
@@ -281,41 +293,51 @@ bool BackgroundSyncBrowserTest::RegisterServiceWorker() {
return script_result == BuildExpectedResult("service worker", "registered");
}
-bool BackgroundSyncBrowserTest::RegisterOneShot(const std::string& tag) {
+bool BackgroundSyncBrowserTest::Register(const std::string& tag) {
std::string script_result;
- EXPECT_TRUE(
- RunScript(BuildScriptString("registerOneShot", tag), &script_result));
+ EXPECT_TRUE(RunScript(BuildScriptString("register", tag), &script_result));
return script_result == BuildExpectedResult(tag, "registered");
}
-bool BackgroundSyncBrowserTest::RegisterOneShotFromServiceWorker(
+bool BackgroundSyncBrowserTest::RegisterFromServiceWorker(
const std::string& tag) {
std::string script_result;
- EXPECT_TRUE(
- RunScript(BuildScriptString("registerOneShotFromServiceWorker", tag),
- &script_result));
+ EXPECT_TRUE(RunScript(BuildScriptString("registerFromServiceWorker", tag),
+ &script_result));
return script_result == BuildExpectedResult(tag, "register sent to SW");
}
-bool BackgroundSyncBrowserTest::GetRegistrationOneShot(const std::string& tag) {
+bool BackgroundSyncBrowserTest::RegisterFromCrossOriginFrame(
+ const std::string& frame_url,
+ std::string* script_result) {
+ // Start a second https server to use as a second origin.
+ net::EmbeddedTestServer alt_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ alt_server.ServeFilesFromSourceDirectory("content/test/data");
+ EXPECT_TRUE(alt_server.Start());
+
+ GURL url = alt_server.GetURL(frame_url);
+ return RunScript(
+ BuildScriptString("registerFromCrossOriginFrame", url.spec()),
+ script_result);
+}
+
+bool BackgroundSyncBrowserTest::HasTag(const std::string& tag) {
std::string script_result;
- EXPECT_TRUE(RunScript(BuildScriptString("getRegistrationOneShot", tag),
- &script_result));
+ EXPECT_TRUE(RunScript(BuildScriptString("hasTag", tag), &script_result));
return script_result == BuildExpectedResult(tag, "found");
}
-bool BackgroundSyncBrowserTest::GetRegistrationOneShotFromServiceWorker(
+bool BackgroundSyncBrowserTest::HasTagFromServiceWorker(
const std::string& tag) {
std::string script_result;
- EXPECT_TRUE(RunScript(
- BuildScriptString("getRegistrationOneShotFromServiceWorker", tag),
- &script_result));
- EXPECT_TRUE(script_result == "ok - getRegistration sent to SW");
+ EXPECT_TRUE(RunScript(BuildScriptString("hasTagFromServiceWorker", tag),
+ &script_result));
+ EXPECT_TRUE(script_result == "ok - hasTag sent to SW");
return PopConsole(BuildExpectedResult(tag, "found"));
}
-bool BackgroundSyncBrowserTest::MatchRegistrations(
+bool BackgroundSyncBrowserTest::MatchTags(
const std::string& script_result,
const std::vector<std::string>& expected_tags) {
EXPECT_TRUE(base::StartsWith(script_result, kSuccessfulOperationPrefix,
@@ -329,79 +351,80 @@ bool BackgroundSyncBrowserTest::MatchRegistrations(
std::set<std::string>(result_tags.begin(), result_tags.end());
}
-bool BackgroundSyncBrowserTest::GetRegistrationsOneShot(
+bool BackgroundSyncBrowserTest::GetTags(
const std::vector<std::string>& expected_tags) {
std::string script_result;
- EXPECT_TRUE(RunScript("getRegistrationsOneShot()", &script_result));
+ EXPECT_TRUE(RunScript("getTags()", &script_result));
- return MatchRegistrations(script_result, expected_tags);
+ return MatchTags(script_result, expected_tags);
}
-bool BackgroundSyncBrowserTest::GetRegistrationsOneShotFromServiceWorker(
+bool BackgroundSyncBrowserTest::GetTagsFromServiceWorker(
const std::vector<std::string>& expected_tags) {
std::string script_result;
- EXPECT_TRUE(
- RunScript("getRegistrationsOneShotFromServiceWorker()", &script_result));
- EXPECT_TRUE(script_result == "ok - getRegistrations sent to SW");
+ EXPECT_TRUE(RunScript("getTagsFromServiceWorker()", &script_result));
+ EXPECT_TRUE(script_result == "ok - getTags sent to SW");
- return MatchRegistrations(PopConsoleString(), expected_tags);
+ return MatchTags(PopConsoleString(), expected_tags);
}
-bool BackgroundSyncBrowserTest::CompleteDelayedOneShot() {
+bool BackgroundSyncBrowserTest::CompleteDelayedSyncEvent() {
std::string script_result;
- EXPECT_TRUE(RunScript("completeDelayedOneShot()", &script_result));
+ EXPECT_TRUE(RunScript("completeDelayedSyncEvent()", &script_result));
return script_result == BuildExpectedResult("delay", "completing");
}
-bool BackgroundSyncBrowserTest::RejectDelayedOneShot() {
+bool BackgroundSyncBrowserTest::RejectDelayedSyncEvent() {
std::string script_result;
- EXPECT_TRUE(RunScript("rejectDelayedOneShot()", &script_result));
+ EXPECT_TRUE(RunScript("rejectDelayedSyncEvent()", &script_result));
return script_result == BuildExpectedResult("delay", "rejecting");
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, OneShotFiresControlled) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ RegisterFromControlledDocument) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
- EXPECT_TRUE(RegisterOneShot("foo"));
+ EXPECT_TRUE(Register("foo"));
EXPECT_TRUE(PopConsole("foo fired"));
- EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_FALSE(HasTag("foo"));
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, OneShotFiresUncontrolled) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ RegisterFromUncontrolledDocument) {
EXPECT_TRUE(RegisterServiceWorker());
- EXPECT_TRUE(RegisterOneShot("foo"));
+ EXPECT_TRUE(Register("foo"));
EXPECT_TRUE(PopConsole("foo fired"));
- EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_FALSE(HasTag("foo"));
}
// Verify that Register works in a service worker
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
- OneShotFromServiceWorkerFires) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, RegisterFromServiceWorker) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
- EXPECT_TRUE(RegisterOneShotFromServiceWorker("foo_sw"));
+ EXPECT_TRUE(RegisterFromServiceWorker("foo_sw"));
EXPECT_TRUE(PopConsole("ok - foo_sw registered in SW"));
EXPECT_TRUE(PopConsole("foo_sw fired"));
- EXPECT_FALSE(GetRegistrationOneShot("foo_sw"));
+ EXPECT_FALSE(HasTag("foo_sw"));
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, OneShotDelaysForNetwork) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ RegistrationDelaysForNetwork) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
// Prevent firing by going offline.
background_sync_test_util::SetOnline(web_contents(), false);
- EXPECT_TRUE(RegisterOneShot("foo"));
- EXPECT_TRUE(GetRegistrationOneShot("foo"));
- EXPECT_TRUE(OneShotPending("foo"));
+ EXPECT_TRUE(Register("foo"));
+ EXPECT_TRUE(HasTag("foo"));
+ EXPECT_TRUE(RegistrationPending("foo"));
// Resume firing by going online.
background_sync_test_util::SetOnline(web_contents(), true);
EXPECT_TRUE(PopConsole("foo fired"));
- EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_FALSE(HasTag("foo"));
}
IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, WaitUntil) {
@@ -409,18 +432,18 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, WaitUntil) {
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
background_sync_test_util::SetOnline(web_contents(), true);
- EXPECT_TRUE(RegisterOneShot("delay"));
+ EXPECT_TRUE(Register("delay"));
// Verify that it is firing.
- EXPECT_TRUE(GetRegistrationOneShot("delay"));
- EXPECT_FALSE(OneShotPending("delay"));
+ EXPECT_TRUE(HasTag("delay"));
+ EXPECT_FALSE(RegistrationPending("delay"));
// Complete the task.
- EXPECT_TRUE(CompleteDelayedOneShot());
+ EXPECT_TRUE(CompleteDelayedSyncEvent());
EXPECT_TRUE(PopConsole("ok - delay completed"));
// Verify that it finished firing.
- EXPECT_FALSE(GetRegistrationOneShot("delay"));
+ EXPECT_FALSE(HasTag("delay"));
}
IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, WaitUntilReject) {
@@ -428,16 +451,16 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, WaitUntilReject) {
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
background_sync_test_util::SetOnline(web_contents(), true);
- EXPECT_TRUE(RegisterOneShot("delay"));
+ EXPECT_TRUE(Register("delay"));
// Verify that it is firing.
- EXPECT_TRUE(GetRegistrationOneShot("delay"));
- EXPECT_FALSE(OneShotPending("delay"));
+ EXPECT_TRUE(HasTag("delay"));
+ EXPECT_FALSE(RegistrationPending("delay"));
// Complete the task.
- EXPECT_TRUE(RejectDelayedOneShot());
+ EXPECT_TRUE(RejectDelayedSyncEvent());
EXPECT_TRUE(PopConsole("ok - delay rejected"));
- EXPECT_FALSE(GetRegistrationOneShot("delay"));
+ EXPECT_FALSE(HasTag("delay"));
}
IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, Incognito) {
@@ -445,8 +468,8 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, Incognito) {
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
background_sync_test_util::SetOnline(web_contents(), false);
- EXPECT_TRUE(RegisterOneShot("normal"));
- EXPECT_TRUE(OneShotPending("normal"));
+ EXPECT_TRUE(Register("normal"));
+ EXPECT_TRUE(RegistrationPending("normal"));
// Go incognito and verify that incognito doesn't see the registration.
SetIncognitoMode(true);
@@ -459,34 +482,34 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, Incognito) {
EXPECT_TRUE(LoadTestPage(kDefaultTestURL));
EXPECT_TRUE(RegisterServiceWorker());
- EXPECT_FALSE(GetRegistrationOneShot("normal"));
+ EXPECT_FALSE(HasTag("normal"));
- EXPECT_TRUE(RegisterOneShot("incognito"));
- EXPECT_TRUE(OneShotPending("incognito"));
+ EXPECT_TRUE(Register("incognito"));
+ EXPECT_TRUE(RegistrationPending("incognito"));
// Switch back and make sure the registration is still there.
SetIncognitoMode(false);
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Should be controlled.
- EXPECT_TRUE(GetRegistrationOneShot("normal"));
- EXPECT_FALSE(GetRegistrationOneShot("incognito"));
+ EXPECT_TRUE(HasTag("normal"));
+ EXPECT_FALSE(HasTag("incognito"));
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, GetRegistrations) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, GetTags) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
std::vector<std::string> registered_tags;
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
background_sync_test_util::SetOnline(web_contents(), false);
registered_tags.push_back("foo");
registered_tags.push_back("bar");
for (const std::string& tag : registered_tags)
- EXPECT_TRUE(RegisterOneShot(tag));
+ EXPECT_TRUE(Register(tag));
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
}
// Verify that GetRegistrations works in a service worker
@@ -496,34 +519,33 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
std::vector<std::string> registered_tags;
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
background_sync_test_util::SetOnline(web_contents(), false);
registered_tags.push_back("foo_sw");
registered_tags.push_back("bar_sw");
for (const std::string& tag : registered_tags) {
- EXPECT_TRUE(RegisterOneShotFromServiceWorker(tag));
+ EXPECT_TRUE(RegisterFromServiceWorker(tag));
EXPECT_TRUE(PopConsole(BuildExpectedResult(tag, "registered in SW")));
}
- EXPECT_TRUE(GetRegistrationsOneShotFromServiceWorker(registered_tags));
+ EXPECT_TRUE(GetTagsFromServiceWorker(registered_tags));
}
// Verify that GetRegistration works in a service worker
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
- GetRegistrationFromServiceWorker) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, HasTagFromServiceWorker) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
std::vector<std::string> registered_tags;
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
background_sync_test_util::SetOnline(web_contents(), false);
- EXPECT_TRUE(RegisterOneShotFromServiceWorker("foo_sw"));
+ EXPECT_TRUE(RegisterFromServiceWorker("foo_sw"));
EXPECT_TRUE(PopConsole("ok - foo_sw registered in SW"));
- EXPECT_TRUE(GetRegistrationOneShotFromServiceWorker("foo_sw"));
+ EXPECT_TRUE(HasTagFromServiceWorker("foo_sw"));
}
// Verify that a background sync registration is deleted when site data is
@@ -535,15 +557,15 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
// Prevent firing by going offline.
background_sync_test_util::SetOnline(web_contents(), false);
- EXPECT_TRUE(RegisterOneShot("foo"));
- EXPECT_TRUE(GetRegistrationOneShot("foo"));
- EXPECT_TRUE(OneShotPending("foo"));
+ EXPECT_TRUE(Register("foo"));
+ EXPECT_TRUE(HasTag("foo"));
+ EXPECT_TRUE(RegistrationPending("foo"));
// Simulate a user clearing site data (including Service Workers, crucially),
// by clearing data from the storage partition.
ClearStoragePartitionData();
- EXPECT_FALSE(GetRegistrationOneShot("foo"));
+ EXPECT_FALSE(HasTag("foo"));
}
// Verify that a background sync registration, from a service worker, is deleted
@@ -554,19 +576,19 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
std::vector<std::string> registered_tags;
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
background_sync_test_util::SetOnline(web_contents(), false);
- EXPECT_TRUE(RegisterOneShotFromServiceWorker("foo_sw"));
+ EXPECT_TRUE(RegisterFromServiceWorker("foo_sw"));
EXPECT_TRUE(PopConsole("ok - foo_sw registered in SW"));
- EXPECT_TRUE(GetRegistrationOneShotFromServiceWorker("foo_sw"));
+ EXPECT_TRUE(HasTagFromServiceWorker("foo_sw"));
// Simulate a user clearing site data (including Service Workers, crucially),
// by clearing data from the storage partition.
ClearStoragePartitionData();
- EXPECT_FALSE(GetRegistrationOneShotFromServiceWorker("foo"));
+ EXPECT_FALSE(HasTagFromServiceWorker("foo"));
}
// Verify that multiple background sync registrations are deleted when site
@@ -577,26 +599,26 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
std::vector<std::string> registered_tags;
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
background_sync_test_util::SetOnline(web_contents(), false);
registered_tags.push_back("foo");
registered_tags.push_back("bar");
for (const std::string& tag : registered_tags)
- EXPECT_TRUE(RegisterOneShot(tag));
+ EXPECT_TRUE(Register(tag));
- EXPECT_TRUE(GetRegistrationsOneShot(registered_tags));
+ EXPECT_TRUE(GetTags(registered_tags));
for (const std::string& tag : registered_tags)
- EXPECT_TRUE(OneShotPending(tag));
+ EXPECT_TRUE(RegistrationPending(tag));
// Simulate a user clearing site data (including Service Workers, crucially),
// by clearing data from the storage partition.
ClearStoragePartitionData();
for (const std::string& tag : registered_tags)
- EXPECT_FALSE(GetRegistrationOneShot(tag));
+ EXPECT_FALSE(HasTag(tag));
}
// Verify that a sync event that is currently firing is deleted when site
@@ -607,58 +629,59 @@ IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
background_sync_test_util::SetOnline(web_contents(), true);
- EXPECT_TRUE(RegisterOneShot("delay"));
+ EXPECT_TRUE(Register("delay"));
// Verify that it is firing.
- EXPECT_TRUE(GetRegistrationOneShot("delay"));
- EXPECT_FALSE(OneShotPending("delay"));
+ EXPECT_TRUE(HasTag("delay"));
+ EXPECT_FALSE(RegistrationPending("delay"));
// Simulate a user clearing site data (including Service Workers, crucially),
// by clearing data from the storage partition.
ClearStoragePartitionData();
// Verify that it was deleted.
- EXPECT_FALSE(GetRegistrationOneShot("delay"));
+ EXPECT_FALSE(HasTag("delay"));
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, VerifyRetry) {
+// Disabled due to flakiness. See https://crbug.com/578952.
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, DISABLED_VerifyRetry) {
EXPECT_TRUE(RegisterServiceWorker());
EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
SetMaxSyncAttempts(2);
- EXPECT_TRUE(RegisterOneShot("delay"));
- EXPECT_TRUE(RejectDelayedOneShot());
+ EXPECT_TRUE(Register("delay"));
+ EXPECT_TRUE(RejectDelayedSyncEvent());
EXPECT_TRUE(PopConsole("ok - delay rejected"));
- // Verify that the oneshot is still around and waiting to try again.
- EXPECT_TRUE(OneShotPending("delay"));
+ // Verify that the registration is still around and waiting to try again.
+ EXPECT_TRUE(RegistrationPending("delay"));
}
-IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, RegisterFromNonMainFrame) {
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ RegisterFromIFrameWithMainFrameHost) {
std::string script_result;
GURL url = https_server()->GetURL(kEmptyURL);
+ EXPECT_TRUE(RunScript(BuildScriptString("registerFromLocalFrame", url.spec()),
+ &script_result));
+ EXPECT_EQ(BuildExpectedResult("iframe", "registered sync"), script_result);
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
+ RegisterFromIFrameWithoutMainFrameHost) {
+ std::string script_result;
EXPECT_TRUE(
- RunScript(BuildScriptString("registerOneShotFromLocalFrame", url.spec()),
- &script_result));
- EXPECT_EQ(BuildExpectedResult("iframe", "failed to register sync"),
+ RegisterFromCrossOriginFrame(kRegisterSyncFromIFrameURL, &script_result));
+ EXPECT_EQ(BuildExpectedResult("frame", "failed to register sync"),
script_result);
}
IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest,
RegisterFromServiceWorkerWithoutMainFrameHost) {
- // Start a second https server to use as a second origin.
- net::EmbeddedTestServer alt_server(net::EmbeddedTestServer::TYPE_HTTPS);
- alt_server.ServeFilesFromSourceDirectory("content/test/data");
- ASSERT_TRUE(alt_server.Start());
-
std::string script_result;
- GURL url = alt_server.GetURL(kRegisterSyncURL);
EXPECT_TRUE(
- RunScript(BuildScriptString("registerOneShotFromCrossOriginServiceWorker",
- url.spec()),
- &script_result));
- EXPECT_EQ(BuildExpectedResult("worker", "failed to register sync"),
+ RegisterFromCrossOriginFrame(kRegisterSyncFromSWURL, &script_result));
+ EXPECT_EQ(BuildExpectedResult("frame", "failed to register sync"),
script_result);
}
diff --git a/chromium/content/browser/background_sync/background_sync_context_impl.cc b/chromium/content/browser/background_sync/background_sync_context_impl.cc
index 009e8864b6f..bd92edb8650 100644
--- a/chromium/content/browser/background_sync/background_sync_context_impl.cc
+++ b/chromium/content/browser/background_sync/background_sync_context_impl.cc
@@ -43,7 +43,7 @@ void BackgroundSyncContextImpl::Shutdown() {
}
void BackgroundSyncContextImpl::CreateService(
- mojo::InterfaceRequest<BackgroundSyncService> request) {
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
@@ -68,8 +68,15 @@ BackgroundSyncManager* BackgroundSyncContextImpl::background_sync_manager()
return background_sync_manager_.get();
}
+void BackgroundSyncContextImpl::set_background_sync_manager_for_testing(
+ scoped_ptr<BackgroundSyncManager> manager) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ background_sync_manager_ = std::move(manager);
+}
+
void BackgroundSyncContextImpl::CreateBackgroundSyncManager(
- const scoped_refptr<ServiceWorkerContextWrapper>& context) {
+ scoped_refptr<ServiceWorkerContextWrapper> context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!background_sync_manager_);
@@ -77,7 +84,7 @@ void BackgroundSyncContextImpl::CreateBackgroundSyncManager(
}
void BackgroundSyncContextImpl::CreateServiceOnIOThread(
- mojo::InterfaceRequest<BackgroundSyncService> request) {
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(background_sync_manager_);
services_.insert(new BackgroundSyncServiceImpl(this, std::move(request)));
diff --git a/chromium/content/browser/background_sync/background_sync_context_impl.h b/chromium/content/browser/background_sync/background_sync_context_impl.h
index f30a6392728..1eebe700256 100644
--- a/chromium/content/browser/background_sync/background_sync_context_impl.h
+++ b/chromium/content/browser/background_sync/background_sync_context_impl.h
@@ -37,7 +37,8 @@ class CONTENT_EXPORT BackgroundSyncContextImpl : public BackgroundSyncContext {
// Create a BackgroundSyncServiceImpl that is owned by this. Call on the UI
// thread.
- void CreateService(mojo::InterfaceRequest<BackgroundSyncService> request);
+ void CreateService(
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request);
// Called by BackgroundSyncServiceImpl objects so that they can
// be deleted. Call on the IO thread.
@@ -49,14 +50,17 @@ class CONTENT_EXPORT BackgroundSyncContextImpl : public BackgroundSyncContext {
protected:
~BackgroundSyncContextImpl() override;
+ void set_background_sync_manager_for_testing(
+ scoped_ptr<BackgroundSyncManager> manager);
+
private:
friend class BackgroundSyncServiceImplTest;
- void CreateBackgroundSyncManager(
- const scoped_refptr<ServiceWorkerContextWrapper>& context);
+ virtual void CreateBackgroundSyncManager(
+ scoped_refptr<ServiceWorkerContextWrapper> context);
void CreateServiceOnIOThread(
- mojo::InterfaceRequest<BackgroundSyncService> request);
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request);
void ShutdownOnIO();
diff --git a/chromium/content/browser/background_sync/background_sync_manager.cc b/chromium/content/browser/background_sync/background_sync_manager.cc
index 926dbca6dc8..343dd05a4a4 100644
--- a/chromium/content/browser/background_sync/background_sync_manager.cc
+++ b/chromium/content/browser/background_sync/background_sync_manager.cc
@@ -15,8 +15,6 @@
#include "build/build_config.h"
#include "content/browser/background_sync/background_sync_metrics.h"
#include "content/browser/background_sync/background_sync_network_observer.h"
-#include "content/browser/background_sync/background_sync_power_observer.h"
-#include "content/browser/background_sync/background_sync_registration_handle.h"
#include "content/browser/background_sync/background_sync_registration_options.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_storage.h"
@@ -25,6 +23,8 @@
#include "content/public/browser/background_sync_controller.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_type.h"
#include "content/public/common/background_sync.mojom.h"
#if defined(OS_ANDROID)
@@ -33,35 +33,24 @@
namespace content {
-class BackgroundSyncManager::RefCountedRegistration
- : public base::RefCounted<RefCountedRegistration> {
- public:
- BackgroundSyncRegistration* value() { return &registration_; }
- const BackgroundSyncRegistration* value() const { return &registration_; }
-
- private:
- friend class base::RefCounted<RefCountedRegistration>;
- ~RefCountedRegistration() = default;
-
- BackgroundSyncRegistration registration_;
-};
-
namespace {
// The key used to index the background sync data in ServiceWorkerStorage.
const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
-void PostErrorResponse(
+void RecordFailureAndPostError(
BackgroundSyncStatus status,
const BackgroundSyncManager::StatusAndRegistrationCallback& callback) {
+ BackgroundSyncMetrics::CountRegisterFailure(status);
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, status,
- base::Passed(scoped_ptr<BackgroundSyncRegistrationHandle>())));
+ base::Passed(scoped_ptr<BackgroundSyncRegistration>())));
}
-// Returns nullptr if the controller cannot be accessed for any reason.
-BackgroundSyncController* GetBackgroundSyncControllerOnUIThread(
+// Returns nullptr if the browser context cannot be accessed for any reason.
+BrowserContext* GetBrowserContextOnUIThread(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -72,8 +61,42 @@ BackgroundSyncController* GetBackgroundSyncControllerOnUIThread(
if (!storage_partition_impl) // may be null in tests
return nullptr;
- return storage_partition_impl->browser_context()
- ->GetBackgroundSyncController();
+ return storage_partition_impl->browser_context();
+}
+
+// Returns nullptr if the controller cannot be accessed for any reason.
+BackgroundSyncController* GetBackgroundSyncControllerOnUIThread(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserContext* browser_context =
+ GetBrowserContextOnUIThread(service_worker_context);
+ if (!browser_context)
+ return nullptr;
+
+ return browser_context->GetBackgroundSyncController();
+}
+
+// Returns PermissionStatus::DENIED if the permission manager cannot be
+// accessed for any reason.
+blink::mojom::PermissionStatus GetBackgroundSyncPermissionOnUIThread(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
+ const GURL& origin) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserContext* browser_context =
+ GetBrowserContextOnUIThread(service_worker_context);
+ if (!browser_context)
+ return blink::mojom::PermissionStatus::DENIED;
+
+ PermissionManager* permission_manager =
+ browser_context->GetPermissionManager();
+ if (!permission_manager)
+ return blink::mojom::PermissionStatus::DENIED;
+
+ // The requesting origin always matches the embedding origin.
+ return permission_manager->GetPermissionStatus(
+ PermissionType::BACKGROUND_SYNC, origin, origin);
}
void NotifyBackgroundSyncRegisteredOnUIThread(
@@ -126,11 +149,12 @@ void OnSyncEventFinished(
const scoped_refptr<ServiceWorkerVersion>& active_version,
int request_id,
const ServiceWorkerVersion::StatusCallback& callback,
- ServiceWorkerEventStatus status) {
- TRACE_EVENT1("ServiceWorker", "BackgroundSyncManager::OnSyncEventFinished",
- "Request id", request_id);
- if (!active_version->FinishRequest(request_id))
+ mojom::ServiceWorkerEventStatus status) {
+ if (!active_version->FinishRequest(
+ request_id,
+ status == content::mojom::ServiceWorkerEventStatus::COMPLETED)) {
return;
+ }
callback.Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status));
}
@@ -141,6 +165,9 @@ BackgroundSyncManager::BackgroundSyncRegistrations::
: next_id(BackgroundSyncRegistration::kInitialId) {
}
+BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations(
+ const BackgroundSyncRegistrations& other) = default;
+
BackgroundSyncManager::BackgroundSyncRegistrations::
~BackgroundSyncRegistrations() {
}
@@ -162,74 +189,25 @@ BackgroundSyncManager::~BackgroundSyncManager() {
service_worker_context_->RemoveObserver(this);
}
-BackgroundSyncManager::RegistrationKey::RegistrationKey(
- const BackgroundSyncRegistration& registration)
- : RegistrationKey(registration.options()->tag,
- registration.options()->periodicity) {
-}
-
-BackgroundSyncManager::RegistrationKey::RegistrationKey(
- const BackgroundSyncRegistrationOptions& options)
- : RegistrationKey(options.tag, options.periodicity) {
-}
-
-BackgroundSyncManager::RegistrationKey::RegistrationKey(
- const std::string& tag,
- SyncPeriodicity periodicity)
- : value_(periodicity == SYNC_ONE_SHOT ? "o_" + tag : "p_" + tag) {
-}
-
void BackgroundSyncManager::Register(
int64_t sw_registration_id,
const BackgroundSyncRegistrationOptions& options,
- bool requested_from_service_worker,
const StatusAndRegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (disabled_) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
- return;
- }
-
- if (requested_from_service_worker) {
- op_scheduler_.ScheduleOperation(
- base::Bind(&BackgroundSyncManager::RegisterCheckIfHasMainFrame,
- weak_ptr_factory_.GetWeakPtr(), sw_registration_id, options,
- MakeStatusAndRegistrationCompletion(callback)));
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
return;
}
op_scheduler_.ScheduleOperation(
- base::Bind(&BackgroundSyncManager::RegisterImpl,
+ base::Bind(&BackgroundSyncManager::RegisterCheckIfHasMainFrame,
weak_ptr_factory_.GetWeakPtr(), sw_registration_id, options,
MakeStatusAndRegistrationCompletion(callback)));
}
-void BackgroundSyncManager::GetRegistration(
- int64_t sw_registration_id,
- const std::string& sync_registration_tag,
- SyncPeriodicity periodicity,
- const StatusAndRegistrationCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (disabled_) {
- PostErrorResponse(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
- return;
- }
-
- RegistrationKey registration_key(sync_registration_tag, periodicity);
-
- op_scheduler_.ScheduleOperation(base::Bind(
- &BackgroundSyncManager::GetRegistrationImpl,
- weak_ptr_factory_.GetWeakPtr(), sw_registration_id, registration_key,
- MakeStatusAndRegistrationCompletion(callback)));
-}
-
void BackgroundSyncManager::GetRegistrations(
int64_t sw_registration_id,
- SyncPeriodicity periodicity,
const StatusAndRegistrationsCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -238,30 +216,15 @@ void BackgroundSyncManager::GetRegistrations(
FROM_HERE,
base::Bind(
callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
- base::Passed(
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>(
- new ScopedVector<BackgroundSyncRegistrationHandle>()))));
+ base::Passed(scoped_ptr<ScopedVector<BackgroundSyncRegistration>>(
+ new ScopedVector<BackgroundSyncRegistration>()))));
return;
}
op_scheduler_.ScheduleOperation(
base::Bind(&BackgroundSyncManager::GetRegistrationsImpl,
weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
- periodicity, MakeStatusAndRegistrationsCompletion(callback)));
-}
-
-// Given a HandleId |handle_id|, return a new handle for the same
-// registration.
-scoped_ptr<BackgroundSyncRegistrationHandle>
-BackgroundSyncManager::DuplicateRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- scoped_refptr<RefCountedRegistration>* ref_registration =
- registration_handle_ids_.Lookup(handle_id);
- if (!ref_registration)
- return scoped_ptr<BackgroundSyncRegistrationHandle>();
- return CreateRegistrationHandle(ref_registration->get());
+ MakeStatusAndRegistrationsCompletion(callback)));
}
void BackgroundSyncManager::OnRegistrationDeleted(int64_t sw_registration_id,
@@ -316,8 +279,6 @@ BackgroundSyncManager::BackgroundSyncManager(
base::Bind(&BackgroundSyncManager::OnNetworkChanged,
weak_ptr_factory_.GetWeakPtr())));
#endif
- power_observer_.reset(new BackgroundSyncPowerObserver(base::Bind(
- &BackgroundSyncManager::OnPowerChanged, weak_ptr_factory_.GetWeakPtr())));
}
void BackgroundSyncManager::Init() {
@@ -400,20 +361,12 @@ void BackgroundSyncManager::InitDidGetDataFromBackend(
break;
}
- RegistrationKey registration_key(registration_proto.tag(),
- registration_proto.periodicity());
-
- scoped_refptr<RefCountedRegistration> ref_registration(
- new RefCountedRegistration());
- registrations->registration_map[registration_key] = ref_registration;
- BackgroundSyncRegistration* registration = ref_registration->value();
+ BackgroundSyncRegistration* registration =
+ &registrations->registration_map[registration_proto.tag()];
BackgroundSyncRegistrationOptions* options = registration->options();
options->tag = registration_proto.tag();
- options->periodicity = registration_proto.periodicity();
- options->min_period = registration_proto.min_period();
options->network_state = registration_proto.network_state();
- options->power_state = registration_proto.power_state();
registration->set_id(registration_proto.id());
registration->set_num_attempts(registration_proto.num_attempts());
@@ -447,9 +400,8 @@ void BackgroundSyncManager::RegisterCheckIfHasMainFrame(
ServiceWorkerRegistration* sw_registration =
service_worker_context_->GetLiveRegistration(sw_registration_id);
if (!sw_registration || !sw_registration->active_version()) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER,
+ callback);
return;
}
@@ -468,9 +420,7 @@ void BackgroundSyncManager::RegisterDidCheckIfMainFrame(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!has_main_frame_client) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_NOT_ALLOWED);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback);
return;
}
RegisterImpl(sw_registration_id, options, callback);
@@ -483,25 +433,53 @@ void BackgroundSyncManager::RegisterImpl(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (disabled_) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
return;
}
if (options.tag.length() > kMaxTagLength) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_NOT_ALLOWED);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback);
return;
}
ServiceWorkerRegistration* sw_registration =
service_worker_context_->GetLiveRegistration(sw_registration_id);
if (!sw_registration || !sw_registration->active_version()) {
- BackgroundSyncMetrics::CountRegisterFailure(
- options.periodicity, BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER,
+ callback);
+ return;
+ }
+
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&GetBackgroundSyncPermissionOnUIThread,
+ service_worker_context_,
+ sw_registration->pattern().GetOrigin()),
+ base::Bind(&BackgroundSyncManager::RegisterDidAskForPermission,
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id, options,
+ callback));
+}
+
+void BackgroundSyncManager::RegisterDidAskForPermission(
+ int64_t sw_registration_id,
+ const BackgroundSyncRegistrationOptions& options,
+ const StatusAndRegistrationCallback& callback,
+ blink::mojom::PermissionStatus permission_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (permission_status == blink::mojom::PermissionStatus::DENIED) {
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_PERMISSION_DENIED,
+ callback);
+ return;
+ }
+ DCHECK(permission_status == blink::mojom::PermissionStatus::GRANTED);
+
+ ServiceWorkerRegistration* sw_registration =
+ service_worker_context_->GetLiveRegistration(sw_registration_id);
+ if (!sw_registration || !sw_registration->active_version()) {
+ // The service worker was shut down in the interim.
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER,
+ callback);
return;
}
@@ -510,57 +488,49 @@ void BackgroundSyncManager::RegisterImpl(
service_worker_context_,
sw_registration->pattern().GetOrigin()));
- RefCountedRegistration* existing_registration_ref =
- LookupActiveRegistration(sw_registration_id, RegistrationKey(options));
- if (existing_registration_ref) {
- if (existing_registration_ref->value()->options()->Equals(options)) {
- BackgroundSyncRegistration* existing_registration =
- existing_registration_ref->value();
-
- BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
- AreOptionConditionsMet(options)
- ? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
- : BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
- BackgroundSyncMetrics::CountRegisterSuccess(
- existing_registration->options()->periodicity,
- registration_could_fire,
- BackgroundSyncMetrics::REGISTRATION_IS_DUPLICATE);
+ BackgroundSyncRegistration* existing_registration =
+ LookupActiveRegistration(sw_registration_id, options.tag);
+ if (existing_registration) {
+ DCHECK(existing_registration->options()->Equals(options));
+
+ BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
+ AreOptionConditionsMet(options)
+ ? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
+ : BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
+ BackgroundSyncMetrics::CountRegisterSuccess(
+ registration_could_fire,
+ BackgroundSyncMetrics::REGISTRATION_IS_DUPLICATE);
if (existing_registration->IsFiring()) {
existing_registration->set_sync_state(
- BACKGROUND_SYNC_STATE_REREGISTERED_WHILE_FIRING);
+ mojom::BackgroundSyncState::REREGISTERED_WHILE_FIRING);
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
- callback, BACKGROUND_SYNC_STATUS_OK,
- base::Passed(CreateRegistrationHandle(existing_registration_ref))));
+ base::Bind(callback, BACKGROUND_SYNC_STATUS_OK,
+ base::Passed(make_scoped_ptr(new BackgroundSyncRegistration(
+ *existing_registration)))));
return;
- } else {
- existing_registration_ref->value()->SetUnregisteredState();
- }
}
- scoped_refptr<RefCountedRegistration> new_ref_registration(
- new RefCountedRegistration());
- BackgroundSyncRegistration* new_registration = new_ref_registration->value();
+ BackgroundSyncRegistration new_registration;
- *new_registration->options() = options;
+ *new_registration.options() = options;
BackgroundSyncRegistrations* registrations =
&active_registrations_[sw_registration_id];
- new_registration->set_id(registrations->next_id++);
+ new_registration.set_id(registrations->next_id++);
AddActiveRegistration(sw_registration_id,
sw_registration->pattern().GetOrigin(),
- new_ref_registration);
+ new_registration);
StoreRegistrations(
sw_registration_id,
base::Bind(&BackgroundSyncManager::RegisterDidStore,
weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
- new_ref_registration, callback));
+ new_registration, callback));
}
void BackgroundSyncManager::DisableAndClearManager(
@@ -575,15 +545,6 @@ void BackgroundSyncManager::DisableAndClearManager(
disabled_ = true;
- for (auto& sw_id_and_registrations : active_registrations_) {
- for (auto& key_and_registration :
- sw_id_and_registrations.second.registration_map) {
- BackgroundSyncRegistration* registration =
- key_and_registration.second->value();
- registration->SetUnregisteredState();
- }
- }
-
active_registrations_.clear();
// Delete all backend entries. The memory representation of registered syncs
@@ -628,10 +589,9 @@ void BackgroundSyncManager::DisableAndClearManagerClearedOne(
base::Bind(barrier_closure));
}
-BackgroundSyncManager::RefCountedRegistration*
-BackgroundSyncManager::LookupActiveRegistration(
+BackgroundSyncRegistration* BackgroundSyncManager::LookupActiveRegistration(
int64_t sw_registration_id,
- const RegistrationKey& registration_key) {
+ const std::string& tag) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
SWIdToRegistrationsMap::iterator it =
@@ -643,12 +603,11 @@ BackgroundSyncManager::LookupActiveRegistration(
DCHECK_LE(BackgroundSyncRegistration::kInitialId, registrations.next_id);
DCHECK(!registrations.origin.is_empty());
- auto key_and_registration_iter =
- registrations.registration_map.find(registration_key);
+ auto key_and_registration_iter = registrations.registration_map.find(tag);
if (key_and_registration_iter == registrations.registration_map.end())
return nullptr;
- return key_and_registration_iter->second.get();
+ return &key_and_registration_iter->second;
}
void BackgroundSyncManager::StoreRegistrations(
@@ -665,16 +624,13 @@ void BackgroundSyncManager::StoreRegistrations(
for (const auto& key_and_registration : registrations.registration_map) {
const BackgroundSyncRegistration& registration =
- *key_and_registration.second->value();
+ key_and_registration.second;
BackgroundSyncRegistrationProto* registration_proto =
registrations_proto.add_registration();
registration_proto->set_id(registration.id());
registration_proto->set_tag(registration.options()->tag);
- registration_proto->set_periodicity(registration.options()->periodicity);
- registration_proto->set_min_period(registration.options()->min_period);
registration_proto->set_network_state(
registration.options()->network_state);
- registration_proto->set_power_state(registration.options()->power_state);
registration_proto->set_num_attempts(registration.num_attempts());
registration_proto->set_delay_until(
registration.delay_until().ToInternalValue());
@@ -689,21 +645,15 @@ void BackgroundSyncManager::StoreRegistrations(
void BackgroundSyncManager::RegisterDidStore(
int64_t sw_registration_id,
- const scoped_refptr<RefCountedRegistration>& new_registration_ref,
+ const BackgroundSyncRegistration& new_registration,
const StatusAndRegistrationCallback& callback,
ServiceWorkerStatusCode status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- const BackgroundSyncRegistration* new_registration =
- new_registration_ref->value();
-
if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
// The service worker registration is gone.
- BackgroundSyncMetrics::CountRegisterFailure(
- new_registration->options()->periodicity,
- BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
active_registrations_.erase(sw_registration_id);
- PostErrorResponse(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
+ RecordFailureAndPostError(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
return;
}
@@ -711,55 +661,54 @@ void BackgroundSyncManager::RegisterDidStore(
LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
"failure.";
BackgroundSyncMetrics::CountRegisterFailure(
- new_registration->options()->periodicity,
BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- DisableAndClearManager(base::Bind(
- callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
- base::Passed(scoped_ptr<BackgroundSyncRegistrationHandle>())));
+ DisableAndClearManager(
+ base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
+ base::Passed(scoped_ptr<BackgroundSyncRegistration>())));
return;
}
BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
- AreOptionConditionsMet(*new_registration->options())
+ AreOptionConditionsMet(*new_registration.options())
? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
: BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
BackgroundSyncMetrics::CountRegisterSuccess(
- new_registration->options()->periodicity, registration_could_fire,
+ registration_could_fire,
BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE);
FireReadyEvents();
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(
- callback, BACKGROUND_SYNC_STATUS_OK,
- base::Passed(CreateRegistrationHandle(new_registration_ref.get()))));
+ base::Bind(callback, BACKGROUND_SYNC_STATUS_OK,
+ base::Passed(make_scoped_ptr(
+ new BackgroundSyncRegistration(new_registration)))));
}
-void BackgroundSyncManager::RemoveActiveRegistration(
- int64_t sw_registration_id,
- const RegistrationKey& registration_key) {
+void BackgroundSyncManager::RemoveActiveRegistration(int64_t sw_registration_id,
+ const std::string& tag) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(LookupActiveRegistration(sw_registration_id, registration_key));
+ DCHECK(LookupActiveRegistration(sw_registration_id, tag));
BackgroundSyncRegistrations* registrations =
&active_registrations_[sw_registration_id];
- registrations->registration_map.erase(registration_key);
+ registrations->registration_map.erase(tag);
}
void BackgroundSyncManager::AddActiveRegistration(
int64_t sw_registration_id,
const GURL& origin,
- const scoped_refptr<RefCountedRegistration>& sync_registration) {
+ const BackgroundSyncRegistration& sync_registration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(sync_registration->value()->IsValid());
+ DCHECK(sync_registration.IsValid());
BackgroundSyncRegistrations* registrations =
&active_registrations_[sw_registration_id];
registrations->origin = origin;
- RegistrationKey registration_key(*sync_registration->value());
- registrations->registration_map[registration_key] = sync_registration;
+ registrations->registration_map[sync_registration.options()->tag] =
+ sync_registration;
}
void BackgroundSyncManager::StoreDataInBackend(
@@ -784,19 +733,21 @@ void BackgroundSyncManager::GetDataFromBackend(
callback);
}
-void BackgroundSyncManager::FireOneShotSync(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
+void BackgroundSyncManager::DispatchSyncEvent(
+ const std::string& tag,
const scoped_refptr<ServiceWorkerVersion>& active_version,
- BackgroundSyncEventLastChance last_chance,
+ mojom::BackgroundSyncEventLastChance last_chance,
const ServiceWorkerVersion::StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(active_version);
if (active_version->running_status() != ServiceWorkerVersion::RUNNING) {
active_version->RunAfterStartWorker(
- callback, base::Bind(&BackgroundSyncManager::FireOneShotSync,
- weak_ptr_factory_.GetWeakPtr(), handle_id,
- active_version, last_chance, callback));
+ ServiceWorkerMetrics::EventType::SYNC,
+ base::Bind(&BackgroundSyncManager::DispatchSyncEvent,
+ weak_ptr_factory_.GetWeakPtr(), tag, active_version,
+ last_chance, callback),
+ callback);
return;
}
@@ -804,16 +755,13 @@ void BackgroundSyncManager::FireOneShotSync(
ServiceWorkerMetrics::EventType::SYNC, callback,
parameters_->max_sync_event_duration,
ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
- base::WeakPtr<BackgroundSyncServiceClient> client =
- active_version->GetMojoServiceForRequest<BackgroundSyncServiceClient>(
- request_id);
-
- // The ServiceWorkerVersion doesn't know when the client (javascript) is done
- // with the registration so don't give it a BackgroundSyncRegistrationHandle.
- // Once the render process gets the handle_id it can create its own handle
- // (with a new unique handle id).
+ base::WeakPtr<mojom::BackgroundSyncServiceClient> client =
+ active_version
+ ->GetMojoServiceForRequest<mojom::BackgroundSyncServiceClient>(
+ request_id);
+
client->Sync(
- handle_id, last_chance,
+ tag, last_chance,
base::Bind(&OnSyncEventFinished, active_version, request_id, callback));
}
@@ -829,221 +777,13 @@ void BackgroundSyncManager::HasMainFrameProviderHost(
service_worker_context_->HasMainFrameProviderHost(origin, callback);
}
-scoped_ptr<BackgroundSyncRegistrationHandle>
-BackgroundSyncManager::CreateRegistrationHandle(
- const scoped_refptr<RefCountedRegistration>& registration) {
- scoped_refptr<RefCountedRegistration>* ptr =
- new scoped_refptr<RefCountedRegistration>(registration);
-
- // Registration handles have unique handle ids. The handle id maps to an
- // internal RefCountedRegistration (which has the persistent registration id)
- // via
- // registration_reference_ids_.
- BackgroundSyncRegistrationHandle::HandleId handle_id =
- registration_handle_ids_.Add(ptr);
-
- return make_scoped_ptr(new BackgroundSyncRegistrationHandle(
- weak_ptr_factory_.GetWeakPtr(), handle_id));
-}
-
-BackgroundSyncRegistration* BackgroundSyncManager::GetRegistrationForHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id) const {
- scoped_refptr<RefCountedRegistration>* ref_registration =
- registration_handle_ids_.Lookup(handle_id);
- if (!ref_registration)
- return nullptr;
- return (*ref_registration)->value();
-}
-
-void BackgroundSyncManager::ReleaseRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(registration_handle_ids_.Lookup(handle_id));
- registration_handle_ids_.Remove(handle_id);
-}
-
-void BackgroundSyncManager::Unregister(
- int64_t sw_registration_id,
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const StatusCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- BackgroundSyncRegistration* registration =
- GetRegistrationForHandle(handle_id);
- DCHECK(registration);
-
- if (disabled_) {
- BackgroundSyncMetrics::CountUnregister(
- registration->options()->periodicity,
- BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR));
- return;
- }
-
- op_scheduler_.ScheduleOperation(base::Bind(
- &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
- sw_registration_id, RegistrationKey(*registration), registration->id(),
- registration->options()->periodicity, MakeStatusCompletion(callback)));
-}
-
-void BackgroundSyncManager::UnregisterImpl(
- int64_t sw_registration_id,
- const RegistrationKey& registration_key,
- BackgroundSyncRegistration::RegistrationId sync_registration_id,
- SyncPeriodicity periodicity,
- const StatusCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (disabled_) {
- BackgroundSyncMetrics::CountUnregister(
- periodicity, BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR));
- return;
- }
-
- RefCountedRegistration* existing_registration =
- LookupActiveRegistration(sw_registration_id, registration_key);
-
- if (!existing_registration ||
- existing_registration->value()->id() != sync_registration_id) {
- BackgroundSyncMetrics::CountUnregister(periodicity,
- BACKGROUND_SYNC_STATUS_NOT_FOUND);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_NOT_FOUND));
- return;
- }
-
- existing_registration->value()->SetUnregisteredState();
-
- RemoveActiveRegistration(sw_registration_id, registration_key);
-
- StoreRegistrations(sw_registration_id,
- base::Bind(&BackgroundSyncManager::UnregisterDidStore,
- weak_ptr_factory_.GetWeakPtr(),
- sw_registration_id, periodicity, callback));
-}
-
-void BackgroundSyncManager::UnregisterDidStore(int64_t sw_registration_id,
- SyncPeriodicity periodicity,
- const StatusCallback& callback,
- ServiceWorkerStatusCode status) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
- // ServiceWorker was unregistered.
- BackgroundSyncMetrics::CountUnregister(
- periodicity, BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- active_registrations_.erase(sw_registration_id);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR));
- return;
- }
-
- if (status != SERVICE_WORKER_OK) {
- LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
- BackgroundSyncMetrics::CountUnregister(
- periodicity, BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
- DisableAndClearManager(
- base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR));
- return;
- }
-
- BackgroundSyncMetrics::CountUnregister(periodicity,
- BACKGROUND_SYNC_STATUS_OK);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_OK));
-}
-
-void BackgroundSyncManager::NotifyWhenFinished(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const StatusAndStateCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (disabled_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
- BACKGROUND_SYNC_STATE_FAILED));
- return;
- }
-
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle =
- DuplicateRegistrationHandle(handle_id);
-
- op_scheduler_.ScheduleOperation(
- base::Bind(&BackgroundSyncManager::NotifyWhenFinishedImpl,
- weak_ptr_factory_.GetWeakPtr(),
- base::Passed(std::move(registration_handle)), callback));
-}
-
-void BackgroundSyncManager::NotifyWhenFinishedImpl(
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
- const StatusAndStateCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK_EQ(SYNC_ONE_SHOT, registration_handle->options()->periodicity);
-
- if (disabled_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_STORAGE_ERROR,
- BACKGROUND_SYNC_STATE_FAILED));
- return;
- }
-
- if (!registration_handle->registration()->HasCompleted()) {
- registration_handle->registration()->AddFinishedCallback(
- base::Bind(&BackgroundSyncManager::NotifyWhenFinishedInvokeCallback,
- weak_ptr_factory_.GetWeakPtr(), callback));
- op_scheduler_.CompleteOperationAndRunNext();
- return;
- }
-
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, BACKGROUND_SYNC_STATUS_OK,
- registration_handle->sync_state()));
- op_scheduler_.CompleteOperationAndRunNext();
-}
-
-void BackgroundSyncManager::NotifyWhenFinishedInvokeCallback(
- const StatusAndStateCallback& callback,
- BackgroundSyncState sync_state) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- callback.Run(BACKGROUND_SYNC_STATUS_OK, sync_state);
-}
-
-void BackgroundSyncManager::GetRegistrationImpl(
- int64_t sw_registration_id,
- const RegistrationKey& registration_key,
- const StatusAndRegistrationCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (disabled_) {
- PostErrorResponse(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback);
- return;
- }
-
- RefCountedRegistration* registration =
- LookupActiveRegistration(sw_registration_id, registration_key);
- if (!registration) {
- PostErrorResponse(BACKGROUND_SYNC_STATUS_NOT_FOUND, callback);
- return;
- }
-
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(callback, BACKGROUND_SYNC_STATUS_OK,
- base::Passed(CreateRegistrationHandle(registration))));
-}
-
void BackgroundSyncManager::GetRegistrationsImpl(
int64_t sw_registration_id,
- SyncPeriodicity periodicity,
const StatusAndRegistrationsCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>> out_registrations(
- new ScopedVector<BackgroundSyncRegistrationHandle>());
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> out_registrations(
+ new ScopedVector<BackgroundSyncRegistration>());
if (disabled_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1058,11 +798,11 @@ void BackgroundSyncManager::GetRegistrationsImpl(
if (it != active_registrations_.end()) {
const BackgroundSyncRegistrations& registrations = it->second;
for (const auto& tag_and_registration : registrations.registration_map) {
- RefCountedRegistration* registration = tag_and_registration.second.get();
- if (registration->value()->options()->periodicity == periodicity) {
- out_registrations->push_back(
- CreateRegistrationHandle(registration).release());
- }
+ const BackgroundSyncRegistration& registration =
+ tag_and_registration.second;
+ BackgroundSyncRegistration* out_registration =
+ new BackgroundSyncRegistration(registration);
+ out_registrations->push_back(out_registration);
}
}
@@ -1074,26 +814,19 @@ void BackgroundSyncManager::GetRegistrationsImpl(
bool BackgroundSyncManager::AreOptionConditionsMet(
const BackgroundSyncRegistrationOptions& options) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return network_observer_->NetworkSufficient(options.network_state) &&
- power_observer_->PowerSufficient(options.power_state);
+ return network_observer_->NetworkSufficient(options.network_state);
}
bool BackgroundSyncManager::IsRegistrationReadyToFire(
const BackgroundSyncRegistration& registration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // TODO(jkarlin): Add support for firing periodic registrations.
- if (registration.options()->periodicity == SYNC_PERIODIC)
- return false;
-
- if (registration.sync_state() != BACKGROUND_SYNC_STATE_PENDING)
+ if (registration.sync_state() != mojom::BackgroundSyncState::PENDING)
return false;
if (clock_->Now() < registration.delay_until())
return false;
- DCHECK_EQ(SYNC_ONE_SHOT, registration.options()->periodicity);
-
return AreOptionConditionsMet(*registration.options());
}
@@ -1105,20 +838,15 @@ void BackgroundSyncManager::RunInBackgroundIfNecessary() {
for (const auto& key_and_registration :
sw_id_and_registrations.second.registration_map) {
const BackgroundSyncRegistration& registration =
- *key_and_registration.second->value();
- if (registration.sync_state() == BACKGROUND_SYNC_STATE_PENDING) {
- if (registration.options()->periodicity == SYNC_ONE_SHOT) {
- if (clock_->Now() >= registration.delay_until()) {
- soonest_wakeup_delta = base::TimeDelta();
- } else {
- base::TimeDelta delay_delta =
- registration.delay_until() - clock_->Now();
- if (delay_delta < soonest_wakeup_delta)
- soonest_wakeup_delta = delay_delta;
- }
+ key_and_registration.second;
+ if (registration.sync_state() == mojom::BackgroundSyncState::PENDING) {
+ if (clock_->Now() >= registration.delay_until()) {
+ soonest_wakeup_delta = base::TimeDelta();
} else {
- // TODO(jkarlin): Support keeping the browser alive for periodic
- // syncs.
+ base::TimeDelta delay_delta =
+ registration.delay_until() - clock_->Now();
+ if (delay_delta < soonest_wakeup_delta)
+ soonest_wakeup_delta = delay_delta;
}
}
}
@@ -1170,26 +898,25 @@ void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
}
// Find the registrations that are ready to run.
- std::vector<std::pair<int64_t, RegistrationKey>> sw_id_and_keys_to_fire;
+ std::vector<std::pair<int64_t, std::string>> sw_id_and_tags_to_fire;
for (auto& sw_id_and_registrations : active_registrations_) {
const int64_t service_worker_id = sw_id_and_registrations.first;
for (auto& key_and_registration :
sw_id_and_registrations.second.registration_map) {
- BackgroundSyncRegistration* registration =
- key_and_registration.second->value();
+ BackgroundSyncRegistration* registration = &key_and_registration.second;
if (IsRegistrationReadyToFire(*registration)) {
- sw_id_and_keys_to_fire.push_back(
+ sw_id_and_tags_to_fire.push_back(
std::make_pair(service_worker_id, key_and_registration.first));
// The state change is not saved to persistent storage because
// if the sync event is killed mid-sync then it should return to
// SYNC_STATE_PENDING.
- registration->set_sync_state(BACKGROUND_SYNC_STATE_FIRING);
+ registration->set_sync_state(mojom::BackgroundSyncState::FIRING);
}
}
}
- if (sw_id_and_keys_to_fire.empty()) {
+ if (sw_id_and_tags_to_fire.empty()) {
RunInBackgroundIfNecessary();
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback));
@@ -1201,33 +928,33 @@ void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
// Fire the sync event of the ready registrations and run |callback| once
// they're all done.
base::Closure events_fired_barrier_closure = base::BarrierClosure(
- sw_id_and_keys_to_fire.size(),
+ sw_id_and_tags_to_fire.size(),
base::Bind(&BackgroundSyncManager::FireReadyEventsAllEventsFiring,
weak_ptr_factory_.GetWeakPtr(), callback));
// Record the total time taken after all events have run to completion.
base::Closure events_completed_barrier_closure =
- base::BarrierClosure(sw_id_and_keys_to_fire.size(),
+ base::BarrierClosure(sw_id_and_tags_to_fire.size(),
base::Bind(&OnAllSyncEventsCompleted, start_time,
- sw_id_and_keys_to_fire.size()));
+ sw_id_and_tags_to_fire.size()));
- for (const auto& sw_id_and_key : sw_id_and_keys_to_fire) {
- int64_t service_worker_id = sw_id_and_key.first;
- const RefCountedRegistration* registration =
- LookupActiveRegistration(service_worker_id, sw_id_and_key.second);
+ for (const auto& sw_id_and_tag : sw_id_and_tags_to_fire) {
+ int64_t service_worker_id = sw_id_and_tag.first;
+ const BackgroundSyncRegistration* registration =
+ LookupActiveRegistration(service_worker_id, sw_id_and_tag.second);
DCHECK(registration);
service_worker_context_->FindReadyRegistrationForId(
service_worker_id, active_registrations_[service_worker_id].origin,
base::Bind(&BackgroundSyncManager::FireReadyEventsDidFindRegistration,
- weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second,
- registration->value()->id(), events_fired_barrier_closure,
+ weak_ptr_factory_.GetWeakPtr(), sw_id_and_tag.second,
+ registration->id(), events_fired_barrier_closure,
events_completed_barrier_closure));
}
}
void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
- const RegistrationKey& registration_key,
+ const std::string& tag,
BackgroundSyncRegistration::RegistrationId registration_id,
const base::Closure& event_fired_callback,
const base::Closure& event_completed_callback,
@@ -1243,37 +970,27 @@ void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
return;
}
- RefCountedRegistration* registration = LookupActiveRegistration(
- service_worker_registration->id(), registration_key);
+ BackgroundSyncRegistration* registration =
+ LookupActiveRegistration(service_worker_registration->id(), tag);
DCHECK(registration);
- // Create a handle and keep it until the sync event completes. The client can
- // acquire its own handle for longer-term use.
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle =
- CreateRegistrationHandle(registration);
-
num_firing_registrations_ += 1;
- BackgroundSyncRegistrationHandle::HandleId handle_id =
- registration_handle->handle_id();
-
- BackgroundSyncEventLastChance last_chance =
- registration->value()->num_attempts() ==
- parameters_->max_sync_attempts - 1
- ? BACKGROUND_SYNC_EVENT_LAST_CHANCE_IS_LAST_CHANCE
- : BACKGROUND_SYNC_EVENT_LAST_CHANCE_IS_NOT_LAST_CHANCE;
+ mojom::BackgroundSyncEventLastChance last_chance =
+ registration->num_attempts() == parameters_->max_sync_attempts - 1
+ ? mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE
+ : mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE;
HasMainFrameProviderHost(
service_worker_registration->pattern().GetOrigin(),
- base::Bind(&BackgroundSyncMetrics::RecordEventStarted,
- registration->value()->options()->periodicity));
+ base::Bind(&BackgroundSyncMetrics::RecordEventStarted));
- FireOneShotSync(
- handle_id, service_worker_registration->active_version(), last_chance,
+ DispatchSyncEvent(
+ registration->options()->tag,
+ service_worker_registration->active_version(), last_chance,
base::Bind(&BackgroundSyncManager::EventComplete,
weak_ptr_factory_.GetWeakPtr(), service_worker_registration,
- service_worker_registration->id(),
- base::Passed(std::move(registration_handle)),
+ service_worker_registration->id(), tag,
event_completed_callback));
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1294,34 +1011,48 @@ void BackgroundSyncManager::FireReadyEventsAllEventsFiring(
void BackgroundSyncManager::EventComplete(
const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
int64_t service_worker_id,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
+ const std::string& tag,
const base::Closure& callback,
ServiceWorkerStatusCode status_code) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Do not check for disabled as events that were firing when disabled should
- // be allowed to complete (for NotifyWhenFinished).
+ if (disabled_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback));
+ return;
+ }
+
op_scheduler_.ScheduleOperation(base::Bind(
&BackgroundSyncManager::EventCompleteImpl, weak_ptr_factory_.GetWeakPtr(),
- service_worker_id, base::Passed(std::move(registration_handle)),
- status_code, MakeClosureCompletion(callback)));
+ service_worker_id, tag, status_code, MakeClosureCompletion(callback)));
}
void BackgroundSyncManager::EventCompleteImpl(
int64_t service_worker_id,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
+ const std::string& tag,
ServiceWorkerStatusCode status_code,
const base::Closure& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (disabled_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback));
+ return;
+ }
+
+ num_firing_registrations_ -= 1;
+
BackgroundSyncRegistration* registration =
- registration_handle->registration();
- DCHECK(registration);
- DCHECK(!registration->HasCompleted());
+ LookupActiveRegistration(service_worker_id, tag);
+ if (!registration) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback));
+ return;
+ }
- registration->set_num_attempts(registration->num_attempts() + 1);
+ DCHECK_NE(mojom::BackgroundSyncState::PENDING, registration->sync_state());
- num_firing_registrations_ -= 1;
+ registration->set_num_attempts(registration->num_attempts() + 1);
// The event ran to completion, we should count it, no matter what happens
// from here.
@@ -1331,58 +1062,36 @@ void BackgroundSyncManager::EventCompleteImpl(
HasMainFrameProviderHost(
sw_registration->pattern().GetOrigin(),
base::Bind(&BackgroundSyncMetrics::RecordEventResult,
- registration->options()->periodicity,
status_code == SERVICE_WORKER_OK));
}
- if (registration->options()->periodicity == SYNC_ONE_SHOT) {
- if (registration->sync_state() ==
- BACKGROUND_SYNC_STATE_REREGISTERED_WHILE_FIRING) {
- registration->set_sync_state(BACKGROUND_SYNC_STATE_PENDING);
- registration->set_num_attempts(0);
- } else if (status_code != SERVICE_WORKER_OK) { // Sync failed
- bool can_retry =
- registration->num_attempts() < parameters_->max_sync_attempts;
- if (registration->sync_state() ==
- BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING) {
- registration->set_sync_state(can_retry
- ? BACKGROUND_SYNC_STATE_UNREGISTERED
- : BACKGROUND_SYNC_STATE_FAILED);
- registration->RunFinishedCallbacks();
- } else if (can_retry) {
- registration->set_sync_state(BACKGROUND_SYNC_STATE_PENDING);
- registration->set_delay_until(
- clock_->Now() +
- parameters_->initial_retry_delay *
- pow(parameters_->retry_delay_factor,
- registration->num_attempts() - 1));
- } else {
- registration->set_sync_state(BACKGROUND_SYNC_STATE_FAILED);
- registration->RunFinishedCallbacks();
- }
- } else { // Sync succeeded
- registration->set_sync_state(BACKGROUND_SYNC_STATE_SUCCESS);
- registration->RunFinishedCallbacks();
- }
-
- if (registration->HasCompleted()) {
- RegistrationKey key(*registration);
- RefCountedRegistration* active_registration =
- LookupActiveRegistration(service_worker_id, key);
- if (active_registration &&
- active_registration->value()->id() == registration->id()) {
- RemoveActiveRegistration(service_worker_id, key);
- }
- }
- } else { // !SYNC_ONE_SHOT
- // TODO(jkarlin): Add support for running periodic syncs. (crbug.com/479674)
- NOTREACHED();
+ bool registration_completed = true;
+ bool can_retry =
+ registration->num_attempts() < parameters_->max_sync_attempts;
+
+ if (registration->sync_state() ==
+ mojom::BackgroundSyncState::REREGISTERED_WHILE_FIRING) {
+ registration->set_sync_state(mojom::BackgroundSyncState::PENDING);
+ registration->set_num_attempts(0);
+ registration_completed = false;
+ } else if (status_code != SERVICE_WORKER_OK &&
+ can_retry) { // Sync failed but can retry
+ registration->set_sync_state(mojom::BackgroundSyncState::PENDING);
+ registration->set_delay_until(clock_->Now() +
+ parameters_->initial_retry_delay *
+ pow(parameters_->retry_delay_factor,
+ registration->num_attempts() - 1));
+ registration_completed = false;
}
- if (disabled_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback));
- return;
+ if (registration_completed) {
+ const std::string& tag = registration->options()->tag;
+ BackgroundSyncRegistration* active_registration =
+ LookupActiveRegistration(service_worker_id, tag);
+ if (active_registration &&
+ active_registration->id() == registration->id()) {
+ RemoveActiveRegistration(service_worker_id, tag);
+ }
}
StoreRegistrations(
@@ -1454,12 +1163,6 @@ void BackgroundSyncManager::OnNetworkChanged() {
FireReadyEvents();
}
-void BackgroundSyncManager::OnPowerChanged() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- FireReadyEvents();
-}
-
void BackgroundSyncManager::SetMaxSyncAttemptsImpl(
int max_attempts,
const base::Closure& callback) {
@@ -1482,21 +1185,20 @@ void BackgroundSyncManager::CompleteOperationCallback(const CallbackT& callback,
void BackgroundSyncManager::CompleteStatusAndRegistrationCallback(
StatusAndRegistrationCallback callback,
BackgroundSyncStatus status,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle) {
+ scoped_ptr<BackgroundSyncRegistration> registration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback.Run(status, std::move(registration_handle));
+ callback.Run(status, std::move(registration));
op_scheduler_.CompleteOperationAndRunNext();
}
void BackgroundSyncManager::CompleteStatusAndRegistrationsCallback(
StatusAndRegistrationsCallback callback,
BackgroundSyncStatus status,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>
- registration_handles) {
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> registrations) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback.Run(status, std::move(registration_handles));
+ callback.Run(status, std::move(registrations));
op_scheduler_.CompleteOperationAndRunNext();
}
diff --git a/chromium/content/browser/background_sync/background_sync_manager.h b/chromium/content/browser/background_sync/background_sync_manager.h
index 42a69ea8989..e80ee0a485c 100644
--- a/chromium/content/browser/background_sync/background_sync_manager.h
+++ b/chromium/content/browser/background_sync/background_sync_manager.h
@@ -22,7 +22,6 @@
#include "base/time/clock.h"
#include "content/browser/background_sync/background_sync.pb.h"
#include "content/browser/background_sync/background_sync_registration.h"
-#include "content/browser/background_sync/background_sync_registration_handle.h"
#include "content/browser/background_sync/background_sync_status.h"
#include "content/browser/cache_storage/cache_storage_scheduler.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
@@ -32,12 +31,18 @@
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/browser/background_sync_parameters.h"
#include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
#include "url/gurl.h"
+namespace blink {
+namespace mojom {
+enum class PermissionStatus;
+}
+}
+
namespace content {
class BackgroundSyncNetworkObserver;
-class BackgroundSyncPowerObserver;
class ServiceWorkerContextWrapper;
// BackgroundSyncManager manages and stores the set of background sync
@@ -53,53 +58,32 @@ class CONTENT_EXPORT BackgroundSyncManager
using StatusCallback = base::Callback<void(BackgroundSyncStatus)>;
using StatusAndRegistrationCallback =
base::Callback<void(BackgroundSyncStatus,
- scoped_ptr<BackgroundSyncRegistrationHandle>)>;
- using StatusAndStateCallback =
- base::Callback<void(BackgroundSyncStatus, BackgroundSyncState)>;
+ scoped_ptr<BackgroundSyncRegistration>)>;
using StatusAndRegistrationsCallback = base::Callback<void(
BackgroundSyncStatus,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>)>;
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>>)>;
static scoped_ptr<BackgroundSyncManager> Create(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
~BackgroundSyncManager() override;
// Stores the given background sync registration and adds it to the scheduling
- // queue. It will overwrite an existing registration with the same tag and
- // periodicity unless they're identical (save for the id). Calls |callback|
- // with BACKGROUND_SYNC_STATUS_OK and the accepted registration on success.
+ // queue. It will overwrite an existing registration with the same tag unless
+ // they're identical (save for the id). Calls |callback| with
+ // BACKGROUND_SYNC_STATUS_OK and the accepted registration on success.
// The accepted registration will have a unique id. It may also have altered
// parameters if the user or UA chose different parameters than those
// supplied.
void Register(int64_t sw_registration_id,
const BackgroundSyncRegistrationOptions& options,
- bool requested_from_service_worker,
const StatusAndRegistrationCallback& callback);
- // Finds the background sync registration associated with
- // |sw_registration_id|, periodicity |periodicity|, and tag
- // |sync_registration_tag|. Calls |callback| with
- // BACKGROUND_SYNC_STATUS_NOT_FOUND if it doesn't exist. Calls |callback| with
- // BACKGROUND_SYNC_STATUS_OK on success. If the callback's status
- // is not BACKGROUND_SYNC_STATUS_OK then the callback's RegistrationHandle
- // will be nullptr.
- void GetRegistration(int64_t sw_registration_id,
- const std::string& sync_registration_tag,
- SyncPeriodicity periodicity,
- const StatusAndRegistrationCallback& callback);
-
// Finds the background sync registrations associated with
- // |sw_registration_id| and periodicity |periodicity|. Calls
- // |callback| with BACKGROUND_SYNC_STATUS_OK on success.
+ // |sw_registration_id|. Calls |callback| with BACKGROUND_SYNC_STATUS_OK on
+ // success.
void GetRegistrations(int64_t sw_registration_id,
- SyncPeriodicity periodicity,
const StatusAndRegistrationsCallback& callback);
- // Given a HandleId |handle_id|, return a new handle for the same
- // registration.
- scoped_ptr<BackgroundSyncRegistrationHandle> DuplicateRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id);
-
// ServiceWorkerContextObserver overrides.
void OnRegistrationDeleted(int64_t sw_registration_id,
const GURL& pattern) override;
@@ -119,14 +103,6 @@ class CONTENT_EXPORT BackgroundSyncManager
}
protected:
- // A registration might be referenced by the client longer than
- // the BackgroundSyncManager needs to keep track of it (e.g., the event has
- // finished firing). The BackgroundSyncManager reference counts its
- // registrations internally and every BackgroundSyncRegistrationHandle has a
- // unique handle id which maps to a locally maintained (in
- // client_registration_ids_) scoped_refptr.
- class RefCountedRegistration;
-
explicit BackgroundSyncManager(
const scoped_refptr<ServiceWorkerContextWrapper>& context);
@@ -144,10 +120,10 @@ class CONTENT_EXPORT BackgroundSyncManager
const std::string& backend_key,
const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
callback);
- virtual void FireOneShotSync(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
+ virtual void DispatchSyncEvent(
+ const std::string& tag,
const scoped_refptr<ServiceWorkerVersion>& active_version,
- BackgroundSyncEventLastChance last_chance,
+ mojom::BackgroundSyncEventLastChance last_chance,
const ServiceWorkerVersion::StatusCallback& callback);
virtual void ScheduleDelayedTask(const base::Closure& callback,
base::TimeDelta delay);
@@ -157,29 +133,12 @@ class CONTENT_EXPORT BackgroundSyncManager
private:
friend class TestBackgroundSyncManager;
friend class BackgroundSyncManagerTest;
- friend class BackgroundSyncRegistrationHandle;
-
- class RegistrationKey {
- public:
- explicit RegistrationKey(const BackgroundSyncRegistration& registration);
- explicit RegistrationKey(const BackgroundSyncRegistrationOptions& options);
- RegistrationKey(const std::string& tag, SyncPeriodicity periodicity);
- RegistrationKey(const RegistrationKey& other) = default;
- RegistrationKey& operator=(const RegistrationKey& other) = default;
-
- bool operator<(const RegistrationKey& rhs) const {
- return value_ < rhs.value_;
- }
-
- private:
- std::string value_;
- };
struct BackgroundSyncRegistrations {
- using RegistrationMap =
- std::map<RegistrationKey, scoped_refptr<RefCountedRegistration>>;
+ using RegistrationMap = std::map<std::string, BackgroundSyncRegistration>;
BackgroundSyncRegistrations();
+ BackgroundSyncRegistrations(const BackgroundSyncRegistrations& other);
~BackgroundSyncRegistrations();
RegistrationMap registration_map;
@@ -192,23 +151,8 @@ class CONTENT_EXPORT BackgroundSyncManager
static const size_t kMaxTagLength = 10240;
- scoped_ptr<BackgroundSyncRegistrationHandle> CreateRegistrationHandle(
- const scoped_refptr<RefCountedRegistration>& registration);
-
- // Returns the BackgroundSyncRegistration corresponding to |handle_id|.
- // Returns nullptr if the registration is not found.
- BackgroundSyncRegistration* GetRegistrationForHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id) const;
-
- // The BackgroundSyncManager holds references to registrations that have
- // active Handles. The handles must call this on destruction.
- void ReleaseRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id);
-
// Disable the manager. Already queued operations will abort once they start
- // to run (in their impl methods). Future operations will not queue. The one
- // exception is already firing events -- their responses will be processed in
- // order to notify their final state.
+ // to run (in their impl methods). Future operations will not queue.
// The list of active registrations is cleared and the backend is also cleared
// (if it's still functioning). The manager will reenable itself once it
// receives the OnStorageWiped message or on browser restart.
@@ -221,9 +165,9 @@ class CONTENT_EXPORT BackgroundSyncManager
ServiceWorkerStatusCode status);
// Returns the existing registration or nullptr if it cannot be found.
- RefCountedRegistration* LookupActiveRegistration(
+ BackgroundSyncRegistration* LookupActiveRegistration(
int64_t sw_registration_id,
- const RegistrationKey& registration_key);
+ const std::string& tag);
// Write all registrations for a given |sw_registration_id| to persistent
// storage.
@@ -232,12 +176,12 @@ class CONTENT_EXPORT BackgroundSyncManager
// Removes the active registration if it is in the map.
void RemoveActiveRegistration(int64_t sw_registration_id,
- const RegistrationKey& registration_key);
+ const std::string& tag);
void AddActiveRegistration(
int64_t sw_registration_id,
const GURL& origin,
- const scoped_refptr<RefCountedRegistration>& sync_registration);
+ const BackgroundSyncRegistration& sync_registration);
void InitImpl(const base::Closure& callback);
void InitDidGetControllerParameters(
@@ -261,49 +205,18 @@ class CONTENT_EXPORT BackgroundSyncManager
void RegisterImpl(int64_t sw_registration_id,
const BackgroundSyncRegistrationOptions& options,
const StatusAndRegistrationCallback& callback);
- void RegisterDidStore(
+ void RegisterDidAskForPermission(
int64_t sw_registration_id,
- const scoped_refptr<RefCountedRegistration>& new_registration_ref,
+ const BackgroundSyncRegistrationOptions& options,
const StatusAndRegistrationCallback& callback,
- ServiceWorkerStatusCode status);
-
- // Removes the background sync with periodicity |periodicity| and id
- // |sync_registration_id|. Calls |callback| with
- // BACKGROUND_SYNC_STATUS_NOT_FOUND if no match is found. Calls |callback|
- // with BACKGROUND_SYNC_STATUS_OK on success.
- void Unregister(int64_t sw_registration_id,
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const StatusCallback& callback);
- void UnregisterImpl(
- int64_t sw_registration_id,
- const RegistrationKey& key,
- BackgroundSyncRegistration::RegistrationId sync_registration_id,
- SyncPeriodicity periodicity,
- const StatusCallback& callback);
- void UnregisterDidStore(int64_t sw_registration_id,
- SyncPeriodicity periodicity,
- const StatusCallback& callback,
- ServiceWorkerStatusCode status);
-
- // NotifyWhenFinished and its callbacks. See
- // BackgroundSyncRegistrationHandle::NotifyWhenFinished for detailed
- // documentation.
- void NotifyWhenFinished(BackgroundSyncRegistrationHandle::HandleId handle_id,
- const StatusAndStateCallback& callback);
- void NotifyWhenFinishedImpl(
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
- const StatusAndStateCallback& callback);
- void NotifyWhenFinishedInvokeCallback(const StatusAndStateCallback& callback,
- BackgroundSyncState status);
-
- // GetRegistration callbacks
- void GetRegistrationImpl(int64_t sw_registration_id,
- const RegistrationKey& registration_key,
- const StatusAndRegistrationCallback& callback);
+ blink::mojom::PermissionStatus permission_status);
+ void RegisterDidStore(int64_t sw_registration_id,
+ const BackgroundSyncRegistration& new_registration,
+ const StatusAndRegistrationCallback& callback,
+ ServiceWorkerStatusCode status);
// GetRegistrations callbacks
void GetRegistrationsImpl(int64_t sw_registration_id,
- SyncPeriodicity periodicity,
const StatusAndRegistrationsCallback& callback);
bool AreOptionConditionsMet(const BackgroundSyncRegistrationOptions& options);
@@ -324,7 +237,7 @@ class CONTENT_EXPORT BackgroundSyncManager
void FireReadyEvents();
void FireReadyEventsImpl(const base::Closure& callback);
void FireReadyEventsDidFindRegistration(
- const RegistrationKey& registration_key,
+ const std::string& tag,
BackgroundSyncRegistration::RegistrationId registration_id,
const base::Closure& event_fired_callback,
const base::Closure& event_completed_callback,
@@ -334,18 +247,16 @@ class CONTENT_EXPORT BackgroundSyncManager
void FireReadyEventsAllEventsFiring(const base::Closure& callback);
// Called when a sync event has completed.
- void EventComplete(
- const scoped_refptr<ServiceWorkerRegistration>&
- service_worker_registration,
- int64_t service_worker_id,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
- const base::Closure& callback,
- ServiceWorkerStatusCode status_code);
- void EventCompleteImpl(
- int64_t service_worker_id,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle,
- ServiceWorkerStatusCode status_code,
- const base::Closure& callback);
+ void EventComplete(const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ int64_t service_worker_id,
+ const std::string& tag,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode status_code);
+ void EventCompleteImpl(int64_t service_worker_id,
+ const std::string& tag,
+ ServiceWorkerStatusCode status_code,
+ const base::Closure& callback);
void EventCompleteDidStore(int64_t service_worker_id,
const base::Closure& callback,
ServiceWorkerStatusCode status_code);
@@ -362,7 +273,6 @@ class CONTENT_EXPORT BackgroundSyncManager
void OnStorageWipedImpl(const base::Closure& callback);
void OnNetworkChanged();
- void OnPowerChanged();
// SetMaxSyncAttempts callback
void SetMaxSyncAttemptsImpl(int max_sync_attempts,
@@ -375,11 +285,11 @@ class CONTENT_EXPORT BackgroundSyncManager
void CompleteStatusAndRegistrationCallback(
StatusAndRegistrationCallback callback,
BackgroundSyncStatus status,
- scoped_ptr<BackgroundSyncRegistrationHandle> result);
+ scoped_ptr<BackgroundSyncRegistration> registration);
void CompleteStatusAndRegistrationsCallback(
StatusAndRegistrationsCallback callback,
BackgroundSyncStatus status,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>> results);
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> registrations);
base::Closure MakeEmptyCompletion();
base::Closure MakeClosureCompletion(const base::Closure& callback);
StatusAndRegistrationCallback MakeStatusAndRegistrationCompletion(
@@ -404,12 +314,6 @@ class CONTENT_EXPORT BackgroundSyncManager
base::CancelableCallback<void()> delayed_sync_task_;
scoped_ptr<BackgroundSyncNetworkObserver> network_observer_;
- scoped_ptr<BackgroundSyncPowerObserver> power_observer_;
-
- // The registrations that clients have handles to.
- IDMap<scoped_refptr<RefCountedRegistration>,
- IDMapOwnPointer,
- BackgroundSyncRegistrationHandle::HandleId> registration_handle_ids_;
scoped_ptr<base::Clock> clock_;
diff --git a/chromium/content/browser/background_sync/background_sync_manager_unittest.cc b/chromium/content/browser/background_sync/background_sync_manager_unittest.cc
index bf0670df243..dbe81cdfec8 100644
--- a/chromium/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/chromium/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -11,16 +11,14 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/metrics/field_trial.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/simple_test_clock.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/background_sync/background_sync_network_observer.h"
-#include "content/browser/background_sync/background_sync_registration_handle.h"
#include "content/browser/background_sync/background_sync_status.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
@@ -28,18 +26,26 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/storage_partition_impl.h"
-#include "content/public/browser/background_sync_controller.h"
#include "content/public/browser/background_sync_parameters.h"
+#include "content/public/browser/permission_type.h"
#include "content/public/test/background_sync_test_util.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/mock_background_sync_controller.h"
+#include "content/test/mock_permission_manager.h"
+#include "content/test/test_background_sync_manager.h"
#include "net/base/network_change_notifier.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
namespace content {
namespace {
+using ::testing::Return;
+using ::testing::_;
+
const char kPattern1[] = "https://example.com/a";
const char kPattern2[] = "https://example.com/b";
const char kScript1[] = "https://example.com/a/script.js";
@@ -69,7 +75,7 @@ void UnregisterServiceWorkerCallback(bool* called,
*called = true;
}
-void OneShotSuccessfulCallback(
+void DispatchSyncSuccessfulCallback(
int* count,
const scoped_refptr<ServiceWorkerVersion>& active_version,
const ServiceWorkerVersion::StatusCallback& callback) {
@@ -77,7 +83,7 @@ void OneShotSuccessfulCallback(
callback.Run(SERVICE_WORKER_OK);
}
-void OneShotFailedCallback(
+void DispatchSyncFailedCallback(
int* count,
const scoped_refptr<ServiceWorkerVersion>& active_version,
const ServiceWorkerVersion::StatusCallback& callback) {
@@ -85,7 +91,7 @@ void OneShotFailedCallback(
callback.Run(SERVICE_WORKER_ERROR_FAILED);
}
-void OneShotDelayedCallback(
+void DispatchSyncDelayedCallback(
int* count,
ServiceWorkerVersion::StatusCallback* out_callback,
const scoped_refptr<ServiceWorkerVersion>& active_version,
@@ -94,222 +100,18 @@ void OneShotDelayedCallback(
*out_callback = callback;
}
-void NotifyWhenFinishedCallback(bool* was_called,
- BackgroundSyncStatus* out_status,
- BackgroundSyncState* out_state,
- BackgroundSyncStatus status,
- BackgroundSyncState state) {
- *was_called = true;
- *out_status = status;
- *out_state = state;
-}
-
-class TestPowerSource : public base::PowerMonitorSource {
- public:
- void GeneratePowerStateEvent(bool on_battery_power) {
- test_on_battery_power_ = on_battery_power;
- ProcessPowerEvent(POWER_STATE_EVENT);
- }
-
- private:
- bool IsOnBatteryPowerImpl() final { return test_on_battery_power_; }
- bool test_on_battery_power_ = false;
-};
-
-class TestBackgroundSyncController : public BackgroundSyncController {
- public:
- TestBackgroundSyncController() = default;
-
- // BackgroundSyncController Overrides
- void NotifyBackgroundSyncRegistered(const GURL& origin) override {
- registration_count_ += 1;
- registration_origin_ = origin;
- }
- void RunInBackground(bool enabled, int64_t min_ms) override {
- run_in_background_count_ += 1;
- run_in_background_enabled_ = enabled;
- run_in_background_min_ms_ = min_ms;
- }
- void GetParameterOverrides(
- BackgroundSyncParameters* parameters) const override {
- *parameters = background_sync_parameters_;
- }
-
- int registration_count() const { return registration_count_; }
- GURL registration_origin() const { return registration_origin_; }
- int run_in_background_count() const { return run_in_background_count_; }
- bool run_in_background_enabled() const { return run_in_background_enabled_; }
- int64_t run_in_background_min_ms() const { return run_in_background_min_ms_; }
- BackgroundSyncParameters* background_sync_parameters() {
- return &background_sync_parameters_;
- }
-
- private:
- int registration_count_ = 0;
- GURL registration_origin_;
-
- int run_in_background_count_ = 0;
- bool run_in_background_enabled_ = true;
- int64_t run_in_background_min_ms_ = 0;
- BackgroundSyncParameters background_sync_parameters_;
-
- DISALLOW_COPY_AND_ASSIGN(TestBackgroundSyncController);
-};
-
} // namespace
-// A BackgroundSyncManager that can simulate delaying and corrupting the backend
-// storage and service worker onsync events.
-class TestBackgroundSyncManager : public BackgroundSyncManager {
- public:
- using OneShotCallback =
- base::Callback<void(const scoped_refptr<ServiceWorkerVersion>&,
- const ServiceWorkerVersion::StatusCallback&)>;
-
- explicit TestBackgroundSyncManager(
- const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
- : BackgroundSyncManager(service_worker_context) {
- }
-
- void DoInit() { Init(); }
-
- void StoreDataInBackendContinue(
- int64_t sw_registration_id,
- const GURL& origin,
- const std::string& key,
- const std::string& data,
- const ServiceWorkerStorage::StatusCallback& callback) {
- BackgroundSyncManager::StoreDataInBackend(sw_registration_id, origin, key,
- data, callback);
- }
-
- void GetDataFromBackendContinue(
- const std::string& key,
- const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
- callback) {
- BackgroundSyncManager::GetDataFromBackend(key, callback);
- }
-
- void Continue() {
- ASSERT_FALSE(continuation_.is_null());
- continuation_.Run();
- continuation_.Reset();
- }
-
- void ClearDelayedTask() { delayed_task_.Reset(); }
-
- void set_corrupt_backend(bool corrupt_backend) {
- corrupt_backend_ = corrupt_backend;
- }
- void set_delay_backend(bool delay_backend) { delay_backend_ = delay_backend; }
- void set_one_shot_callback(const OneShotCallback& callback) {
- one_shot_callback_ = callback;
- }
-
- base::Closure delayed_task() const { return delayed_task_; }
- base::TimeDelta delayed_task_delta() const { return delayed_task_delta_; }
-
- BackgroundSyncEventLastChance last_chance() const { return last_chance_; }
-
- void set_has_main_frame_provider_host(bool value) {
- has_main_frame_provider_host_ = value;
- }
-
- const BackgroundSyncParameters* background_sync_parameters() const {
- return parameters_.get();
- }
-
- protected:
- void StoreDataInBackend(
- int64_t sw_registration_id,
- const GURL& origin,
- const std::string& key,
- const std::string& data,
- const ServiceWorkerStorage::StatusCallback& callback) override {
- EXPECT_TRUE(continuation_.is_null());
- if (corrupt_backend_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
- return;
- }
- continuation_ =
- base::Bind(&TestBackgroundSyncManager::StoreDataInBackendContinue,
- base::Unretained(this), sw_registration_id, origin, key,
- data, callback);
- if (delay_backend_)
- return;
-
- Continue();
- }
-
- void GetDataFromBackend(
- const std::string& key,
- const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
- callback) override {
- EXPECT_TRUE(continuation_.is_null());
- if (corrupt_backend_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(callback, std::vector<std::pair<int64_t, std::string>>(),
- SERVICE_WORKER_ERROR_FAILED));
- return;
- }
- continuation_ =
- base::Bind(&TestBackgroundSyncManager::GetDataFromBackendContinue,
- base::Unretained(this), key, callback);
- if (delay_backend_)
- return;
-
- Continue();
- }
-
- void FireOneShotSync(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const scoped_refptr<ServiceWorkerVersion>& active_version,
- BackgroundSyncEventLastChance last_chance,
- const ServiceWorkerVersion::StatusCallback& callback) override {
- ASSERT_FALSE(one_shot_callback_.is_null());
- last_chance_ = last_chance;
- one_shot_callback_.Run(active_version, callback);
- }
-
- void ScheduleDelayedTask(const base::Closure& callback,
- base::TimeDelta delay) override {
- delayed_task_ = callback;
- delayed_task_delta_ = delay;
- }
-
- void HasMainFrameProviderHost(const GURL& origin,
- const BoolCallback& callback) override {
- callback.Run(has_main_frame_provider_host_);
- }
-
- private:
- bool corrupt_backend_ = false;
- bool delay_backend_ = false;
- bool has_main_frame_provider_host_ = true;
- BackgroundSyncEventLastChance last_chance_ =
- BACKGROUND_SYNC_EVENT_LAST_CHANCE_IS_NOT_LAST_CHANCE;
- base::Closure continuation_;
- OneShotCallback one_shot_callback_;
- base::Closure delayed_task_;
- base::TimeDelta delayed_task_delta_;
-};
-
class BackgroundSyncManagerTest : public testing::Test {
public:
BackgroundSyncManagerTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {
sync_options_1_.tag = "foo";
- sync_options_1_.periodicity = SYNC_ONE_SHOT;
sync_options_1_.network_state = NETWORK_STATE_ONLINE;
- sync_options_1_.power_state = POWER_STATE_AUTO;
sync_options_2_.tag = "bar";
- sync_options_2_.periodicity = SYNC_ONE_SHOT;
sync_options_2_.network_state = NETWORK_STATE_ONLINE;
- sync_options_2_.power_state = POWER_STATE_AUTO;
}
void SetUp() override {
@@ -321,28 +123,23 @@ class BackgroundSyncManagerTest : public testing::Test {
// extra SW stuff.
helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
+ scoped_ptr<MockPermissionManager> mock_permission_manager(
+ new testing::NiceMock<MockPermissionManager>());
+ ON_CALL(*mock_permission_manager,
+ GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
+ .WillByDefault(Return(blink::mojom::PermissionStatus::GRANTED));
+ helper_->browser_context()->SetPermissionManager(
+ std::move(mock_permission_manager));
+
// Create a StoragePartition with the correct BrowserContext so that the
// BackgroundSyncManager can find the BrowserContext through it.
storage_partition_impl_.reset(new StoragePartitionImpl(
helper_->browser_context(), base::FilePath(), nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr));
+ nullptr, nullptr, nullptr));
helper_->context_wrapper()->set_storage_partition(
storage_partition_impl_.get());
- power_monitor_source_ = new TestPowerSource();
- // power_monitor_ takes ownership of power_monitor_source.
- power_monitor_.reset(new base::PowerMonitor(
- scoped_ptr<base::PowerMonitorSource>(power_monitor_source_)));
-
- SetOnBatteryPower(false);
-
- scoped_ptr<TestBackgroundSyncController> background_sync_controller(
- new TestBackgroundSyncController());
- test_controller_ = background_sync_controller.get();
- helper_->browser_context()->SetBackgroundSyncController(
- std::move(background_sync_controller));
-
SetMaxSyncAttemptsAndRestartManager(1);
// Wait for storage to finish initializing before registering service
@@ -398,28 +195,22 @@ class BackgroundSyncManagerTest : public testing::Test {
}
}
- void SetOnBatteryPower(bool on_battery_power) {
- power_monitor_source_->GeneratePowerStateEvent(on_battery_power);
- base::RunLoop().RunUntilIdle();
- }
-
void StatusAndRegistrationCallback(
bool* was_called,
BackgroundSyncStatus status,
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle) {
+ scoped_ptr<BackgroundSyncRegistration> registration) {
*was_called = true;
callback_status_ = status;
- callback_registration_handle_ = std::move(registration_handle);
+ callback_registration_ = std::move(registration);
}
void StatusAndRegistrationsCallback(
bool* was_called,
BackgroundSyncStatus status,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>
- registration_handles) {
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> registrations) {
*was_called = true;
callback_status_ = status;
- callback_registration_handles_ = std::move(registration_handles);
+ callback_registrations_ = std::move(registrations);
}
void StatusCallback(bool* was_called, BackgroundSyncStatus status) {
@@ -429,8 +220,6 @@ class BackgroundSyncManagerTest : public testing::Test {
protected:
void CreateBackgroundSyncManager() {
- ClearRegistrationHandles();
-
test_background_sync_manager_ =
new TestBackgroundSyncManager(helper_->context_wrapper());
background_sync_manager_.reset(test_background_sync_manager_);
@@ -451,12 +240,6 @@ class BackgroundSyncManagerTest : public testing::Test {
base::RunLoop().RunUntilIdle();
}
- // Clear the registrations so that the BackgroundSyncManager can release them.
- void ClearRegistrationHandles() {
- callback_registration_handle_.reset();
- callback_registration_handles_.reset();
- }
-
void SetupBackgroundSyncManager() {
CreateBackgroundSyncManager();
InitBackgroundSyncManager();
@@ -475,7 +258,6 @@ class BackgroundSyncManagerTest : public testing::Test {
}
void DeleteBackgroundSyncManager() {
- ClearRegistrationHandles();
background_sync_manager_.reset();
test_background_sync_manager_ = nullptr;
test_clock_ = nullptr;
@@ -490,7 +272,7 @@ class BackgroundSyncManagerTest : public testing::Test {
const BackgroundSyncRegistrationOptions& options) {
bool was_called = false;
background_sync_manager_->Register(
- sw_registration_id, options, true /* requested_from_service_worker */,
+ sw_registration_id, options,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &was_called));
base::RunLoop().RunUntilIdle();
@@ -498,58 +280,9 @@ class BackgroundSyncManagerTest : public testing::Test {
return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
}
- bool RegisterFromDocumentWithServiceWorkerId(
- int64_t sw_registration_id,
- const BackgroundSyncRegistrationOptions& options) {
- bool was_called = false;
- background_sync_manager_->Register(
- sw_registration_id, options, false /* requested_from_service_worker */,
- base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
- base::Unretained(this), &was_called));
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(was_called);
- return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
- }
-
- bool Unregister(BackgroundSyncRegistrationHandle* registration_handle) {
- return UnregisterWithServiceWorkerId(sw_registration_id_1_,
- registration_handle);
- }
-
- bool UnregisterWithServiceWorkerId(
- int64_t sw_registration_id,
- BackgroundSyncRegistrationHandle* registration_handle) {
- bool was_called = false;
- registration_handle->Unregister(
- sw_registration_id,
- base::Bind(&BackgroundSyncManagerTest::StatusCallback,
- base::Unretained(this), &was_called));
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(was_called);
- return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
- }
-
- bool NotifyWhenFinished(
- BackgroundSyncRegistrationHandle* registration_handle) {
- callback_finished_called_ = false;
- callback_finished_status_ = BACKGROUND_SYNC_STATUS_NOT_FOUND;
- callback_finished_state_ = BACKGROUND_SYNC_STATE_FAILED;
-
- registration_handle->NotifyWhenFinished(
- base::Bind(&NotifyWhenFinishedCallback, &callback_finished_called_,
- &callback_finished_status_, &callback_finished_state_));
- base::RunLoop().RunUntilIdle();
-
- if (callback_finished_called_)
- EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, callback_finished_status_);
-
- return callback_finished_called_;
- }
-
- BackgroundSyncState FinishedState() {
- EXPECT_TRUE(callback_finished_called_);
- EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, callback_finished_status_);
- return callback_finished_state_;
+ MockPermissionManager* GetPermissionManager() {
+ return static_cast<MockPermissionManager*>(
+ helper_->browser_context()->GetPermissionManager());
}
bool GetRegistration(
@@ -562,32 +295,36 @@ class BackgroundSyncManagerTest : public testing::Test {
int64_t sw_registration_id,
const BackgroundSyncRegistrationOptions& registration_options) {
bool was_called = false;
- background_sync_manager_->GetRegistration(
- sw_registration_id, registration_options.tag,
- registration_options.periodicity,
- base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
+ background_sync_manager_->GetRegistrations(
+ sw_registration_id,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
base::Unretained(this), &was_called));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
if (callback_status_ == BACKGROUND_SYNC_STATUS_OK) {
- EXPECT_STREQ(registration_options.tag.c_str(),
- callback_registration_handle_->options()->tag.c_str());
+ for (auto iter = callback_registrations_->begin();
+ iter < callback_registrations_->end(); ++iter) {
+ if ((*iter)->options()->tag == registration_options.tag) {
+ // Transfer the matching registration out of the vector into
+ // callback_registration_ for testing.
+ callback_registration_.reset(*iter);
+ callback_registrations_->weak_erase(iter);
+ return true;
+ }
+ }
}
-
- return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
+ return false;
}
- bool GetRegistrations(SyncPeriodicity periodicity) {
- return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
- periodicity);
+ bool GetRegistrations() {
+ return GetRegistrationsWithServiceWorkerId(sw_registration_id_1_);
}
- bool GetRegistrationWithServiceWorkerId(int64_t sw_registration_id,
- SyncPeriodicity periodicity) {
+ bool GetRegistrationsWithServiceWorkerId(int64_t sw_registration_id) {
bool was_called = false;
background_sync_manager_->GetRegistrations(
- sw_registration_id, periodicity,
+ sw_registration_id,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
base::Unretained(this), &was_called));
base::RunLoop().RunUntilIdle();
@@ -596,6 +333,11 @@ class BackgroundSyncManagerTest : public testing::Test {
return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
}
+ MockBackgroundSyncController* GetController() {
+ return static_cast<MockBackgroundSyncController*>(
+ helper_->browser_context()->GetBackgroundSyncController());
+ }
+
void StorageRegistrationCallback(ServiceWorkerStatusCode result) {
callback_sw_status_code_ = result;
}
@@ -616,23 +358,24 @@ class BackgroundSyncManagerTest : public testing::Test {
}
void SetupForSyncEvent(
- const TestBackgroundSyncManager::OneShotCallback& callback) {
- test_background_sync_manager_->set_one_shot_callback(callback);
+ const TestBackgroundSyncManager::DispatchSyncCallback& callback) {
+ test_background_sync_manager_->set_dispatch_sync_callback(callback);
SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
}
void InitSyncEventTest() {
SetupForSyncEvent(
- base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
+ base::Bind(DispatchSyncSuccessfulCallback, &sync_events_called_));
}
void InitFailedSyncEventTest() {
- SetupForSyncEvent(base::Bind(OneShotFailedCallback, &sync_events_called_));
+ SetupForSyncEvent(
+ base::Bind(DispatchSyncFailedCallback, &sync_events_called_));
}
void InitDelayedSyncEventTest() {
- SetupForSyncEvent(base::Bind(OneShotDelayedCallback, &sync_events_called_,
- &sync_fired_callback_));
+ SetupForSyncEvent(base::Bind(DispatchSyncDelayedCallback,
+ &sync_events_called_, &sync_fired_callback_));
}
void RegisterAndVerifySyncEventDelayed(
@@ -656,7 +399,7 @@ class BackgroundSyncManagerTest : public testing::Test {
void SetMaxSyncAttemptsAndRestartManager(int max_sync_attempts) {
BackgroundSyncParameters* parameters =
- test_controller_->background_sync_parameters();
+ GetController()->background_sync_parameters();
parameters->max_sync_attempts = max_sync_attempts;
// Restart the BackgroundSyncManager so that it updates its parameters.
@@ -665,13 +408,10 @@ class BackgroundSyncManagerTest : public testing::Test {
TestBrowserThreadBundle browser_thread_bundle_;
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
- TestPowerSource* power_monitor_source_ = nullptr; // owned by power_monitor_
- scoped_ptr<base::PowerMonitor> power_monitor_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_ptr<BackgroundSyncManager> background_sync_manager_;
scoped_ptr<StoragePartitionImpl> storage_partition_impl_;
TestBackgroundSyncManager* test_background_sync_manager_ = nullptr;
- TestBackgroundSyncController* test_controller_;
base::SimpleTestClock* test_clock_ = nullptr;
int64_t sw_registration_id_1_;
@@ -684,14 +424,9 @@ class BackgroundSyncManagerTest : public testing::Test {
// Callback values.
BackgroundSyncStatus callback_status_ = BACKGROUND_SYNC_STATUS_OK;
- scoped_ptr<BackgroundSyncRegistrationHandle> callback_registration_handle_;
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>
- callback_registration_handles_;
+ scoped_ptr<BackgroundSyncRegistration> callback_registration_;
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> callback_registrations_;
ServiceWorkerStatusCode callback_sw_status_code_ = SERVICE_WORKER_OK;
- bool callback_finished_called_ = false;
- BackgroundSyncStatus callback_finished_status_ =
- BACKGROUND_SYNC_STATUS_NOT_FOUND;
- BackgroundSyncState callback_finished_state_ = BACKGROUND_SYNC_STATE_FAILED;
int sync_events_called_ = 0;
ServiceWorkerVersion::StatusCallback sync_fired_callback_;
};
@@ -700,11 +435,11 @@ TEST_F(BackgroundSyncManagerTest, Register) {
EXPECT_TRUE(Register(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, RegistractionIntact) {
+TEST_F(BackgroundSyncManagerTest, RegistrationIntact) {
EXPECT_TRUE(Register(sync_options_1_));
EXPECT_STREQ(sync_options_1_.tag.c_str(),
- callback_registration_handle_->options()->tag.c_str());
- EXPECT_TRUE(callback_registration_handle_->IsValid());
+ callback_registration_->options()->tag.c_str());
+ EXPECT_TRUE(callback_registration_->IsValid());
}
TEST_F(BackgroundSyncManagerTest, RegisterWithoutLiveSWRegistration) {
@@ -719,36 +454,6 @@ TEST_F(BackgroundSyncManagerTest, RegisterWithoutActiveSWRegistration) {
EXPECT_EQ(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback_status_);
}
-TEST_F(BackgroundSyncManagerTest, RegisterOverwrites) {
- EXPECT_TRUE(Register(sync_options_1_));
- scoped_ptr<BackgroundSyncRegistrationHandle> first_registration_handle =
- std::move(callback_registration_handle_);
-
- sync_options_1_.min_period = 100;
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_LT(first_registration_handle->handle_id(),
- callback_registration_handle_->handle_id());
- EXPECT_FALSE(first_registration_handle->options()->Equals(
- *callback_registration_handle_->options()));
-}
-
-TEST_F(BackgroundSyncManagerTest, RegisterOverlappingPeriodicAndOneShotTags) {
- // Registrations with the same tags but different periodicities should not
- // collide.
- sync_options_1_.tag = "";
- sync_options_2_.tag = "";
- sync_options_1_.periodicity = SYNC_PERIODIC;
- sync_options_2_.periodicity = SYNC_ONE_SHOT;
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
- EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_EQ(SYNC_PERIODIC,
- callback_registration_handle_->options()->periodicity);
- EXPECT_TRUE(GetRegistration(sync_options_2_));
- EXPECT_EQ(SYNC_ONE_SHOT,
- callback_registration_handle_->options()->periodicity);
-}
-
TEST_F(BackgroundSyncManagerTest, RegisterBadBackend) {
test_background_sync_manager_->set_corrupt_backend(true);
EXPECT_FALSE(Register(sync_options_1_));
@@ -757,18 +462,26 @@ TEST_F(BackgroundSyncManagerTest, RegisterBadBackend) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, DuplicateRegistrationHandle) {
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(
- sync_options_1_.Equals(*callback_registration_handle_->options()));
+TEST_F(BackgroundSyncManagerTest, RegisterPermissionDenied) {
+ GURL expected_origin = GURL(kPattern1).GetOrigin();
+ MockPermissionManager* mock_permission_manager = GetPermissionManager();
- scoped_ptr<BackgroundSyncRegistrationHandle> dup_handle =
- background_sync_manager_->DuplicateRegistrationHandle(
- callback_registration_handle_->handle_id());
+ EXPECT_CALL(*mock_permission_manager,
+ GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
+ expected_origin, expected_origin))
+ .WillOnce(testing::Return(blink::mojom::PermissionStatus::DENIED));
+ EXPECT_FALSE(Register(sync_options_1_));
+}
+
+TEST_F(BackgroundSyncManagerTest, RegisterPermissionGranted) {
+ GURL expected_origin = GURL(kPattern1).GetOrigin();
+ MockPermissionManager* mock_permission_manager = GetPermissionManager();
- EXPECT_TRUE(sync_options_1_.Equals(*dup_handle->options()));
- EXPECT_NE(callback_registration_handle_->handle_id(),
- dup_handle->handle_id());
+ EXPECT_CALL(*mock_permission_manager,
+ GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
+ expected_origin, expected_origin))
+ .WillOnce(testing::Return(blink::mojom::PermissionStatus::GRANTED));
+ EXPECT_TRUE(Register(sync_options_1_));
}
TEST_F(BackgroundSyncManagerTest, TwoRegistrations) {
@@ -799,115 +512,70 @@ TEST_F(BackgroundSyncManagerTest, GetRegistrationBadBackend) {
}
TEST_F(BackgroundSyncManagerTest, GetRegistrationsZero) {
- EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
- EXPECT_EQ(0u, callback_registration_handles_->size());
+ EXPECT_TRUE(GetRegistrations());
+ EXPECT_EQ(0u, callback_registrations_->size());
}
TEST_F(BackgroundSyncManagerTest, GetRegistrationsOne) {
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));
+ EXPECT_TRUE(GetRegistrations());
- EXPECT_EQ(1u, callback_registration_handles_->size());
- sync_options_1_.Equals(*(*callback_registration_handles_)[0]->options());
+ EXPECT_EQ(1u, callback_registrations_->size());
+ sync_options_1_.Equals(*(*callback_registrations_)[0]->options());
}
TEST_F(BackgroundSyncManagerTest, GetRegistrationsTwo) {
- EXPECT_EQ(sync_options_1_.periodicity, sync_options_2_.periodicity);
-
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
- EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));
-
- EXPECT_EQ(2u, callback_registration_handles_->size());
- sync_options_1_.Equals(*(*callback_registration_handles_)[0]->options());
- sync_options_2_.Equals(*(*callback_registration_handles_)[1]->options());
-}
-
-TEST_F(BackgroundSyncManagerTest, GetRegistrationsPeriodicity) {
- sync_options_1_.periodicity = SYNC_ONE_SHOT;
- sync_options_2_.periodicity = SYNC_PERIODIC;
EXPECT_TRUE(Register(sync_options_1_));
EXPECT_TRUE(Register(sync_options_2_));
+ EXPECT_TRUE(GetRegistrations());
- EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
- EXPECT_EQ(1u, callback_registration_handles_->size());
- sync_options_1_.Equals(*(*callback_registration_handles_)[0]->options());
-
- EXPECT_TRUE(GetRegistrations(SYNC_PERIODIC));
- EXPECT_EQ(1u, callback_registration_handles_->size());
- sync_options_2_.Equals(*(*callback_registration_handles_)[0]->options());
+ EXPECT_EQ(2u, callback_registrations_->size());
+ sync_options_1_.Equals(*(*callback_registrations_)[0]->options());
+ sync_options_2_.Equals(*(*callback_registrations_)[1]->options());
}
TEST_F(BackgroundSyncManagerTest, GetRegistrationsBadBackend) {
EXPECT_TRUE(Register(sync_options_1_));
test_background_sync_manager_->set_corrupt_backend(true);
- EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));
+ EXPECT_TRUE(GetRegistrations());
EXPECT_FALSE(Register(sync_options_2_));
// Registration should have discovered the bad backend and disabled the
// BackgroundSyncManager.
- EXPECT_FALSE(GetRegistrations(sync_options_1_.periodicity));
+ EXPECT_FALSE(GetRegistrations());
test_background_sync_manager_->set_corrupt_backend(false);
- EXPECT_FALSE(GetRegistrations(sync_options_1_.periodicity));
+ EXPECT_FALSE(GetRegistrations());
}
-TEST_F(BackgroundSyncManagerTest, Unregister) {
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-}
TEST_F(BackgroundSyncManagerTest, Reregister) {
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_TRUE(Register(sync_options_1_));
-}
-
-TEST_F(BackgroundSyncManagerTest, UnregisterSecond) {
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
}
-TEST_F(BackgroundSyncManagerTest, UnregisterBadBackend) {
- sync_options_1_.min_period += 1;
+TEST_F(BackgroundSyncManagerTest, ReregisterSecond) {
EXPECT_TRUE(Register(sync_options_1_));
EXPECT_TRUE(Register(sync_options_2_));
- test_background_sync_manager_->set_corrupt_backend(true);
- EXPECT_FALSE(Unregister(callback_registration_handle_.get()));
- // Unregister should have discovered the bad backend and disabled the
- // BackgroundSyncManager.
- test_background_sync_manager_->set_corrupt_backend(false);
- EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_FALSE(GetRegistration(sync_options_2_));
+ EXPECT_TRUE(Register(sync_options_2_));
}
TEST_F(BackgroundSyncManagerTest, RegisterMaxTagLength) {
sync_options_1_.tag = std::string(MaxTagLength(), 'a');
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- sync_options_1_.tag = std::string(MaxTagLength() + 1, 'a');
- EXPECT_FALSE(Register(sync_options_1_));
+ sync_options_2_.tag = std::string(MaxTagLength() + 1, 'b');
+ EXPECT_FALSE(Register(sync_options_2_));
EXPECT_EQ(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback_status_);
}
TEST_F(BackgroundSyncManagerTest, RegistrationIncreasesId) {
EXPECT_TRUE(Register(sync_options_1_));
- scoped_ptr<BackgroundSyncRegistrationHandle> registered_handle =
- std::move(callback_registration_handle_);
BackgroundSyncRegistration::RegistrationId cur_id =
- registered_handle->handle_id();
+ callback_registration_->id();
EXPECT_TRUE(GetRegistration(sync_options_1_));
EXPECT_TRUE(Register(sync_options_2_));
- EXPECT_LT(cur_id, callback_registration_handle_->handle_id());
- cur_id = callback_registration_handle_->handle_id();
-
- EXPECT_TRUE(Unregister(registered_handle.get()));
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_LT(cur_id, callback_registration_handle_->handle_id());
+ EXPECT_LT(cur_id, callback_registration_->id());
}
TEST_F(BackgroundSyncManagerTest, RebootRecovery) {
@@ -960,34 +628,33 @@ TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
SetupDelayedBackgroundSyncManager();
bool register_called = false;
- bool get_registration_called = false;
+ bool get_registrations_called = false;
test_background_sync_manager_->Register(
sw_registration_id_1_, sync_options_1_,
- true /* requested_from_service_worker */,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &register_called));
- test_background_sync_manager_->GetRegistration(
- sw_registration_id_1_, sync_options_1_.tag, sync_options_1_.periodicity,
- base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
- base::Unretained(this), &get_registration_called));
+ test_background_sync_manager_->GetRegistrations(
+ sw_registration_id_1_,
+ base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
+ base::Unretained(this), &get_registrations_called));
base::RunLoop().RunUntilIdle();
// Init should be blocked while loading from the backend.
EXPECT_FALSE(register_called);
- EXPECT_FALSE(get_registration_called);
+ EXPECT_FALSE(get_registrations_called);
- test_background_sync_manager_->Continue();
+ test_background_sync_manager_->ResumeBackendOperation();
base::RunLoop().RunUntilIdle();
// Register should be blocked while storing to the backend.
EXPECT_FALSE(register_called);
- EXPECT_FALSE(get_registration_called);
+ EXPECT_FALSE(get_registrations_called);
- test_background_sync_manager_->Continue();
+ test_background_sync_manager_->ResumeBackendOperation();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(register_called);
EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, callback_status_);
- // GetRegistration should run immediately as it doesn't write to disk.
- EXPECT_TRUE(get_registration_called);
+ // GetRegistrations should run immediately as it doesn't write to disk.
+ EXPECT_TRUE(get_registrations_called);
}
TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorker) {
@@ -1004,7 +671,6 @@ TEST_F(BackgroundSyncManagerTest,
bool callback_called = false;
test_background_sync_manager_->Register(
sw_registration_id_1_, sync_options_2_,
- true /* requested_from_service_worker */,
base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
base::Unretained(this), &callback_called));
@@ -1012,7 +678,7 @@ TEST_F(BackgroundSyncManagerTest,
EXPECT_FALSE(callback_called);
UnregisterServiceWorker(sw_registration_id_1_);
- test_background_sync_manager_->Continue();
+ test_background_sync_manager_->ResumeBackendOperation();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(callback_called);
EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);
@@ -1078,23 +744,6 @@ TEST_F(BackgroundSyncManagerTest, RegistrationEqualsTag) {
EXPECT_FALSE(reg_1.Equals(reg_2));
}
-TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPeriodicity) {
- BackgroundSyncRegistration reg_1;
- BackgroundSyncRegistration reg_2;
- EXPECT_TRUE(reg_1.Equals(reg_2));
- reg_1.options()->periodicity = SYNC_PERIODIC;
- reg_2.options()->periodicity = SYNC_ONE_SHOT;
- EXPECT_FALSE(reg_1.Equals(reg_2));
-}
-
-TEST_F(BackgroundSyncManagerTest, RegistrationEqualsMinPeriod) {
- BackgroundSyncRegistration reg_1;
- BackgroundSyncRegistration reg_2;
- EXPECT_TRUE(reg_1.Equals(reg_2));
- reg_2.options()->min_period = reg_1.options()->min_period + 1;
- EXPECT_FALSE(reg_1.Equals(reg_2));
-}
-
TEST_F(BackgroundSyncManagerTest, RegistrationEqualsNetworkState) {
BackgroundSyncRegistration reg_1;
BackgroundSyncRegistration reg_2;
@@ -1104,26 +753,14 @@ TEST_F(BackgroundSyncManagerTest, RegistrationEqualsNetworkState) {
EXPECT_FALSE(reg_1.Equals(reg_2));
}
-TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPowerState) {
- BackgroundSyncRegistration reg_1;
- BackgroundSyncRegistration reg_2;
- EXPECT_TRUE(reg_1.Equals(reg_2));
- reg_1.options()->power_state = POWER_STATE_AUTO;
- reg_2.options()->power_state = POWER_STATE_AVOID_DRAINING;
- EXPECT_FALSE(reg_1.Equals(reg_2));
-}
-
TEST_F(BackgroundSyncManagerTest, StoreAndRetrievePreservesValues) {
+ InitDelayedSyncEventTest();
BackgroundSyncRegistrationOptions options;
+
// Set non-default values for each field.
options.tag = "foo";
- EXPECT_NE(SYNC_PERIODIC, options.periodicity);
- options.periodicity = SYNC_PERIODIC;
- options.min_period += 1;
- EXPECT_NE(NETWORK_STATE_ANY, options.network_state);
- options.network_state = NETWORK_STATE_ANY;
- EXPECT_NE(POWER_STATE_AUTO, options.power_state);
- options.power_state = POWER_STATE_AUTO;
+ EXPECT_NE(NETWORK_STATE_AVOID_CELLULAR, options.network_state);
+ options.network_state = NETWORK_STATE_AVOID_CELLULAR;
// Store the registration.
EXPECT_TRUE(Register(options));
@@ -1133,49 +770,17 @@ TEST_F(BackgroundSyncManagerTest, StoreAndRetrievePreservesValues) {
SetupBackgroundSyncManager();
EXPECT_TRUE(GetRegistration(options));
- EXPECT_TRUE(options.Equals(*callback_registration_handle_->options()));
+ EXPECT_TRUE(options.Equals(*callback_registration_->options()));
}
TEST_F(BackgroundSyncManagerTest, EmptyTagSupported) {
- sync_options_1_.tag = "a";
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_TRUE(
- sync_options_1_.Equals(*callback_registration_handle_->options()));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-}
-
-TEST_F(BackgroundSyncManagerTest, OverlappingPeriodicAndOneShotTags) {
- // Registrations with the same tags but different periodicities should not
- // collide.
sync_options_1_.tag = "";
- sync_options_2_.tag = "";
- sync_options_1_.periodicity = SYNC_PERIODIC;
- sync_options_2_.periodicity = SYNC_ONE_SHOT;
-
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
-
- EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_EQ(SYNC_PERIODIC,
- callback_registration_handle_->options()->periodicity);
- EXPECT_TRUE(GetRegistration(sync_options_2_));
- EXPECT_EQ(SYNC_ONE_SHOT,
- callback_registration_handle_->options()->periodicity);
-
EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_TRUE(GetRegistration(sync_options_2_));
- EXPECT_EQ(SYNC_ONE_SHOT,
- callback_registration_handle_->options()->periodicity);
-
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_2_));
+ EXPECT_TRUE(sync_options_1_.Equals(*callback_registration_->options()));
}
-TEST_F(BackgroundSyncManagerTest, OneShotFiresOnRegistration) {
+TEST_F(BackgroundSyncManagerTest, FiresOnRegistration) {
InitSyncEventTest();
EXPECT_TRUE(Register(sync_options_1_));
@@ -1183,139 +788,9 @@ TEST_F(BackgroundSyncManagerTest, OneShotFiresOnRegistration) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedAfterEventSuccess) {
- InitSyncEventTest();
-
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_EQ(1, sync_events_called_);
-
- EXPECT_TRUE(NotifyWhenFinished(callback_registration_handle_.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedBeforeEventSuccess) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
-
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyWhenFinishedBeforeUnregisteredEventSuccess) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Unregistering should set the state to UNREGISTERED but finished shouldn't
- // be called until the event finishes firing, at which point its state should
- // be SUCCESS.
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyWhenFinishedBeforeUnregisteredEventFailure) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Unregistering should set the state to UNREGISTERED but finished shouldn't
- // be called until the event finishes firing, at which point its state should
- // be FAILED.
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyWhenFinishedBeforeUnregisteredEventFires) {
- InitSyncEventTest();
-
- SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_TRUE(NotifyWhenFinished(callback_registration_handle_.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyWhenFinishedBeforeEventSuccessDroppedHandle) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Drop the client's handle to the registration before the event fires, ensure
- // that the finished callback is still run.
- callback_registration_handle_ = nullptr;
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedAfterEventFailure) {
- InitFailedSyncEventTest();
-
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_EQ(1, sync_events_called_);
-
- EXPECT_TRUE(NotifyWhenFinished(callback_registration_handle_.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedBeforeEventFailure) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedAfterUnregistered) {
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
-
- EXPECT_TRUE(NotifyWhenFinished(callback_registration_handle_.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, NotifyWhenFinishedBeforeUnregistered) {
- Register(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
-}
-
TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptFails) {
InitDelayedSyncEventTest();
RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
// Reregister the event mid-sync
EXPECT_TRUE(Register(sync_options_1_));
@@ -1323,19 +798,16 @@ TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptFails) {
// The first sync attempt fails.
sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(callback_finished_called_);
// It should fire again since it was reregistered mid-sync.
EXPECT_TRUE(GetRegistration(sync_options_1_));
sync_fired_callback_.Run(SERVICE_WORKER_OK);
EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
}
TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptSucceeds) {
InitDelayedSyncEventTest();
RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
// Reregister the event mid-sync
EXPECT_TRUE(Register(sync_options_1_));
@@ -1343,198 +815,67 @@ TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptSucceeds) {
// The first sync event succeeds.
sync_fired_callback_.Run(SERVICE_WORKER_OK);
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(callback_finished_called_);
// It should fire again since it was reregistered mid-sync.
EXPECT_TRUE(GetRegistration(sync_options_1_));
sync_fired_callback_.Run(SERVICE_WORKER_OK);
EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyUnregisteredMidSyncNoRetryAttemptsLeft) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Unregister the event mid-sync.
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
- base::RunLoop().RunUntilIdle();
-
- // Since there were no retry attempts left, the sync ultimately failed.
- EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest,
- NotifyUnregisteredMidSyncWithRetryAttemptsLeft) {
- SetMaxSyncAttemptsAndRestartManager(2);
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
-
- // Unregister the event mid-sync.
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
-
- // Finish firing the event.
- sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
- base::RunLoop().RunUntilIdle();
- // Since there was one retry attempt left, the sync didn't completely fail
- // before it was unregistered.
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
}
TEST_F(BackgroundSyncManagerTest, OverwritePendingRegistration) {
- // An overwritten pending registration should complete with
- // BACKGROUND_SYNC_STATE_UNREGISTERED.
- sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_EQ(POWER_STATE_AVOID_DRAINING,
- callback_registration_handle_->options()->power_state);
- scoped_ptr<BackgroundSyncRegistrationHandle> original_handle =
- std::move(callback_registration_handle_);
+ InitFailedSyncEventTest();
- // Overwrite the pending registration.
- sync_options_1_.power_state = POWER_STATE_AUTO;
+ // Prevent the first sync from running so that it stays in a pending state.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
EXPECT_TRUE(Register(sync_options_1_));
EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_EQ(POWER_STATE_AUTO,
- callback_registration_handle_->options()->power_state);
- EXPECT_TRUE(NotifyWhenFinished(original_handle.get()));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
- EXPECT_EQ(0, sync_events_called_);
-}
-
-TEST_F(BackgroundSyncManagerTest, OverwriteFiringRegistrationWhichSucceeds) {
- // An overwritten pending registration should complete with
- // BACKGROUND_SYNC_STATE_SUCCESS if firing completes successfully.
- InitDelayedSyncEventTest();
-
- sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- scoped_ptr<BackgroundSyncRegistrationHandle> original_handle =
- std::move(callback_registration_handle_);
-
- // The next registration won't block.
- InitSyncEventTest();
-
- // Overwrite the firing registration.
- sync_options_1_.power_state = POWER_STATE_AUTO;
+ // Overwrite the first sync. It should still be pending.
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_FALSE(NotifyWhenFinished(original_handle.get()));
+ EXPECT_TRUE(GetRegistration(sync_options_1_));
- // Successfully finish the first event.
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
+ // Verify that it only gets to run once.
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
+ EXPECT_EQ(1, sync_events_called_);
+ EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, OverwriteFiringRegistrationWhichFails) {
- // An overwritten pending registration should complete with
- // BACKGROUND_SYNC_STATE_FAILED if firing fails.
+TEST_F(BackgroundSyncManagerTest, DisableWhilePending) {
InitDelayedSyncEventTest();
-
- sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
- scoped_ptr<BackgroundSyncRegistrationHandle> original_handle =
- std::move(callback_registration_handle_);
-
- // The next registration won't block.
- InitSyncEventTest();
-
- // Overwrite the firing registration.
- sync_options_1_.power_state = POWER_STATE_AUTO;
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_FALSE(NotifyWhenFinished(original_handle.get()));
-
- // Fail the first event.
- sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(BACKGROUND_SYNC_STATE_FAILED, FinishedState());
-}
-
-TEST_F(BackgroundSyncManagerTest, DisableWhilePendingNotifiesFinished) {
- InitSyncEventTest();
-
- // Register a one-shot that must wait for network connectivity before it
- // can fire.
SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
// Corrupting the backend should result in the manager disabling itself on the
- // next operation. While disabling, it should finalize any pending
- // registrations.
+ // next operation.
test_background_sync_manager_->set_corrupt_backend(true);
EXPECT_FALSE(Register(sync_options_2_));
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, FinishedState());
+
+ test_background_sync_manager_->set_corrupt_backend(false);
+ SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, sync_events_called_);
}
-TEST_F(BackgroundSyncManagerTest, DisableWhileFiringNotifiesFinished) {
+TEST_F(BackgroundSyncManagerTest, DisableWhileFiring) {
InitDelayedSyncEventTest();
// Register a one-shot that pauses mid-fire.
RegisterAndVerifySyncEventDelayed(sync_options_1_);
- EXPECT_FALSE(NotifyWhenFinished(callback_registration_handle_.get()));
// Corrupting the backend should result in the manager disabling itself on the
- // next operation. Even though the manager is disabled, the firing sync event
- // should still be able to complete successfully and notify as much.
+ // next operation.
test_background_sync_manager_->set_corrupt_backend(true);
EXPECT_FALSE(Register(sync_options_2_));
- EXPECT_FALSE(callback_finished_called_);
test_background_sync_manager_->set_corrupt_backend(false);
- // Successfully complete the firing event.
+ // Successfully complete the firing event. We can't verify that it actually
+ // completed but at least we can test that it doesn't crash.
sync_fired_callback_.Run(SERVICE_WORKER_OK);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(BACKGROUND_SYNC_STATE_SUCCESS, FinishedState());
-}
-
-// TODO(jkarlin): Change this to a periodic test as one-shots can't be power
-// dependent according to spec.
-TEST_F(BackgroundSyncManagerTest, OneShotFiresOnPowerChange) {
- InitSyncEventTest();
- sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
-
- SetOnBatteryPower(true);
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_EQ(0, sync_events_called_);
- EXPECT_TRUE(GetRegistration(sync_options_1_));
-
- SetOnBatteryPower(false);
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-// TODO(jkarlin): Change this to a periodic test as one-shots can't be power
-// dependent according to spec.
-TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnPowerChange) {
- InitSyncEventTest();
- sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
- sync_options_2_.power_state = POWER_STATE_AVOID_DRAINING;
-
- SetOnBatteryPower(true);
- EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_TRUE(Register(sync_options_2_));
- EXPECT_EQ(0, sync_events_called_);
- EXPECT_TRUE(GetRegistration(sync_options_1_));
- EXPECT_TRUE(GetRegistration(sync_options_2_));
-
- SetOnBatteryPower(false);
- EXPECT_EQ(2, sync_events_called_);
- EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_FALSE(GetRegistration(sync_options_2_));
-}
-
-TEST_F(BackgroundSyncManagerTest, OneShotFiresOnNetworkChange) {
+TEST_F(BackgroundSyncManagerTest, FiresOnNetworkChange) {
InitSyncEventTest();
SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
@@ -1548,7 +889,7 @@ TEST_F(BackgroundSyncManagerTest, OneShotFiresOnNetworkChange) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnNetworkChange) {
+TEST_F(BackgroundSyncManagerTest, MultipleRegistrationsFireOnNetworkChange) {
InitSyncEventTest();
SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
@@ -1565,7 +906,7 @@ TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnNetworkChange) {
EXPECT_FALSE(GetRegistration(sync_options_2_));
}
-TEST_F(BackgroundSyncManagerTest, OneShotFiresOnManagerRestart) {
+TEST_F(BackgroundSyncManagerTest, FiresOnManagerRestart) {
InitSyncEventTest();
// Initially the event won't run because there is no network.
@@ -1587,7 +928,7 @@ TEST_F(BackgroundSyncManagerTest, OneShotFiresOnManagerRestart) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, FailedOneShotShouldBeRemoved) {
+TEST_F(BackgroundSyncManagerTest, FailedRegistrationShouldBeRemoved) {
InitFailedSyncEventTest();
EXPECT_TRUE(Register(sync_options_1_));
@@ -1595,7 +936,7 @@ TEST_F(BackgroundSyncManagerTest, FailedOneShotShouldBeRemoved) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, FailedOneShotReregisteredAndFires) {
+TEST_F(BackgroundSyncManagerTest, FailedRegistrationReregisteredAndFires) {
InitFailedSyncEventTest();
// The initial sync event fails.
@@ -1612,7 +953,7 @@ TEST_F(BackgroundSyncManagerTest, FailedOneShotReregisteredAndFires) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, DelayOneShotMidSync) {
+TEST_F(BackgroundSyncManagerTest, DelayMidSync) {
InitDelayedSyncEventTest();
RegisterAndVerifySyncEventDelayed(sync_options_1_);
@@ -1624,50 +965,6 @@ TEST_F(BackgroundSyncManagerTest, DelayOneShotMidSync) {
EXPECT_FALSE(GetRegistration(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, OverwriteRegistrationMidSync) {
- InitDelayedSyncEventTest();
-
- sync_options_1_.network_state = NETWORK_STATE_ANY;
- SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
-
- // Don't delay the next sync.
- test_background_sync_manager_->set_one_shot_callback(
- base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
-
- // Register a different sync event with the same tag, overwriting the first.
- sync_options_1_.network_state = NETWORK_STATE_ONLINE;
- EXPECT_TRUE(Register(sync_options_1_));
-
- // The new sync event won't run as the network requirements aren't met.
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_TRUE(GetRegistration(sync_options_1_));
-
- // Finish the first event, note that the second is still registered.
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
- EXPECT_EQ(1, sync_events_called_);
- EXPECT_TRUE(GetRegistration(sync_options_1_));
-
- // Change the network and the second should run.
- SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(2, sync_events_called_);
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-}
-
-TEST_F(BackgroundSyncManagerTest, UnregisterOneShotMidSync) {
- InitDelayedSyncEventTest();
-
- RegisterAndVerifySyncEventDelayed(sync_options_1_);
-
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-
- sync_fired_callback_.Run(SERVICE_WORKER_OK);
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-}
-
TEST_F(BackgroundSyncManagerTest, BadBackendMidSync) {
InitDelayedSyncEventTest();
@@ -1712,34 +1009,19 @@ TEST_F(BackgroundSyncManagerTest, KillManagerMidSync) {
EXPECT_EQ(2, sync_events_called_);
}
-TEST_F(BackgroundSyncManagerTest, RegisterFromServiceWorkerWithoutMainFrame) {
+TEST_F(BackgroundSyncManagerTest, RegisterWithoutMainFrame) {
test_background_sync_manager_->set_has_main_frame_provider_host(false);
EXPECT_FALSE(Register(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest,
- RegisterFromDocumentWithoutMainFrameProviderHost) {
- test_background_sync_manager_->set_has_main_frame_provider_host(false);
- EXPECT_TRUE(RegisterFromDocumentWithServiceWorkerId(sw_registration_id_1_,
- sync_options_1_));
-}
-
-TEST_F(BackgroundSyncManagerTest,
- RegisterExistingFromServiceWorkerWithoutMainFrame) {
+TEST_F(BackgroundSyncManagerTest, RegisterExistingWithoutMainFrame) {
EXPECT_TRUE(Register(sync_options_1_));
test_background_sync_manager_->set_has_main_frame_provider_host(false);
EXPECT_FALSE(Register(sync_options_1_));
}
-TEST_F(BackgroundSyncManagerTest, UnregisterSucceedsWithoutMainFrame) {
- EXPECT_TRUE(Register(sync_options_1_));
- test_background_sync_manager_->set_has_main_frame_provider_host(false);
- EXPECT_TRUE(Unregister(callback_registration_handle_.get()));
- EXPECT_FALSE(GetRegistration(sync_options_1_));
-}
-
TEST_F(BackgroundSyncManagerTest, DefaultParameters) {
- *test_controller_->background_sync_parameters() = BackgroundSyncParameters();
+ *GetController()->background_sync_parameters() = BackgroundSyncParameters();
// Restart the BackgroundSyncManager so that it updates its parameters.
SetupBackgroundSyncManager();
@@ -1749,7 +1031,7 @@ TEST_F(BackgroundSyncManagerTest, DefaultParameters) {
TEST_F(BackgroundSyncManagerTest, OverrideParameters) {
BackgroundSyncParameters* parameters =
- test_controller_->background_sync_parameters();
+ GetController()->background_sync_parameters();
parameters->disable = true;
parameters->max_sync_attempts = 100;
parameters->initial_retry_delay = base::TimeDelta::FromMinutes(200);
@@ -1773,7 +1055,7 @@ TEST_F(BackgroundSyncManagerTest, DisablingFromControllerKeepsRegistrations) {
EXPECT_TRUE(Register(sync_options_1_));
BackgroundSyncParameters* parameters =
- test_controller_->background_sync_parameters();
+ GetController()->background_sync_parameters();
parameters->disable = true;
// Restart the BackgroundSyncManager so that it updates its parameters.
@@ -1790,7 +1072,7 @@ TEST_F(BackgroundSyncManagerTest, DisablingFromControllerKeepsRegistrations) {
TEST_F(BackgroundSyncManagerTest, DisabledPermanently) {
BackgroundSyncParameters* parameters =
- test_controller_->background_sync_parameters();
+ GetController()->background_sync_parameters();
parameters->disable = true;
// Restart the BackgroundSyncManager so that it updates its parameters.
@@ -1810,11 +1092,11 @@ TEST_F(BackgroundSyncManagerTest, DisabledPermanently) {
TEST_F(BackgroundSyncManagerTest, NotifyBackgroundSyncRegistered) {
// Verify that the BackgroundSyncController is informed of registrations.
- EXPECT_EQ(0, test_controller_->registration_count());
+ EXPECT_EQ(0, GetController()->registration_count());
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_EQ(1, test_controller_->registration_count());
+ EXPECT_EQ(1, GetController()->registration_count());
EXPECT_EQ(GURL(kPattern1).GetOrigin().spec(),
- test_controller_->registration_origin().spec());
+ GetController()->registration_origin().spec());
}
TEST_F(BackgroundSyncManagerTest, WakeBrowserCalled) {
@@ -1822,30 +1104,30 @@ TEST_F(BackgroundSyncManagerTest, WakeBrowserCalled) {
// The BackgroundSyncManager should declare in initialization
// that it doesn't need to be woken up since it has no registrations.
- EXPECT_LT(0, test_controller_->run_in_background_count());
- EXPECT_FALSE(test_controller_->run_in_background_enabled());
+ EXPECT_LT(0, GetController()->run_in_background_count());
+ EXPECT_FALSE(GetController()->run_in_background_enabled());
SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
- EXPECT_FALSE(test_controller_->run_in_background_enabled());
+ EXPECT_FALSE(GetController()->run_in_background_enabled());
// Register a one-shot but it can't fire due to lack of network, wake up is
// required.
Register(sync_options_1_);
- EXPECT_TRUE(test_controller_->run_in_background_enabled());
+ EXPECT_TRUE(GetController()->run_in_background_enabled());
// Start the event but it will pause mid-sync due to
// InitDelayedSyncEventTest() above.
SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
- EXPECT_TRUE(test_controller_->run_in_background_enabled());
+ EXPECT_TRUE(GetController()->run_in_background_enabled());
EXPECT_EQ(test_background_sync_manager_->background_sync_parameters()
->min_sync_recovery_time,
base::TimeDelta::FromMilliseconds(
- test_controller_->run_in_background_min_ms()));
+ GetController()->run_in_background_min_ms()));
// Finish the sync.
sync_fired_callback_.Run(SERVICE_WORKER_OK);
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(test_controller_->run_in_background_enabled());
+ EXPECT_FALSE(GetController()->run_in_background_enabled());
}
TEST_F(BackgroundSyncManagerTest, OneAttempt) {
@@ -2022,7 +1304,7 @@ TEST_F(BackgroundSyncManagerTest, LastChance) {
InitFailedSyncEventTest();
EXPECT_TRUE(Register(sync_options_1_));
- EXPECT_EQ(BACKGROUND_SYNC_EVENT_LAST_CHANCE_IS_NOT_LAST_CHANCE,
+ EXPECT_EQ(mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE,
test_background_sync_manager_->last_chance());
EXPECT_TRUE(GetRegistration(sync_options_1_));
@@ -2031,7 +1313,7 @@ TEST_F(BackgroundSyncManagerTest, LastChance) {
test_background_sync_manager_->delayed_task().Run();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetRegistration(sync_options_1_));
- EXPECT_EQ(BACKGROUND_SYNC_EVENT_LAST_CHANCE_IS_LAST_CHANCE,
+ EXPECT_EQ(mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE,
test_background_sync_manager_->last_chance());
}
diff --git a/chromium/content/browser/background_sync/background_sync_metrics.cc b/chromium/content/browser/background_sync/background_sync_metrics.cc
index 20b3a6651a3..8ae07b74eb6 100644
--- a/chromium/content/browser/background_sync/background_sync_metrics.cc
+++ b/chromium/content/browser/background_sync/background_sync_metrics.cc
@@ -33,40 +33,18 @@ ResultPattern EventResultToResultPattern(bool success,
namespace content {
// static
-void BackgroundSyncMetrics::RecordEventStarted(SyncPeriodicity periodicity,
- bool started_in_foreground) {
- switch (periodicity) {
- case SYNC_ONE_SHOT:
- UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Event.OneShotStartedInForeground",
- started_in_foreground);
- return;
- case SYNC_PERIODIC:
- UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Event.PeriodicStartedInForeground",
- started_in_foreground);
- return;
- }
- NOTREACHED();
+void BackgroundSyncMetrics::RecordEventStarted(bool started_in_foreground) {
+ UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Event.OneShotStartedInForeground",
+ started_in_foreground);
}
// static
-void BackgroundSyncMetrics::RecordEventResult(SyncPeriodicity periodicity,
- bool success,
+void BackgroundSyncMetrics::RecordEventResult(bool success,
bool finished_in_foreground) {
- switch (periodicity) {
- case SYNC_ONE_SHOT:
- UMA_HISTOGRAM_ENUMERATION(
- "BackgroundSync.Event.OneShotResultPattern",
- EventResultToResultPattern(success, finished_in_foreground),
- RESULT_PATTERN_MAX + 1);
- return;
- case SYNC_PERIODIC:
- UMA_HISTOGRAM_ENUMERATION(
- "BackgroundSync.Event.PeriodicResultPattern",
- EventResultToResultPattern(success, finished_in_foreground),
- RESULT_PATTERN_MAX + 1);
- return;
- }
- NOTREACHED();
+ UMA_HISTOGRAM_ENUMERATION(
+ "BackgroundSync.Event.OneShotResultPattern",
+ EventResultToResultPattern(success, finished_in_foreground),
+ RESULT_PATTERN_MAX + 1);
}
// static
@@ -84,62 +62,23 @@ void BackgroundSyncMetrics::RecordBatchSyncEventComplete(
// static
void BackgroundSyncMetrics::CountRegisterSuccess(
- SyncPeriodicity periodicity,
RegistrationCouldFire registration_could_fire,
RegistrationIsDuplicate registration_is_duplicate) {
- switch (periodicity) {
- case SYNC_ONE_SHOT:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.OneShot",
- BACKGROUND_SYNC_STATUS_OK,
- BACKGROUND_SYNC_STATUS_MAX + 1);
- UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Registration.OneShot.CouldFire",
- registration_could_fire == REGISTRATION_COULD_FIRE);
- UMA_HISTOGRAM_BOOLEAN(
- "BackgroundSync.Registration.OneShot.IsDuplicate",
- registration_is_duplicate == REGISTRATION_IS_DUPLICATE);
- return;
- case SYNC_PERIODIC:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.Periodic",
- BACKGROUND_SYNC_STATUS_OK,
- BACKGROUND_SYNC_STATUS_MAX + 1);
- UMA_HISTOGRAM_BOOLEAN(
- "BackgroundSync.Registration.Periodic.IsDuplicate",
- registration_is_duplicate == REGISTRATION_IS_DUPLICATE);
- return;
- }
- NOTREACHED();
-}
-
-// static
-void BackgroundSyncMetrics::CountRegisterFailure(SyncPeriodicity periodicity,
- BackgroundSyncStatus result) {
- switch (periodicity) {
- case SYNC_ONE_SHOT:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.OneShot", result,
- BACKGROUND_SYNC_STATUS_MAX + 1);
- return;
- case SYNC_PERIODIC:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.Periodic", result,
- BACKGROUND_SYNC_STATUS_MAX + 1);
- return;
- }
- NOTREACHED();
+ UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.OneShot",
+ BACKGROUND_SYNC_STATUS_OK,
+ BACKGROUND_SYNC_STATUS_MAX + 1);
+ UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Registration.OneShot.CouldFire",
+ registration_could_fire == REGISTRATION_COULD_FIRE);
+ UMA_HISTOGRAM_BOOLEAN("BackgroundSync.Registration.OneShot.IsDuplicate",
+ registration_is_duplicate == REGISTRATION_IS_DUPLICATE);
+ return;
}
// static
-void BackgroundSyncMetrics::CountUnregister(SyncPeriodicity periodicity,
- BackgroundSyncStatus result) {
- switch (periodicity) {
- case SYNC_ONE_SHOT:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Unregistration.OneShot", result,
- BACKGROUND_SYNC_STATUS_MAX + 1);
- return;
- case SYNC_PERIODIC:
- UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Unregistration.Periodic",
- result, BACKGROUND_SYNC_STATUS_MAX + 1);
- return;
- }
- NOTREACHED();
+void BackgroundSyncMetrics::CountRegisterFailure(BackgroundSyncStatus result) {
+ UMA_HISTOGRAM_ENUMERATION("BackgroundSync.Registration.OneShot", result,
+ BACKGROUND_SYNC_STATUS_MAX + 1);
+ return;
}
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_metrics.h b/chromium/content/browser/background_sync/background_sync_metrics.h
index f92a7c5b7a3..3280896f671 100644
--- a/chromium/content/browser/background_sync/background_sync_metrics.h
+++ b/chromium/content/browser/background_sync/background_sync_metrics.h
@@ -29,13 +29,10 @@ class BackgroundSyncMetrics {
};
// Records the start of a sync event.
- static void RecordEventStarted(SyncPeriodicity periodicity,
- bool startedin_foreground);
+ static void RecordEventStarted(bool startedin_foreground);
// Records the result of a single sync event firing.
- static void RecordEventResult(SyncPeriodicity periodicity,
- bool result,
- bool finished_in_foreground);
+ static void RecordEventResult(bool result, bool finished_in_foreground);
// Records the result of running a batch of sync events, including the total
// time spent, and the batch size.
@@ -46,17 +43,11 @@ class BackgroundSyncMetrics {
// indicates whether the conditions were sufficient for the sync to fire
// immediately at the time it was registered.
static void CountRegisterSuccess(
- SyncPeriodicity periodicity,
RegistrationCouldFire could_fire,
RegistrationIsDuplicate registration_is_duplicate);
// Records the status of a failed sync registration.
- static void CountRegisterFailure(SyncPeriodicity periodicity,
- BackgroundSyncStatus status);
-
- // Records the result of trying to unregister a sync.
- static void CountUnregister(SyncPeriodicity periodicity,
- BackgroundSyncStatus result);
+ static void CountRegisterFailure(BackgroundSyncStatus status);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BackgroundSyncMetrics);
diff --git a/chromium/content/browser/background_sync/background_sync_power_observer.cc b/chromium/content/browser/background_sync/background_sync_power_observer.cc
deleted file mode 100644
index 087fe21e37d..00000000000
--- a/chromium/content/browser/background_sync/background_sync_power_observer.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/background_sync/background_sync_power_observer.h"
-
-#include "base/power_monitor/power_monitor.h"
-#include "base/thread_task_runner_handle.h"
-
-namespace content {
-
-BackgroundSyncPowerObserver::BackgroundSyncPowerObserver(
- const base::Closure& power_callback)
- : observing_power_monitor_(false),
- on_battery_(true),
- power_changed_callback_(power_callback) {
- base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
- if (power_monitor) {
- observing_power_monitor_ = true;
- on_battery_ = power_monitor->IsOnBatteryPower();
- power_monitor->AddObserver(this);
- }
-}
-
-BackgroundSyncPowerObserver::~BackgroundSyncPowerObserver() {
- base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
-
- if (power_monitor)
- power_monitor->RemoveObserver(this);
-}
-
-bool BackgroundSyncPowerObserver::PowerSufficient(
- SyncPowerState power_state) const {
- DCHECK(observing_power_monitor_);
- DCHECK(base::PowerMonitor::Get());
-
- switch (power_state) {
- case POWER_STATE_AUTO:
- // TODO(jkarlin): Also check for device status, such as power saving mode
- // or user preferences. crbug.com/482088.
- return true;
- case POWER_STATE_AVOID_DRAINING:
- return !on_battery_;
- }
-
- NOTREACHED();
- return false;
-}
-
-void BackgroundSyncPowerObserver::OnPowerStateChange(bool on_battery_power) {
- DCHECK(observing_power_monitor_);
- DCHECK(base::PowerMonitor::Get());
-
- if (on_battery_ == on_battery_power)
- return;
-
- on_battery_ = on_battery_power;
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- power_changed_callback_);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_power_observer.h b/chromium/content/browser/background_sync/background_sync_power_observer.h
deleted file mode 100644
index b0da8f9facc..00000000000
--- a/chromium/content/browser/background_sync/background_sync_power_observer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_POWER_OBSERVER_H_
-#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_POWER_OBSERVER_H_
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/power_monitor/power_observer.h"
-#include "content/browser/background_sync/background_sync.pb.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-// BackgroundSyncPowerObserver monitors the charging status of the device and
-// determines if the power conditions of BackgroundSyncRegistrations are met.
-class CONTENT_EXPORT BackgroundSyncPowerObserver : public base::PowerObserver {
- public:
- // Creates a BackgroundSyncPowerObserver. |power_callback| is run when the
- // battery states changes asynchronously via PostMessage.
- explicit BackgroundSyncPowerObserver(const base::Closure& power_callback);
-
- ~BackgroundSyncPowerObserver() override;
-
- // Returns true if the state of the battery (charging or not) meets the needs
- // of |power_state|.
- bool PowerSufficient(SyncPowerState power_state) const;
-
- private:
- friend class BackgroundSyncPowerObserverTest;
-
- // PowerObserver overrides
- void OnPowerStateChange(bool on_battery_power) override;
-
- // |observing_power_monitor_| is true when the constructor is able to find and
- // register an observer with the base::PowerMonitor. This should always be
- // true except for tests in which the browser initialization isn't done.
- bool observing_power_monitor_;
-
- bool on_battery_;
-
- // The callback to run when the battery state changes.
- base::Closure power_changed_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(BackgroundSyncPowerObserver);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_POWER_OBSERVER_H_
diff --git a/chromium/content/browser/background_sync/background_sync_power_observer_unittest.cc b/chromium/content/browser/background_sync/background_sync_power_observer_unittest.cc
deleted file mode 100644
index 857ac069192..00000000000
--- a/chromium/content/browser/background_sync/background_sync_power_observer_unittest.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <content/browser/background_sync/background_sync_power_observer.h>
-
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/test/power_monitor_test_base.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-class BackgroundSyncPowerObserverTest : public testing::Test {
- protected:
- BackgroundSyncPowerObserverTest() : power_changed_count_(0) {
- power_monitor_source_ = new base::PowerMonitorTestSource();
- power_monitor_.reset(new base::PowerMonitor(
- scoped_ptr<base::PowerMonitorSource>(power_monitor_source_)));
- power_observer_.reset(new BackgroundSyncPowerObserver(
- base::Bind(&BackgroundSyncPowerObserverTest::OnPowerChanged,
- base::Unretained(this))));
- }
-
- void SetOnBatteryPower(bool on_battery_power) {
- power_monitor_source_->GeneratePowerStateEvent(on_battery_power);
- }
-
- void OnPowerChanged() { power_changed_count_++; }
-
- // power_monitor_source_ is owned by power_monitor_
- base::PowerMonitorTestSource* power_monitor_source_;
- scoped_ptr<base::PowerMonitor> power_monitor_;
- scoped_ptr<BackgroundSyncPowerObserver> power_observer_;
- int power_changed_count_;
-
- DISALLOW_COPY_AND_ASSIGN(BackgroundSyncPowerObserverTest);
-};
-
-TEST_F(BackgroundSyncPowerObserverTest, PowerChangeInvokesCallback) {
- SetOnBatteryPower(true);
- power_changed_count_ = 0;
-
- SetOnBatteryPower(false);
- EXPECT_EQ(1, power_changed_count_);
- SetOnBatteryPower(true);
- EXPECT_EQ(2, power_changed_count_);
- SetOnBatteryPower(true);
- EXPECT_EQ(2, power_changed_count_);
-}
-
-TEST_F(BackgroundSyncPowerObserverTest, PowerSufficientAuto) {
- SetOnBatteryPower(false);
- EXPECT_TRUE(power_observer_->PowerSufficient(POWER_STATE_AUTO));
-
- SetOnBatteryPower(true);
- EXPECT_TRUE(power_observer_->PowerSufficient(POWER_STATE_AUTO));
-}
-
-TEST_F(BackgroundSyncPowerObserverTest, PowerSufficientAvoidDraining) {
- SetOnBatteryPower(false);
- EXPECT_TRUE(power_observer_->PowerSufficient(POWER_STATE_AVOID_DRAINING));
-
- SetOnBatteryPower(true);
- EXPECT_FALSE(power_observer_->PowerSufficient(POWER_STATE_AVOID_DRAINING));
-}
-
-} // namespace
-
-} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_registration.cc b/chromium/content/browser/background_sync/background_sync_registration.cc
index b20e2ef744f..d835e67d4cb 100644
--- a/chromium/content/browser/background_sync/background_sync_registration.cc
+++ b/chromium/content/browser/background_sync/background_sync_registration.cc
@@ -18,9 +18,6 @@ const BackgroundSyncRegistration::RegistrationId
const BackgroundSyncRegistration::RegistrationId
BackgroundSyncRegistration::kInitialId = 0;
-BackgroundSyncRegistration::BackgroundSyncRegistration() = default;
-BackgroundSyncRegistration::~BackgroundSyncRegistration() = default;
-
bool BackgroundSyncRegistration::Equals(
const BackgroundSyncRegistration& other) const {
return options_.Equals(other.options_);
@@ -30,69 +27,16 @@ bool BackgroundSyncRegistration::IsValid() const {
return id_ != kInvalidRegistrationId;
}
-void BackgroundSyncRegistration::AddFinishedCallback(
- const StateCallback& callback) {
- DCHECK(!HasCompleted());
- notify_finished_callbacks_.push_back(callback);
-}
-
-void BackgroundSyncRegistration::RunFinishedCallbacks() {
- DCHECK(HasCompleted());
-
- for (auto& callback : notify_finished_callbacks_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, sync_state_));
- }
-
- notify_finished_callbacks_.clear();
-}
-
-bool BackgroundSyncRegistration::HasCompleted() const {
- switch (sync_state_) {
- case BACKGROUND_SYNC_STATE_PENDING:
- case BACKGROUND_SYNC_STATE_FIRING:
- case BACKGROUND_SYNC_STATE_REREGISTERED_WHILE_FIRING:
- case BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING:
- return false;
- case BACKGROUND_SYNC_STATE_FAILED:
- case BACKGROUND_SYNC_STATE_SUCCESS:
- case BACKGROUND_SYNC_STATE_UNREGISTERED:
- return true;
- }
- NOTREACHED();
- return false;
-}
-
bool BackgroundSyncRegistration::IsFiring() const {
switch (sync_state_) {
- case BACKGROUND_SYNC_STATE_FIRING:
- case BACKGROUND_SYNC_STATE_REREGISTERED_WHILE_FIRING:
- case BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING:
+ case mojom::BackgroundSyncState::FIRING:
+ case mojom::BackgroundSyncState::REREGISTERED_WHILE_FIRING:
return true;
- case BACKGROUND_SYNC_STATE_PENDING:
- case BACKGROUND_SYNC_STATE_FAILED:
- case BACKGROUND_SYNC_STATE_SUCCESS:
- case BACKGROUND_SYNC_STATE_UNREGISTERED:
+ case mojom::BackgroundSyncState::PENDING:
return false;
}
NOTREACHED();
return false;
}
-void BackgroundSyncRegistration::SetUnregisteredState() {
- DCHECK(!HasCompleted());
-
- bool is_firing = IsFiring();
-
- sync_state_ = is_firing ? BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING
- : BACKGROUND_SYNC_STATE_UNREGISTERED;
-
- if (!is_firing) {
- // If the registration is currently firing then wait to run
- // RunFinishedCallbacks until after it has finished as it might
- // change state to SUCCESS first.
- RunFinishedCallbacks();
- }
-}
-
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_registration.h b/chromium/content/browser/background_sync/background_sync_registration.h
index 4e4f1cd3f33..924540f65ac 100644
--- a/chromium/content/browser/background_sync/background_sync_registration.h
+++ b/chromium/content/browser/background_sync/background_sync_registration.h
@@ -24,34 +24,27 @@ namespace content {
class CONTENT_EXPORT BackgroundSyncRegistration {
public:
using RegistrationId = int64_t;
- using StateCallback = base::Callback<void(BackgroundSyncState)>;
static const RegistrationId kInitialId;
- BackgroundSyncRegistration();
- ~BackgroundSyncRegistration();
+ BackgroundSyncRegistration() = default;
+ BackgroundSyncRegistration(const BackgroundSyncRegistration& other) = default;
+ BackgroundSyncRegistration& operator=(
+ const BackgroundSyncRegistration& other) = default;
+ ~BackgroundSyncRegistration() = default;
bool Equals(const BackgroundSyncRegistration& other) const;
bool IsValid() const;
- void AddFinishedCallback(const StateCallback& callback);
- void RunFinishedCallbacks();
- bool HasCompleted() const;
bool IsFiring() const;
- // If the registration is currently firing, sets its state to
- // BACKGROUND_SYNC_STATE_UNREGISTERED_WHILE_FIRING. If it is firing, it sets
- // the state to BACKGROUND_SYNC_STATE_UNREGISTERED and calls
- // RunFinishedCallbacks.
- void SetUnregisteredState();
-
const BackgroundSyncRegistrationOptions* options() const { return &options_; }
BackgroundSyncRegistrationOptions* options() { return &options_; }
RegistrationId id() const { return id_; }
void set_id(RegistrationId id) { id_ = id; }
- BackgroundSyncState sync_state() const { return sync_state_; }
- void set_sync_state(BackgroundSyncState state) { sync_state_ = state; }
+ mojom::BackgroundSyncState sync_state() const { return sync_state_; }
+ void set_sync_state(mojom::BackgroundSyncState state) { sync_state_ = state; }
int num_attempts() const { return num_attempts_; }
void set_num_attempts(int num_attempts) { num_attempts_ = num_attempts; }
@@ -64,13 +57,9 @@ class CONTENT_EXPORT BackgroundSyncRegistration {
BackgroundSyncRegistrationOptions options_;
RegistrationId id_ = kInvalidRegistrationId;
- BackgroundSyncState sync_state_ = BACKGROUND_SYNC_STATE_PENDING;
+ mojom::BackgroundSyncState sync_state_ = mojom::BackgroundSyncState::PENDING;
int num_attempts_ = 0;
base::Time delay_until_;
-
- std::list<StateCallback> notify_finished_callbacks_;
-
- DISALLOW_COPY_AND_ASSIGN(BackgroundSyncRegistration);
};
} // namespace content
@@ -80,15 +69,15 @@ namespace mojo {
template <>
struct CONTENT_EXPORT
TypeConverter<scoped_ptr<content::BackgroundSyncRegistration>,
- content::SyncRegistrationPtr> {
+ content::mojom::SyncRegistrationPtr> {
static scoped_ptr<content::BackgroundSyncRegistration> Convert(
- const content::SyncRegistrationPtr& input);
+ const content::mojom::SyncRegistrationPtr& input);
};
template <>
-struct CONTENT_EXPORT TypeConverter<content::SyncRegistrationPtr,
+struct CONTENT_EXPORT TypeConverter<content::mojom::SyncRegistrationPtr,
content::BackgroundSyncRegistration> {
- static content::SyncRegistrationPtr Convert(
+ static content::mojom::SyncRegistrationPtr Convert(
const content::BackgroundSyncRegistration& input);
};
diff --git a/chromium/content/browser/background_sync/background_sync_registration_handle.cc b/chromium/content/browser/background_sync/background_sync_registration_handle.cc
deleted file mode 100644
index eca0abbb693..00000000000
--- a/chromium/content/browser/background_sync/background_sync_registration_handle.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/background_sync/background_sync_registration_handle.h"
-
-#include "content/browser/background_sync/background_sync_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-BackgroundSyncRegistrationHandle::~BackgroundSyncRegistrationHandle() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (IsValid() && background_sync_manager_)
- background_sync_manager_->ReleaseRegistrationHandle(handle_id_);
-}
-
-void BackgroundSyncRegistrationHandle::Unregister(
- int64_t sw_registration_id,
- const StatusCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(IsValid());
- DCHECK(background_sync_manager_);
-
- background_sync_manager_->Unregister(sw_registration_id, handle_id_,
- callback);
-}
-
-void BackgroundSyncRegistrationHandle::NotifyWhenFinished(
- const StatusAndStateCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(IsValid());
- DCHECK(background_sync_manager_);
-
- background_sync_manager_->NotifyWhenFinished(handle_id_, callback);
-}
-
-bool BackgroundSyncRegistrationHandle::IsValid() const {
- return registration_ != nullptr;
-}
-
-BackgroundSyncRegistrationHandle::BackgroundSyncRegistrationHandle(
- base::WeakPtr<BackgroundSyncManager> background_sync_manager,
- HandleId handle_id)
- : background_sync_manager_(background_sync_manager),
- handle_id_(handle_id),
- registration_(
- background_sync_manager_->GetRegistrationForHandle(handle_id_)) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(background_sync_manager_);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_registration_handle.h b/chromium/content/browser/background_sync/background_sync_registration_handle.h
deleted file mode 100644
index 8b2b5a92bb9..00000000000
--- a/chromium/content/browser/background_sync/background_sync_registration_handle.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_REGISTRATION_HANDLE_H_
-#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_REGISTRATION_HANDLE_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/background_sync/background_sync_registration.h"
-#include "content/browser/background_sync/background_sync_status.h"
-#include "content/common/background_sync_service.mojom.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class BackgroundSyncManager;
-
-// Handle to BackgroundSyncRegistration that is exposed to clients. Each
-// BackgroundSyncRegistrationHandle is given a unique handle id (by the
-// BackgroundSyncManager) which is released at destruction.
-// BackgroundSyncRegistrationHandle objects must not be used (but may be
-// destroyed) after the BackgroundSyncManager has been deleted.
-class CONTENT_EXPORT BackgroundSyncRegistrationHandle {
- public:
- using HandleId = int64_t;
- using StatusCallback = base::Callback<void(BackgroundSyncStatus)>;
- using StatusAndStateCallback =
- base::Callback<void(BackgroundSyncStatus, BackgroundSyncState)>;
-
- ~BackgroundSyncRegistrationHandle();
-
- const BackgroundSyncRegistrationOptions* options() const {
- DCHECK(background_sync_manager_);
- return registration_->options();
- }
-
- BackgroundSyncState sync_state() const {
- DCHECK(background_sync_manager_);
- return registration_->sync_state();
- }
-
- // Unregisters the background sync registration. Calls |callback|
- // with BACKGROUND_SYNC_STATUS_OK if it succeeds.
- void Unregister(int64_t service_worker_id, const StatusCallback& callback);
-
- // Runs |callback| when the registration associated with |handle_id|
- // completes.The provided status is BACKGROUND_SYNC_STATUS_OK if the operation
- // succeeded. The provided state is BACKGROUND_SYNC_STATE_SUCCESS on success,
- // BACKGRUOND_SYNC_STATE_FAILED on final failure, and
- // BACKGROUND_SYNC_STATE_UNREGISTERED if the registration was unregistered
- // before it could complete. NotifyWhenFinished should only be called for
- // SYNC_ONE_SHOT registrations.
- void NotifyWhenFinished(const StatusAndStateCallback& callback);
-
- // Returns true if the handle is backed by a BackgroundSyncRegistration in the
- // BackgroundSyncManager.
- bool IsValid() const;
-
- HandleId handle_id() const { return handle_id_; }
-
- private:
- friend class BackgroundSyncManager;
-
- BackgroundSyncRegistrationHandle(
- base::WeakPtr<BackgroundSyncManager> background_sync_manager,
- HandleId handle_id);
-
- BackgroundSyncRegistration* registration() {
- DCHECK(background_sync_manager_);
- return registration_;
- }
-
- // The BackgroundSyncManager is expected to remain alive for all operations
- // except for possibly at destruction.
- base::WeakPtr<BackgroundSyncManager> background_sync_manager_;
-
- // Each BackgroundSyncRegistrationHandle is assigned a unique handle id.
- // The BackgroundSyncManager maps the id to an internal pointer.
- HandleId handle_id_;
-
- // This is owned by background_sync_manager_ and is valid until handle_id_ is
- // released in the destructor or background_sync_manager_ has been destroyed.
- BackgroundSyncRegistration* registration_;
-
- DISALLOW_COPY_AND_ASSIGN(BackgroundSyncRegistrationHandle);
-};
-
-} // namespace
-
-#endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_REGISTRATION_HANDLE_H_
diff --git a/chromium/content/browser/background_sync/background_sync_registration_options.cc b/chromium/content/browser/background_sync/background_sync_registration_options.cc
index 74b8bac8ef7..7b8e1e7e7bc 100644
--- a/chromium/content/browser/background_sync/background_sync_registration_options.cc
+++ b/chromium/content/browser/background_sync/background_sync_registration_options.cc
@@ -8,9 +8,7 @@ namespace content {
bool BackgroundSyncRegistrationOptions::Equals(
const BackgroundSyncRegistrationOptions& other) const {
- return tag == other.tag && min_period == other.min_period &&
- network_state == other.network_state &&
- power_state == other.power_state && periodicity == other.periodicity;
+ return tag == other.tag && network_state == other.network_state;
}
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_registration_options.h b/chromium/content/browser/background_sync/background_sync_registration_options.h
index 0429f2a90cc..5c81e308846 100644
--- a/chromium/content/browser/background_sync/background_sync_registration_options.h
+++ b/chromium/content/browser/background_sync/background_sync_registration_options.h
@@ -19,10 +19,7 @@ struct CONTENT_EXPORT BackgroundSyncRegistrationOptions {
bool Equals(const BackgroundSyncRegistrationOptions& other) const;
std::string tag;
- int64_t min_period = 0;
SyncNetworkState network_state = NETWORK_STATE_ONLINE;
- SyncPowerState power_state = POWER_STATE_AVOID_DRAINING;
- SyncPeriodicity periodicity = SYNC_ONE_SHOT;
};
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_service_impl.cc b/chromium/content/browser/background_sync/background_sync_service_impl.cc
index ffab6abc995..a5b51bd2edf 100644
--- a/chromium/content/browser/background_sync/background_sync_service_impl.cc
+++ b/chromium/content/browser/background_sync/background_sync_service_impl.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "background_sync_registration_handle.h"
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "content/browser/background_sync/background_sync_context_impl.h"
@@ -20,28 +19,20 @@ namespace {
// specializations.
BackgroundSyncRegistrationOptions ToBackgroundSyncRegistrationOptions(
- const SyncRegistrationPtr& in) {
+ const mojom::SyncRegistrationPtr& in) {
BackgroundSyncRegistrationOptions out;
out.tag = in->tag;
- out.min_period = in->min_period_ms;
- out.power_state = static_cast<SyncPowerState>(in->power_state);
out.network_state = static_cast<SyncNetworkState>(in->network_state);
- out.periodicity = static_cast<SyncPeriodicity>(in->periodicity);
return out;
}
-SyncRegistrationPtr ToMojoRegistration(
- const BackgroundSyncRegistrationHandle& in) {
- SyncRegistrationPtr out(content::SyncRegistration::New());
- out->handle_id = in.handle_id();
+mojom::SyncRegistrationPtr ToMojoRegistration(
+ const BackgroundSyncRegistration& in) {
+ mojom::SyncRegistrationPtr out(content::mojom::SyncRegistration::New());
+ out->id = in.id();
out->tag = in.options()->tag;
- out->min_period_ms = in.options()->min_period;
- out->periodicity = static_cast<content::BackgroundSyncPeriodicity>(
- in.options()->periodicity);
- out->power_state =
- static_cast<content::BackgroundSyncPowerState>(in.options()->power_state);
- out->network_state = static_cast<content::BackgroundSyncNetworkState>(
+ out->network_state = static_cast<content::mojom::BackgroundSyncNetworkState>(
in.options()->network_state);
return out;
}
@@ -54,42 +45,30 @@ SyncRegistrationPtr ToMojoRegistration(
"mojo and manager enums must match")
// TODO(iclelland): Move these tests somewhere else
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_NONE,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::NONE,
BACKGROUND_SYNC_STATUS_OK);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_STORAGE,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::STORAGE,
BACKGROUND_SYNC_STATUS_STORAGE_ERROR);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_NOT_FOUND,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::NOT_FOUND,
BACKGROUND_SYNC_STATUS_NOT_FOUND);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_NO_SERVICE_WORKER,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::NO_SERVICE_WORKER,
BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_NOT_ALLOWED,
- BACKGROUND_SYNC_STATUS_NOT_ALLOWED);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_ERROR_MAX,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::NOT_ALLOWED,
BACKGROUND_SYNC_STATUS_NOT_ALLOWED);
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::PERMISSION_DENIED,
+ BACKGROUND_SYNC_STATUS_PERMISSION_DENIED);
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncError::MAX,
+ BACKGROUND_SYNC_STATUS_PERMISSION_DENIED);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_ANY,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncNetworkState::ANY,
SyncNetworkState::NETWORK_STATE_ANY);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_AVOID_CELLULAR,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncNetworkState::AVOID_CELLULAR,
SyncNetworkState::NETWORK_STATE_AVOID_CELLULAR);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_ONLINE,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncNetworkState::ONLINE,
SyncNetworkState::NETWORK_STATE_ONLINE);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_NETWORK_STATE_MAX,
+COMPILE_ASSERT_MATCHING_ENUM(mojom::BackgroundSyncNetworkState::MAX,
SyncNetworkState::NETWORK_STATE_ONLINE);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_AUTO,
- SyncPowerState::POWER_STATE_AUTO);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_AVOID_DRAINING,
- SyncPowerState::POWER_STATE_AVOID_DRAINING);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_POWER_STATE_MAX,
- SyncPowerState::POWER_STATE_AVOID_DRAINING);
-
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_PERIODIC,
- SyncPeriodicity::SYNC_PERIODIC);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_ONE_SHOT,
- SyncPeriodicity::SYNC_ONE_SHOT);
-COMPILE_ASSERT_MATCHING_ENUM(BACKGROUND_SYNC_PERIODICITY_MAX,
- SyncPeriodicity::SYNC_ONE_SHOT);
-
BackgroundSyncServiceImpl::~BackgroundSyncServiceImpl() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(background_sync_context_->background_sync_manager());
@@ -97,7 +76,7 @@ BackgroundSyncServiceImpl::~BackgroundSyncServiceImpl() {
BackgroundSyncServiceImpl::BackgroundSyncServiceImpl(
BackgroundSyncContextImpl* background_sync_context,
- mojo::InterfaceRequest<BackgroundSyncService> request)
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request)
: background_sync_context_(background_sync_context),
binding_(this, std::move(request)),
weak_ptr_factory_(this) {
@@ -114,60 +93,25 @@ void BackgroundSyncServiceImpl::OnConnectionError() {
// |this| is now deleted.
}
-void BackgroundSyncServiceImpl::Register(content::SyncRegistrationPtr options,
- int64_t sw_registration_id,
- bool requested_from_service_worker,
- const RegisterCallback& callback) {
+void BackgroundSyncServiceImpl::Register(
+ content::mojom::SyncRegistrationPtr options,
+ int64_t sw_registration_id,
+ const RegisterCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BackgroundSyncRegistrationOptions mgr_options =
+ BackgroundSyncRegistrationOptions manager_options =
ToBackgroundSyncRegistrationOptions(options);
BackgroundSyncManager* background_sync_manager =
background_sync_context_->background_sync_manager();
DCHECK(background_sync_manager);
background_sync_manager->Register(
- sw_registration_id, mgr_options, requested_from_service_worker,
- base::Bind(&BackgroundSyncServiceImpl::OnRegisterResult,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void BackgroundSyncServiceImpl::Unregister(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- int64_t sw_registration_id,
- const UnregisterCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- BackgroundSyncRegistrationHandle* registration =
- active_handles_.Lookup(handle_id);
- if (!registration) {
- callback.Run(BACKGROUND_SYNC_ERROR_NOT_ALLOWED);
- return;
- }
-
- registration->Unregister(
- sw_registration_id,
- base::Bind(&BackgroundSyncServiceImpl::OnUnregisterResult,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void BackgroundSyncServiceImpl::GetRegistration(
- BackgroundSyncPeriodicity periodicity,
- const mojo::String& tag,
- int64_t sw_registration_id,
- const GetRegistrationCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BackgroundSyncManager* background_sync_manager =
- background_sync_context_->background_sync_manager();
- DCHECK(background_sync_manager);
- background_sync_manager->GetRegistration(
- sw_registration_id, tag.get(), static_cast<SyncPeriodicity>(periodicity),
+ sw_registration_id, manager_options,
base::Bind(&BackgroundSyncServiceImpl::OnRegisterResult,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void BackgroundSyncServiceImpl::GetRegistrations(
- BackgroundSyncPeriodicity periodicity,
int64_t sw_registration_id,
const GetRegistrationsCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -175,129 +119,43 @@ void BackgroundSyncServiceImpl::GetRegistrations(
background_sync_context_->background_sync_manager();
DCHECK(background_sync_manager);
background_sync_manager->GetRegistrations(
- sw_registration_id, static_cast<SyncPeriodicity>(periodicity),
+ sw_registration_id,
base::Bind(&BackgroundSyncServiceImpl::OnGetRegistrationsResult,
weak_ptr_factory_.GetWeakPtr(), callback));
}
-void BackgroundSyncServiceImpl::GetPermissionStatus(
- BackgroundSyncPeriodicity periodicity,
- int64_t sw_registration_id,
- const GetPermissionStatusCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // TODO(iclelland): Implement a real policy. This is a stub implementation.
- // OneShot: crbug.com/482091
- // Periodic: crbug.com/482093
- callback.Run(BACKGROUND_SYNC_ERROR_NONE, PERMISSION_STATUS_GRANTED);
-}
-
-void BackgroundSyncServiceImpl::DuplicateRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const DuplicateRegistrationHandleCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BackgroundSyncManager* background_sync_manager =
- background_sync_context_->background_sync_manager();
- DCHECK(background_sync_manager);
-
- scoped_ptr<BackgroundSyncRegistrationHandle> registration_handle =
- background_sync_manager->DuplicateRegistrationHandle(handle_id);
-
- BackgroundSyncRegistrationHandle* handle_ptr = registration_handle.get();
-
- if (!registration_handle) {
- callback.Run(BACKGROUND_SYNC_ERROR_NOT_FOUND,
- SyncRegistrationPtr(content::SyncRegistration::New()));
- return;
- }
-
- active_handles_.AddWithID(registration_handle.release(),
- handle_ptr->handle_id());
- SyncRegistrationPtr mojoResult = ToMojoRegistration(*handle_ptr);
- callback.Run(BACKGROUND_SYNC_ERROR_NONE, std::move(mojoResult));
-}
-
-void BackgroundSyncServiceImpl::ReleaseRegistration(
- BackgroundSyncRegistrationHandle::HandleId handle_id) {
- if (!active_handles_.Lookup(handle_id)) {
- // TODO(jkarlin): Abort client.
- LOG(WARNING) << "Client attempted to release non-existing registration";
- return;
- }
-
- active_handles_.Remove(handle_id);
-}
-
-void BackgroundSyncServiceImpl::NotifyWhenFinished(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const NotifyWhenFinishedCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BackgroundSyncRegistrationHandle* registration =
- active_handles_.Lookup(handle_id);
- if (!registration) {
- callback.Run(BACKGROUND_SYNC_ERROR_NOT_ALLOWED,
- BACKGROUND_SYNC_STATE_FAILED);
- return;
- }
-
- registration->NotifyWhenFinished(
- base::Bind(&BackgroundSyncServiceImpl::OnNotifyWhenFinishedResult,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
void BackgroundSyncServiceImpl::OnRegisterResult(
const RegisterCallback& callback,
BackgroundSyncStatus status,
- scoped_ptr<BackgroundSyncRegistrationHandle> result) {
+ scoped_ptr<BackgroundSyncRegistration> result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BackgroundSyncRegistrationHandle* result_ptr = result.get();
if (status != BACKGROUND_SYNC_STATUS_OK) {
- callback.Run(static_cast<content::BackgroundSyncError>(status),
- SyncRegistrationPtr(content::SyncRegistration::New()));
+ callback.Run(
+ static_cast<content::mojom::BackgroundSyncError>(status),
+ mojom::SyncRegistrationPtr(content::mojom::SyncRegistration::New()));
return;
}
DCHECK(result);
- active_handles_.AddWithID(result.release(), result_ptr->handle_id());
- SyncRegistrationPtr mojoResult = ToMojoRegistration(*result_ptr);
- callback.Run(static_cast<content::BackgroundSyncError>(status),
+ mojom::SyncRegistrationPtr mojoResult = ToMojoRegistration(*result);
+ callback.Run(static_cast<content::mojom::BackgroundSyncError>(status),
std::move(mojoResult));
}
-void BackgroundSyncServiceImpl::OnUnregisterResult(
- const UnregisterCallback& callback,
- BackgroundSyncStatus status) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback.Run(static_cast<content::BackgroundSyncError>(status));
-}
-
void BackgroundSyncServiceImpl::OnGetRegistrationsResult(
const GetRegistrationsCallback& callback,
BackgroundSyncStatus status,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>>
- result_registrations) {
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> result_registrations) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(result_registrations);
- mojo::Array<content::SyncRegistrationPtr> mojo_registrations(0);
- for (BackgroundSyncRegistrationHandle* registration : *result_registrations) {
- active_handles_.AddWithID(registration, registration->handle_id());
+ mojo::Array<content::mojom::SyncRegistrationPtr> mojo_registrations;
+ for (const BackgroundSyncRegistration* registration : *result_registrations)
mojo_registrations.push_back(ToMojoRegistration(*registration));
- }
- result_registrations->weak_clear();
-
- callback.Run(static_cast<content::BackgroundSyncError>(status),
+ callback.Run(static_cast<content::mojom::BackgroundSyncError>(status),
std::move(mojo_registrations));
}
-void BackgroundSyncServiceImpl::OnNotifyWhenFinishedResult(
- const NotifyWhenFinishedCallback& callback,
- BackgroundSyncStatus status,
- BackgroundSyncState sync_state) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback.Run(static_cast<content::BackgroundSyncError>(status), sync_state);
-}
-
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_service_impl.h b/chromium/content/browser/background_sync/background_sync_service_impl.h
index a5b6d184e06..1851b90579a 100644
--- a/chromium/content/browser/background_sync/background_sync_service_impl.h
+++ b/chromium/content/browser/background_sync/background_sync_service_impl.h
@@ -20,56 +20,31 @@ namespace content {
class BackgroundSyncContextImpl;
class CONTENT_EXPORT BackgroundSyncServiceImpl
- : public NON_EXPORTED_BASE(BackgroundSyncService) {
+ : public NON_EXPORTED_BASE(mojom::BackgroundSyncService) {
public:
BackgroundSyncServiceImpl(
BackgroundSyncContextImpl* background_sync_context,
- mojo::InterfaceRequest<BackgroundSyncService> request);
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> request);
~BackgroundSyncServiceImpl() override;
private:
friend class BackgroundSyncServiceImplTest;
- // BackgroundSyncService methods:
- void Register(content::SyncRegistrationPtr options,
+ // mojom::BackgroundSyncService methods:
+ void Register(content::mojom::SyncRegistrationPtr options,
int64_t sw_registration_id,
- bool requested_from_service_worker,
const RegisterCallback& callback) override;
- void Unregister(BackgroundSyncRegistrationHandle::HandleId handle_id,
- int64_t sw_registration_id,
- const UnregisterCallback& callback) override;
- void GetRegistration(BackgroundSyncPeriodicity periodicity,
- const mojo::String& tag,
- int64_t sw_registration_id,
- const GetRegistrationCallback& callback) override;
- void GetRegistrations(BackgroundSyncPeriodicity periodicity,
- int64_t sw_registration_id,
+ void GetRegistrations(int64_t sw_registration_id,
const GetRegistrationsCallback& callback) override;
- void GetPermissionStatus(
- BackgroundSyncPeriodicity periodicity,
- int64_t sw_registration_id,
- const GetPermissionStatusCallback& callback) override;
- void DuplicateRegistrationHandle(
- BackgroundSyncRegistrationHandle::HandleId handle_id,
- const DuplicateRegistrationHandleCallback& callback) override;
- void ReleaseRegistration(
- BackgroundSyncRegistrationHandle::HandleId handle_id) override;
- void NotifyWhenFinished(BackgroundSyncRegistrationHandle::HandleId handle_id,
- const NotifyWhenFinishedCallback& callback) override;
void OnRegisterResult(const RegisterCallback& callback,
BackgroundSyncStatus status,
- scoped_ptr<BackgroundSyncRegistrationHandle> result);
- void OnUnregisterResult(const UnregisterCallback& callback,
- BackgroundSyncStatus status);
+ scoped_ptr<BackgroundSyncRegistration> result);
void OnGetRegistrationsResult(
const GetRegistrationsCallback& callback,
BackgroundSyncStatus status,
- scoped_ptr<ScopedVector<BackgroundSyncRegistrationHandle>> result);
- void OnNotifyWhenFinishedResult(const NotifyWhenFinishedCallback& callback,
- BackgroundSyncStatus status,
- BackgroundSyncState sync_state);
+ scoped_ptr<ScopedVector<BackgroundSyncRegistration>> result);
// Called when an error is detected on binding_.
void OnConnectionError();
@@ -77,12 +52,7 @@ class CONTENT_EXPORT BackgroundSyncServiceImpl
// background_sync_context_ owns this.
BackgroundSyncContextImpl* background_sync_context_;
- mojo::Binding<BackgroundSyncService> binding_;
-
- // The registrations that the client might reference.
- IDMap<BackgroundSyncRegistrationHandle,
- IDMapOwnPointer,
- BackgroundSyncRegistrationHandle::HandleId> active_handles_;
+ mojo::Binding<mojom::BackgroundSyncService> binding_;
base::WeakPtrFactory<BackgroundSyncServiceImpl> weak_ptr_factory_;
diff --git a/chromium/content/browser/background_sync/background_sync_service_impl_unittest.cc b/chromium/content/browser/background_sync/background_sync_service_impl_unittest.cc
index a9f8307c04a..8f413508481 100644
--- a/chromium/content/browser/background_sync/background_sync_service_impl_unittest.cc
+++ b/chromium/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -10,8 +10,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "content/browser/background_sync/background_sync_context_impl.h"
#include "content/browser/background_sync/background_sync_network_observer.h"
@@ -19,9 +17,12 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/permission_type.h"
#include "content/public/test/background_sync_test_util.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/mock_permission_manager.h"
+#include "content/test/test_background_sync_context_impl.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "net/base/network_change_notifier.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,6 +31,8 @@ namespace content {
namespace {
+using ::testing::_;
+
const char kServiceWorkerPattern[] = "https://example.com/a";
const char kServiceWorkerScript[] = "https://example.com/a/script.js";
@@ -54,51 +57,29 @@ void FindServiceWorkerRegistrationCallback(
// Callbacks from BackgroundSyncServiceImpl methods
-void ErrorAndRegistrationCallback(bool* called,
- BackgroundSyncError* out_error,
- SyncRegistrationPtr* out_registration,
- BackgroundSyncError error,
- const SyncRegistrationPtr& registration) {
+void ErrorAndRegistrationCallback(
+ bool* called,
+ mojom::BackgroundSyncError* out_error,
+ mojom::SyncRegistrationPtr* out_registration,
+ mojom::BackgroundSyncError error,
+ const mojom::SyncRegistrationPtr& registration) {
*called = true;
*out_error = error;
*out_registration = registration.Clone();
}
-void ErrorAndStateCallback(bool* called,
- BackgroundSyncError* out_error,
- BackgroundSyncState* out_state,
- BackgroundSyncError error,
- BackgroundSyncState state) {
- *called = true;
- *out_error = error;
- *out_state = state;
-}
-
-void ErrorCallback(bool* called,
- BackgroundSyncError* out_error,
- BackgroundSyncError error) {
- *called = true;
- *out_error = error;
-}
-
void ErrorAndRegistrationListCallback(
bool* called,
- BackgroundSyncError* out_error,
+ mojom::BackgroundSyncError* out_error,
unsigned long* out_array_size,
- BackgroundSyncError error,
- mojo::Array<content::SyncRegistrationPtr> registrations) {
+ mojom::BackgroundSyncError error,
+ mojo::Array<content::mojom::SyncRegistrationPtr> registrations) {
*called = true;
*out_error = error;
- if (error == BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE)
+ if (error == mojom::BackgroundSyncError::NONE)
*out_array_size = registrations.size();
}
-class MockPowerMonitorSource : public base::PowerMonitorSource {
- private:
- // PowerMonitorSource overrides.
- bool IsOnBatteryPowerImpl() final { return false; }
-};
-
} // namespace
class BackgroundSyncServiceImplTest : public testing::Test {
@@ -107,7 +88,7 @@ class BackgroundSyncServiceImplTest : public testing::Test {
: thread_bundle_(
new TestBrowserThreadBundle(TestBrowserThreadBundle::IO_MAINLOOP)),
network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {
- default_sync_registration_ = SyncRegistration::New();
+ default_sync_registration_ = mojom::SyncRegistration::New();
}
void SetUp() override {
@@ -137,6 +118,14 @@ class BackgroundSyncServiceImplTest : public testing::Test {
void CreateTestHelper() {
embedded_worker_helper_.reset(
new EmbeddedWorkerTestHelper(base::FilePath()));
+ scoped_ptr<MockPermissionManager> mock_permission_manager(
+ new testing::NiceMock<MockPermissionManager>());
+ ON_CALL(*mock_permission_manager,
+ GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
+ .WillByDefault(
+ testing::Return(blink::mojom::PermissionStatus::GRANTED));
+ embedded_worker_helper_->browser_context()->SetPermissionManager(
+ std::move(mock_permission_manager));
}
void CreateStoragePartition() {
@@ -145,16 +134,15 @@ class BackgroundSyncServiceImplTest : public testing::Test {
storage_partition_impl_.reset(new StoragePartitionImpl(
embedded_worker_helper_->browser_context(), base::FilePath(), nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
+ nullptr, nullptr, nullptr, nullptr, nullptr));
embedded_worker_helper_->context_wrapper()->set_storage_partition(
storage_partition_impl_.get());
}
void CreateBackgroundSyncContext() {
- power_monitor_.reset(
- new base::PowerMonitor(make_scoped_ptr(new MockPowerMonitorSource())));
-
- background_sync_context_ = new BackgroundSyncContextImpl();
+ // Registering for background sync includes a check for having a same-origin
+ // main frame. Use a test context that allows control over that check.
+ background_sync_context_ = new TestBackgroundSyncContextImpl();
background_sync_context_->Init(embedded_worker_helper_->context_wrapper());
// Tests do not expect the sync event to fire immediately after
@@ -190,10 +178,10 @@ class BackgroundSyncServiceImplTest : public testing::Test {
void CreateBackgroundSyncServiceImpl() {
// Create a dummy mojo channel so that the BackgroundSyncServiceImpl can be
- // instantiated
- mojo::InterfaceRequest<BackgroundSyncService> service_request =
+ // instantiated.
+ mojo::InterfaceRequest<mojom::BackgroundSyncService> service_request =
mojo::GetProxy(&service_ptr_);
- // Create a new BackgroundSyncServiceImpl bound to the dummy channel
+ // Create a new BackgroundSyncServiceImpl bound to the dummy channel.
background_sync_context_->CreateService(std::move(service_request));
base::RunLoop().RunUntilIdle();
@@ -202,44 +190,16 @@ class BackgroundSyncServiceImplTest : public testing::Test {
}
// Helpers for testing BackgroundSyncServiceImpl methods
- void RegisterOneShot(
- SyncRegistrationPtr sync,
- const BackgroundSyncService::RegisterCallback& callback) {
- service_impl_->Register(std::move(sync), sw_registration_id_,
- false /* requested_from_service_worker */,
- callback);
- base::RunLoop().RunUntilIdle();
- }
-
- void UnregisterOneShot(
- int32_t handle_id,
- const BackgroundSyncService::UnregisterCallback& callback) {
- service_impl_->Unregister(
- handle_id, sw_registration_id_, callback);
- base::RunLoop().RunUntilIdle();
- }
-
- void GetRegistrationOneShot(
- const mojo::String& tag,
- const BackgroundSyncService::RegisterCallback& callback) {
- service_impl_->GetRegistration(
- BackgroundSyncPeriodicity::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT, tag,
- sw_registration_id_, callback);
- base::RunLoop().RunUntilIdle();
- }
-
- void GetRegistrationsOneShot(
- const BackgroundSyncService::GetRegistrationsCallback& callback) {
- service_impl_->GetRegistrations(
- BackgroundSyncPeriodicity::BACKGROUND_SYNC_PERIODICITY_ONE_SHOT,
- sw_registration_id_, callback);
+ void Register(
+ mojom::SyncRegistrationPtr sync,
+ const mojom::BackgroundSyncService::RegisterCallback& callback) {
+ service_impl_->Register(std::move(sync), sw_registration_id_, callback);
base::RunLoop().RunUntilIdle();
}
- void NotifyWhenDone(
- int32_t handle_id,
- const BackgroundSyncService::NotifyWhenFinishedCallback& callback) {
- service_impl_->NotifyWhenFinished(handle_id, callback);
+ void GetRegistrations(
+ const mojom::BackgroundSyncService::GetRegistrationsCallback& callback) {
+ service_impl_->GetRegistrations(sw_registration_id_, callback);
base::RunLoop().RunUntilIdle();
}
@@ -247,154 +207,57 @@ class BackgroundSyncServiceImplTest : public testing::Test {
scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
scoped_ptr<EmbeddedWorkerTestHelper> embedded_worker_helper_;
scoped_ptr<StoragePartitionImpl> storage_partition_impl_;
- scoped_ptr<base::PowerMonitor> power_monitor_;
scoped_refptr<BackgroundSyncContextImpl> background_sync_context_;
int64_t sw_registration_id_;
scoped_refptr<ServiceWorkerRegistration> sw_registration_;
- BackgroundSyncServicePtr service_ptr_;
+ mojom::BackgroundSyncServicePtr service_ptr_;
BackgroundSyncServiceImpl*
service_impl_; // Owned by background_sync_context_
- SyncRegistrationPtr default_sync_registration_;
+ mojom::SyncRegistrationPtr default_sync_registration_;
};
// Tests
TEST_F(BackgroundSyncServiceImplTest, Register) {
bool called = false;
- BackgroundSyncError error;
- SyncRegistrationPtr reg;
- RegisterOneShot(
- default_sync_registration_.Clone(),
- base::Bind(&ErrorAndRegistrationCallback, &called, &error, &reg));
+ mojom::BackgroundSyncError error;
+ mojom::SyncRegistrationPtr reg;
+ Register(default_sync_registration_.Clone(),
+ base::Bind(&ErrorAndRegistrationCallback, &called, &error, &reg));
EXPECT_TRUE(called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, error);
+ EXPECT_EQ(mojom::BackgroundSyncError::NONE, error);
EXPECT_EQ("", reg->tag);
}
-TEST_F(BackgroundSyncServiceImplTest, Unregister) {
- bool unregister_called = false;
- BackgroundSyncError unregister_error;
- SyncRegistrationPtr reg;
- UnregisterOneShot(
- default_sync_registration_->handle_id,
- base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
- EXPECT_TRUE(unregister_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NOT_ALLOWED,
- unregister_error);
-}
-
-TEST_F(BackgroundSyncServiceImplTest, UnregisterWithRegisteredSync) {
- bool register_called = false;
- bool unregister_called = false;
- BackgroundSyncError register_error;
- BackgroundSyncError unregister_error;
- SyncRegistrationPtr reg;
- RegisterOneShot(default_sync_registration_.Clone(),
- base::Bind(&ErrorAndRegistrationCallback, &register_called,
- &register_error, &reg));
- EXPECT_TRUE(register_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, register_error);
- UnregisterOneShot(
- reg->handle_id,
- base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
- EXPECT_TRUE(unregister_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, unregister_error);
-}
-
-TEST_F(BackgroundSyncServiceImplTest, GetRegistration) {
- bool called = false;
- BackgroundSyncError error;
- SyncRegistrationPtr reg;
- GetRegistrationOneShot(
- "", base::Bind(&ErrorAndRegistrationCallback, &called, &error, &reg));
- EXPECT_TRUE(called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NOT_FOUND, error);
-}
-
-TEST_F(BackgroundSyncServiceImplTest, GetRegistrationWithRegisteredSync) {
- bool register_called = false;
- bool getregistration_called = false;
- BackgroundSyncError register_error;
- BackgroundSyncError getregistration_error;
- SyncRegistrationPtr register_reg;
- SyncRegistrationPtr getregistration_reg;
- RegisterOneShot(default_sync_registration_.Clone(),
- base::Bind(&ErrorAndRegistrationCallback, &register_called,
- &register_error, &register_reg));
- EXPECT_TRUE(register_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, register_error);
- GetRegistrationOneShot(
- register_reg->tag,
- base::Bind(&ErrorAndRegistrationCallback, &getregistration_called,
- &getregistration_error, &getregistration_reg));
- EXPECT_TRUE(getregistration_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE,
- getregistration_error);
-}
-
TEST_F(BackgroundSyncServiceImplTest, GetRegistrations) {
bool called = false;
- BackgroundSyncError error;
+ mojom::BackgroundSyncError error;
unsigned long array_size = 0UL;
- GetRegistrationsOneShot(base::Bind(&ErrorAndRegistrationListCallback, &called,
- &error, &array_size));
+ GetRegistrations(base::Bind(&ErrorAndRegistrationListCallback, &called,
+ &error, &array_size));
EXPECT_TRUE(called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, error);
+ EXPECT_EQ(mojom::BackgroundSyncError::NONE, error);
EXPECT_EQ(0UL, array_size);
}
TEST_F(BackgroundSyncServiceImplTest, GetRegistrationsWithRegisteredSync) {
bool register_called = false;
bool getregistrations_called = false;
- BackgroundSyncError register_error;
- BackgroundSyncError getregistrations_error;
- SyncRegistrationPtr register_reg;
+ mojom::BackgroundSyncError register_error;
+ mojom::BackgroundSyncError getregistrations_error;
+ mojom::SyncRegistrationPtr register_reg;
unsigned long array_size = 0UL;
- RegisterOneShot(default_sync_registration_.Clone(),
- base::Bind(&ErrorAndRegistrationCallback, &register_called,
- &register_error, &register_reg));
+ Register(default_sync_registration_.Clone(),
+ base::Bind(&ErrorAndRegistrationCallback, &register_called,
+ &register_error, &register_reg));
EXPECT_TRUE(register_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE, register_error);
- GetRegistrationsOneShot(base::Bind(&ErrorAndRegistrationListCallback,
- &getregistrations_called,
- &getregistrations_error, &array_size));
+ EXPECT_EQ(mojom::BackgroundSyncError::NONE, register_error);
+ GetRegistrations(base::Bind(&ErrorAndRegistrationListCallback,
+ &getregistrations_called, &getregistrations_error,
+ &array_size));
EXPECT_TRUE(getregistrations_called);
- EXPECT_EQ(BackgroundSyncError::BACKGROUND_SYNC_ERROR_NONE,
- getregistrations_error);
+ EXPECT_EQ(mojom::BackgroundSyncError::NONE, getregistrations_error);
EXPECT_EQ(1UL, array_size);
}
-TEST_F(BackgroundSyncServiceImplTest, NotifyWhenFinished) {
- // Register a sync event.
- bool register_called = false;
- BackgroundSyncError register_error;
- SyncRegistrationPtr reg;
- RegisterOneShot(default_sync_registration_.Clone(),
- base::Bind(&ErrorAndRegistrationCallback, &register_called,
- &register_error, &reg));
- EXPECT_TRUE(register_called);
- EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, register_error);
-
- // Unregister it.
- bool unregister_called = false;
- BackgroundSyncError unregister_error;
- UnregisterOneShot(
- reg->handle_id,
- base::Bind(&ErrorCallback, &unregister_called, &unregister_error));
- EXPECT_TRUE(unregister_called);
- EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, unregister_error);
-
- // Call NotifyWhenDone and verify that it calls back with unregistered.
- bool notify_done_called = false;
- BackgroundSyncError notify_done_error = BACKGROUND_SYNC_ERROR_NONE;
- BackgroundSyncState notify_done_sync_state = BACKGROUND_SYNC_STATE_SUCCESS;
-
- NotifyWhenDone(reg->handle_id,
- base::Bind(&ErrorAndStateCallback, &notify_done_called,
- &notify_done_error, &notify_done_sync_state));
- EXPECT_TRUE(notify_done_called);
- EXPECT_EQ(BACKGROUND_SYNC_ERROR_NONE, notify_done_error);
- EXPECT_EQ(BACKGROUND_SYNC_STATE_UNREGISTERED, notify_done_sync_state);
-}
-
} // namespace content
diff --git a/chromium/content/browser/background_sync/background_sync_status.h b/chromium/content/browser/background_sync/background_sync_status.h
index 3faee998377..27a8805325c 100644
--- a/chromium/content/browser/background_sync/background_sync_status.h
+++ b/chromium/content/browser/background_sync/background_sync_status.h
@@ -16,7 +16,8 @@ enum BackgroundSyncStatus {
BACKGROUND_SYNC_STATUS_NOT_FOUND,
BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER,
BACKGROUND_SYNC_STATUS_NOT_ALLOWED,
- BACKGROUND_SYNC_STATUS_MAX = BACKGROUND_SYNC_STATUS_NOT_ALLOWED
+ BACKGROUND_SYNC_STATUS_PERMISSION_DENIED,
+ BACKGROUND_SYNC_STATUS_MAX = BACKGROUND_SYNC_STATUS_PERMISSION_DENIED
};
} // namespace content
diff --git a/chromium/content/browser/bad_message.h b/chromium/content/browser/bad_message.h
index 1a8c80abb4e..441b903e350 100644
--- a/chromium/content/browser/bad_message.h
+++ b/chromium/content/browser/bad_message.h
@@ -127,6 +127,19 @@ enum BadMessageReason {
DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE = 103,
DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE = 104,
BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN = 105,
+ ACI_WRONG_STORAGE_PARTITION = 106,
+ RDHI_WRONG_STORAGE_PARTITION = 107,
+ RDH_INVALID_REQUEST_ID = 108,
+ BDH_SERVICE_NOT_ALLOWED_FOR_ORIGIN = 109,
+ WSH_SEND_BLOB_DURING_BLOB_SEND = 110,
+ WSH_SEND_FRAME_DURING_BLOB_SEND = 111,
+ RFH_UNEXPECTED_LOAD_START = 112,
+ NMF_INVALID_ARGUMENT = 113,
+ RFH_INVALID_ORIGIN_ON_COMMIT = 114,
+ BDH_UUID_REGISTERED = 115,
+ BDH_CONSTRUCTION_FAILED = 116,
+ BDH_INVALID_REFCOUNT_OPERATION = 117,
+ BDH_INVALID_URL_OPERATION = 118,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc b/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc
index 468126f3d39..1aee295891b 100644
--- a/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc
+++ b/chromium/content/browser/battery_status/battery_monitor_integration_browsertest.cc
@@ -95,6 +95,13 @@ class TestContentBrowserClient : public ContentBrowserClient {
registry->AddService(base::Bind(&FakeBatteryMonitor::Create));
}
+ void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
+ int child_process_id) override {
+ // Necessary for passing kIsolateSitesForTesting flag to the renderer.
+ ShellContentBrowserClient::Get()->AppendExtraCommandLineSwitches(
+ command_line, child_process_id);
+ }
+
#if defined(OS_ANDROID)
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
diff --git a/chromium/content/browser/blob_storage/blob_async_builder_host_unittest.cc b/chromium/content/browser/blob_storage/blob_async_builder_host_unittest.cc
index 934e0db887b..d40cc7cbc0c 100644
--- a/chromium/content/browser/blob_storage/blob_async_builder_host_unittest.cc
+++ b/chromium/content/browser/blob_storage/blob_async_builder_host_unittest.cc
@@ -11,14 +11,21 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
+#include "base/run_loop.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "storage/common/blob_storage/blob_storage_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace storage {
namespace {
const std::string kBlobUUID = "blobUUIDYAY";
-const std::string kFakeBlobUUID = "fakeBlob";
-const std::string kBlobType = "blobtypeYAY";
+const std::string kContentType = "content_type";
+const std::string kContentDisposition = "content_disposition";
+const std::string kCompletedBlobUUID = "completedBlob";
+const std::string kCompletedBlobData = "completedBlobData";
const size_t kTestBlobStorageIPCThresholdBytes = 5;
const size_t kTestBlobStorageMaxSharedMemoryBytes = 20;
@@ -52,87 +59,81 @@ void AddShortcutMemoryItem(size_t length, BlobDataBuilder* out) {
void AddBlobItem(std::vector<DataElement>* out) {
DataElement blob;
- blob.SetToBlob(kFakeBlobUUID);
+ blob.SetToBlob(kCompletedBlobUUID);
out->push_back(blob);
}
+} // namespace
class BlobAsyncBuilderHostTest : public testing::Test {
- protected:
+ public:
BlobAsyncBuilderHostTest()
- : matching_builder_(nullptr),
- done_called_(false),
- cancel_called_(false),
- cancel_code_(IPCBlobCreationCancelCode::UNKNOWN),
+ : cancel_code_(IPCBlobCreationCancelCode::UNKNOWN),
request_called_(false) {}
~BlobAsyncBuilderHostTest() override {}
void SetUp() override {
- matching_builder_ = nullptr;
- done_called_ = false;
- cancel_called_ = false;
cancel_code_ = IPCBlobCreationCancelCode::UNKNOWN;
request_called_ = false;
requests_.clear();
memory_handles_.clear();
- file_handles_.clear();
host_.SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes,
kTestBlobStorageMaxSharedMemoryBytes,
kTestBlobStorageMaxFileSizeBytes);
- }
-
- void SetMatchingBuilder(BlobDataBuilder* builder) {
- matching_builder_ = builder;
- }
-
- void CancelCallback(IPCBlobCreationCancelCode code) {
- cancel_called_ = true;
- cancel_code_ = code;
- }
-
- void DoneCallback(const BlobDataBuilder& builder) {
- // This does a deep comparison, including internal data items.
- if (matching_builder_)
- EXPECT_EQ(*matching_builder_, builder);
- done_called_ = true;
+ BlobDataBuilder builder(kCompletedBlobUUID);
+ builder.AppendData(kCompletedBlobData);
+ completed_blob_handle_ = context_.AddFinishedBlob(builder);
+ completed_blob_uuid_set_ = {kCompletedBlobUUID};
}
void RequestMemoryCallback(
- const std::vector<storage::BlobItemBytesRequest>& requests,
- const std::vector<base::SharedMemoryHandle>& shared_memory_handles,
- const std::vector<uint64_t>& file_sizes) {
- this->requests_ = requests;
- memory_handles_ = shared_memory_handles;
- file_handles_ = file_sizes;
+ scoped_ptr<std::vector<storage::BlobItemBytesRequest>> requests,
+ scoped_ptr<std::vector<base::SharedMemoryHandle>> shared_memory_handles,
+ scoped_ptr<std::vector<base::File>> files) {
+ requests_ = std::move(*requests);
+ memory_handles_ = std::move(*shared_memory_handles);
request_called_ = true;
}
- bool BuildBlobAsync(const std::vector<DataElement>& descriptions,
- size_t memory_available) {
- done_called_ = false;
- cancel_called_ = false;
+ BlobTransportResult BuildBlobAsync(
+ const std::vector<DataElement>& descriptions,
+ const std::set<std::string>& referenced_blob_uuids,
+ size_t memory_available) {
request_called_ = false;
+ BlobTransportResult register_result =
+ host_.RegisterBlobUUID(kBlobUUID, kContentType, kContentDisposition,
+ referenced_blob_uuids, &context_);
+ if (register_result != BlobTransportResult::DONE) {
+ return register_result;
+ }
return host_.StartBuildingBlob(
- kBlobUUID, kBlobType, descriptions, memory_available,
+ kBlobUUID, descriptions, memory_available, &context_,
base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
- base::Unretained(this)),
- base::Bind(&BlobAsyncBuilderHostTest::DoneCallback,
- base::Unretained(this)),
- base::Bind(&BlobAsyncBuilderHostTest::CancelCallback,
base::Unretained(this)));
}
- BlobDataBuilder* matching_builder_;
+ void DecrementBlobRefCount(const std::string& uuid) {
+ context_.DecrementBlobRefCount(uuid);
+ }
+
+ bool IsBeingBuiltInContext(const std::string& uuid) {
+ return context_.IsBeingBuilt(uuid);
+ }
+
+ content::TestBrowserThreadBundle browser_thread_bundle_;
+ BlobStorageContext context_;
BlobAsyncBuilderHost host_;
- bool done_called_;
- bool cancel_called_;
IPCBlobCreationCancelCode cancel_code_;
bool request_called_;
std::vector<storage::BlobItemBytesRequest> requests_;
std::vector<base::SharedMemoryHandle> memory_handles_;
- std::vector<uint64_t> file_handles_;
+ std::set<std::string> completed_blob_uuid_set_;
+
+ scoped_ptr<BlobDataHandle> completed_blob_handle_;
};
+// The 'shortcut' method is when the data is included in the initial IPCs and
+// the browser uses that instead of requesting the memory.
TEST_F(BlobAsyncBuilderHostTest, TestShortcut) {
std::vector<DataElement> descriptions;
@@ -141,16 +142,37 @@ TEST_F(BlobAsyncBuilderHostTest, TestShortcut) {
AddShortcutMemoryItem(5000, &descriptions);
BlobDataBuilder expected(kBlobUUID);
- expected.set_content_type(kBlobType);
+ expected.set_content_type(kContentType);
+ expected.set_content_disposition(kContentDisposition);
AddShortcutMemoryItem(10, &expected);
- expected.AppendBlob(kFakeBlobUUID);
+ expected.AppendData(kCompletedBlobData);
AddShortcutMemoryItem(5000, &expected);
- SetMatchingBuilder(&expected);
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
+
+ EXPECT_FALSE(request_called_);
+ EXPECT_EQ(0u, host_.blob_building_count());
+ scoped_ptr<BlobDataHandle> handle = context_.GetBlobDataFromUUID(kBlobUUID);
+ EXPECT_FALSE(handle->IsBeingBuilt());
+ EXPECT_FALSE(handle->IsBroken());
+ scoped_ptr<BlobDataSnapshot> data = handle->CreateSnapshot();
+ EXPECT_EQ(expected, *data);
+ data.reset();
+ handle.reset();
+ base::RunLoop().RunUntilIdle();
+};
+
+TEST_F(BlobAsyncBuilderHostTest, TestShortcutNoRoom) {
+ std::vector<DataElement> descriptions;
+
+ AddShortcutMemoryItem(10, &descriptions);
+ AddBlobItem(&descriptions);
+ AddShortcutMemoryItem(5000, &descriptions);
+
+ EXPECT_EQ(BlobTransportResult::CANCEL_MEMORY_FULL,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5000));
- EXPECT_TRUE(done_called_);
- EXPECT_FALSE(cancel_called_);
EXPECT_FALSE(request_called_);
EXPECT_EQ(0u, host_.blob_building_count());
};
@@ -160,11 +182,10 @@ TEST_F(BlobAsyncBuilderHostTest, TestSingleSharedMemRequest) {
const size_t kSize = kTestBlobStorageIPCThresholdBytes + 1;
AddMemoryItem(kSize, &descriptions);
- EXPECT_TRUE(
- BuildBlobAsync(descriptions, kTestBlobStorageIPCThresholdBytes + 1));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, std::set<std::string>(),
+ kTestBlobStorageIPCThresholdBytes + 1));
- EXPECT_FALSE(done_called_);
- EXPECT_FALSE(cancel_called_);
EXPECT_TRUE(request_called_);
EXPECT_EQ(1u, host_.blob_building_count());
ASSERT_EQ(1u, requests_.size());
@@ -183,18 +204,17 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) {
AddMemoryItem(kSize, &descriptions);
BlobDataBuilder expected(kBlobUUID);
- expected.set_content_type(kBlobType);
+ expected.set_content_type(kContentType);
+ expected.set_content_disposition(kContentDisposition);
char data[kSize];
memset(data, kFirstBlockByte, kTestBlobStorageMaxSharedMemoryBytes);
expected.AppendData(data, kTestBlobStorageMaxSharedMemoryBytes);
expected.AppendData(&kSecondBlockByte, 1);
- SetMatchingBuilder(&expected);
- EXPECT_TRUE(
- BuildBlobAsync(descriptions, kTestBlobStorageMaxSharedMemoryBytes + 1));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, std::set<std::string>(),
+ kTestBlobStorageMaxSharedMemoryBytes + 1));
- EXPECT_FALSE(done_called_);
- EXPECT_FALSE(cancel_called_);
EXPECT_TRUE(request_called_);
EXPECT_EQ(1u, host_.blob_building_count());
ASSERT_EQ(1u, requests_.size());
@@ -217,10 +237,9 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) {
BlobItemBytesResponse response(0);
std::vector<BlobItemBytesResponse> responses = {response};
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
- EXPECT_FALSE(done_called_);
- EXPECT_FALSE(cancel_called_);
EXPECT_TRUE(request_called_);
EXPECT_EQ(1u, host_.blob_building_count());
ASSERT_EQ(1u, requests_.size());
@@ -234,11 +253,16 @@ TEST_F(BlobAsyncBuilderHostTest, TestMultipleSharedMemRequests) {
response.request_number = 1;
responses[0] = response;
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses));
- EXPECT_TRUE(done_called_);
- EXPECT_FALSE(cancel_called_);
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
EXPECT_FALSE(request_called_);
EXPECT_EQ(0u, host_.blob_building_count());
+ scoped_ptr<BlobDataHandle> blob_handle =
+ context_.GetBlobDataFromUUID(kBlobUUID);
+ EXPECT_FALSE(blob_handle->IsBeingBuilt());
+ EXPECT_FALSE(blob_handle->IsBroken());
+ scoped_ptr<BlobDataSnapshot> blob_data = blob_handle->CreateSnapshot();
+ EXPECT_EQ(expected, *blob_data);
};
TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) {
@@ -249,18 +273,32 @@ TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) {
AddMemoryItem(2, &descriptions);
BlobDataBuilder expected(kBlobUUID);
- expected.set_content_type(kBlobType);
+ expected.set_content_type(kContentType);
+ expected.set_content_disposition(kContentDisposition);
AddShortcutMemoryItem(2, &expected);
- expected.AppendBlob(kFakeBlobUUID);
+ expected.AppendData(kCompletedBlobData);
AddShortcutMemoryItem(2, &expected);
- SetMatchingBuilder(&expected);
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
- host_.StopBuildingBlob(kBlobUUID);
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
+ host_.CancelBuildingBlob(kBlobUUID, IPCBlobCreationCancelCode::UNKNOWN,
+ &context_);
+
+ // Check that we're broken, and then remove the blob.
+ scoped_ptr<BlobDataHandle> blob_handle =
+ context_.GetBlobDataFromUUID(kBlobUUID);
+ EXPECT_FALSE(blob_handle->IsBeingBuilt());
+ EXPECT_TRUE(blob_handle->IsBroken());
+ blob_handle.reset();
+ DecrementBlobRefCount(kBlobUUID);
+ base::RunLoop().RunUntilIdle();
+ blob_handle = context_.GetBlobDataFromUUID(kBlobUUID);
+ EXPECT_FALSE(blob_handle.get());
+
+ // This should succeed because we've removed all references to the blob.
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
- EXPECT_FALSE(done_called_);
- EXPECT_FALSE(cancel_called_);
EXPECT_TRUE(request_called_);
EXPECT_EQ(1u, host_.blob_building_count());
request_called_ = false;
@@ -270,58 +308,308 @@ TEST_F(BlobAsyncBuilderHostTest, TestBasicIPCAndStopBuilding) {
BlobItemBytesResponse response2(1);
PopulateBytes(response2.allocate_mutable_data(2), 2);
std::vector<BlobItemBytesResponse> responses = {response1, response2};
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses));
- EXPECT_TRUE(done_called_);
- EXPECT_FALSE(cancel_called_);
+
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
EXPECT_FALSE(request_called_);
EXPECT_EQ(0u, host_.blob_building_count());
+ blob_handle = context_.GetBlobDataFromUUID(kBlobUUID);
+ EXPECT_FALSE(blob_handle->IsBeingBuilt());
+ EXPECT_FALSE(blob_handle->IsBroken());
+ scoped_ptr<BlobDataSnapshot> blob_data = blob_handle->CreateSnapshot();
+ EXPECT_EQ(expected, *blob_data);
+};
+
+TEST_F(BlobAsyncBuilderHostTest, TestBreakingAllBuilding) {
+ const std::string& kBlob1 = "blob1";
+ const std::string& kBlob2 = "blob2";
+ const std::string& kBlob3 = "blob3";
+
+ // Register blobs.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+
+ // Start building one of them.
+ std::vector<DataElement> descriptions;
+ AddMemoryItem(2, &descriptions);
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ host_.StartBuildingBlob(
+ kBlob1, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_TRUE(request_called_);
+
+ scoped_ptr<BlobDataHandle> blob_handle1 =
+ context_.GetBlobDataFromUUID(kBlob1);
+ scoped_ptr<BlobDataHandle> blob_handle2 =
+ context_.GetBlobDataFromUUID(kBlob2);
+ scoped_ptr<BlobDataHandle> blob_handle3 =
+ context_.GetBlobDataFromUUID(kBlob2);
+ EXPECT_TRUE(blob_handle1->IsBeingBuilt() && blob_handle2->IsBeingBuilt() &&
+ blob_handle3->IsBeingBuilt());
+ EXPECT_FALSE(blob_handle1->IsBroken() || blob_handle2->IsBroken() ||
+ blob_handle3->IsBroken());
+
+ host_.CancelAll(&context_);
+
+ EXPECT_FALSE(blob_handle1->IsBeingBuilt() || blob_handle2->IsBeingBuilt() ||
+ blob_handle3->IsBeingBuilt());
+ EXPECT_TRUE(blob_handle1->IsBroken() && blob_handle2->IsBroken() &&
+ blob_handle3->IsBroken());
+ blob_handle1.reset();
+ blob_handle2.reset();
+ blob_handle3.reset();
+ base::RunLoop().RunUntilIdle();
};
TEST_F(BlobAsyncBuilderHostTest, TestBadIPCs) {
std::vector<DataElement> descriptions;
// Test reusing same blob uuid.
- SetMatchingBuilder(nullptr);
AddMemoryItem(10, &descriptions);
AddBlobItem(&descriptions);
AddMemoryItem(5000, &descriptions);
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
- EXPECT_FALSE(BuildBlobAsync(descriptions, 5010));
- EXPECT_FALSE(done_called_);
- EXPECT_FALSE(cancel_called_);
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
EXPECT_FALSE(request_called_);
- host_.StopBuildingBlob(kBlobUUID);
+ host_.CancelBuildingBlob(kBlobUUID, IPCBlobCreationCancelCode::UNKNOWN,
+ &context_);
+ base::RunLoop().RunUntilIdle();
+ DecrementBlobRefCount(kBlobUUID);
+ EXPECT_FALSE(context_.GetBlobDataFromUUID(kBlobUUID).get());
- // Test we're _not_ an error if we get a bad uuid for responses.
+ // Test we're an error if we get a bad uuid for responses.
BlobItemBytesResponse response(0);
std::vector<BlobItemBytesResponse> responses = {response};
- EXPECT_TRUE(host_.OnMemoryResponses(kBlobUUID, responses));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
// Test empty responses.
responses.clear();
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
// Test response problems below here.
descriptions.clear();
AddMemoryItem(2, &descriptions);
AddBlobItem(&descriptions);
AddMemoryItem(2, &descriptions);
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
// Invalid request number.
BlobItemBytesResponse response1(3);
PopulateBytes(response1.allocate_mutable_data(2), 2);
responses = {response1};
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlobUUID)->IsBroken());
+ DecrementBlobRefCount(kBlobUUID);
+ base::RunLoop().RunUntilIdle();
// Duplicate request number responses.
- EXPECT_TRUE(BuildBlobAsync(descriptions, 5010));
+ EXPECT_EQ(BlobTransportResult::PENDING_RESPONSES,
+ BuildBlobAsync(descriptions, completed_blob_uuid_set_, 5010));
response1.request_number = 0;
BlobItemBytesResponse response2(0);
PopulateBytes(response2.allocate_mutable_data(2), 2);
responses = {response1, response2};
- EXPECT_FALSE(host_.OnMemoryResponses(kBlobUUID, responses));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.OnMemoryResponses(kBlobUUID, responses, &context_));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlobUUID)->IsBroken());
+ DecrementBlobRefCount(kBlobUUID);
+ base::RunLoop().RunUntilIdle();
+};
+
+TEST_F(BlobAsyncBuilderHostTest, WaitOnReferencedBlob) {
+ const std::string& kBlob1 = "blob1";
+ const std::string& kBlob2 = "blob2";
+ const std::string& kBlob3 = "blob3";
+
+ // Register blobs.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition,
+ {kBlob1, kBlob2}, &context_));
+
+ // Finish the third one, with a reference to the first and second blob.
+ std::vector<DataElement> descriptions;
+ AddShortcutMemoryItem(2, &descriptions);
+ DataElement element;
+ element.SetToBlob(kBlob1);
+ descriptions.push_back(element);
+ element.SetToBlob(kBlob2);
+ descriptions.push_back(element);
+
+ // Finish the third, but we should still be 'building' it.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.StartBuildingBlob(
+ kBlob3, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(request_called_);
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob3));
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob3));
+
+ // Finish the first.
+ descriptions.clear();
+ AddShortcutMemoryItem(2, &descriptions);
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.StartBuildingBlob(
+ kBlob1, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(request_called_);
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob1));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob1));
+
+ // Run the message loop so we propogate the construction complete callbacks.
+ base::RunLoop().RunUntilIdle();
+ // Verify we're not done.
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob3));
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob3));
+
+ // Finish the second.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.StartBuildingBlob(
+ kBlob2, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(request_called_);
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2));
+
+ // Run the message loop so we propogate the construction complete callbacks.
+ base::RunLoop().RunUntilIdle();
+ // Finally, we should be finished with third blob.
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob3));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob3));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob3));
+};
+
+TEST_F(BlobAsyncBuilderHostTest, IncorrectBlobDependencies) {
+ const std::string& kGoodBlob = "goodBlob";
+ const std::string& kBlob1 = "blob1";
+ const std::string& kBlob2 = "blob2";
+ const std::string& kBlob3 = "blob3";
+
+ // Register blobs. Blob 1 has a reference to itself, Blob 2 has a reference
+ // but doesn't use it, and blob 3 doesn't list it's reference.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kGoodBlob, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition,
+ {kBlob1}, &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition,
+ {kGoodBlob}, &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob3, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+
+ // The first blob shouldn't be building anymore.
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1));
+
+ // Try to finish the second one, without a reference to the first.
+ std::vector<DataElement> descriptions;
+ AddShortcutMemoryItem(2, &descriptions);
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.StartBuildingBlob(
+ kBlob2, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2));
+
+ // Try to finish the third one with the reference we didn't declare earlier.
+ descriptions.clear();
+ AddShortcutMemoryItem(2, &descriptions);
+ DataElement element;
+ element.SetToBlob(kGoodBlob);
+ descriptions.push_back(element);
+ EXPECT_EQ(BlobTransportResult::BAD_IPC,
+ host_.StartBuildingBlob(
+ kBlob3, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob3));
+};
+
+TEST_F(BlobAsyncBuilderHostTest, BlobBreaksWhenReferenceBreaks) {
+ const std::string& kBlob1 = "blob1";
+ const std::string& kBlob2 = "blob2";
+
+ // Register blobs.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition,
+ {kBlob1}, &context_));
+
+ // Finish the second one, with a reference to the first.
+ std::vector<DataElement> descriptions;
+ AddShortcutMemoryItem(2, &descriptions);
+ DataElement element;
+ element.SetToBlob(kBlob1);
+ descriptions.push_back(element);
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.StartBuildingBlob(
+ kBlob2, descriptions, 2, &context_,
+ base::Bind(&BlobAsyncBuilderHostTest::RequestMemoryCallback,
+ base::Unretained(this))));
+ EXPECT_FALSE(request_called_);
+ EXPECT_TRUE(host_.IsBeingBuilt(kBlob2));
+ EXPECT_TRUE(IsBeingBuiltInContext(kBlob2));
+
+ // Break the first.
+ descriptions.clear();
+ host_.CancelBuildingBlob(kBlob1, IPCBlobCreationCancelCode::UNKNOWN,
+ &context_);
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob1));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob1));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob1)->IsBroken());
+
+ // Run the message loop so we propogate the construction complete callbacks.
+ base::RunLoop().RunUntilIdle();
+ // We should be finished with third blob, and it should be broken.
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)->IsBroken());
+};
+
+TEST_F(BlobAsyncBuilderHostTest, BlobBreaksWhenReferenceBroken) {
+ const std::string& kBlob1 = "blob1";
+ const std::string& kBlob2 = "blob2";
+
+ // Register blobs.
+ EXPECT_EQ(BlobTransportResult::DONE,
+ host_.RegisterBlobUUID(kBlob1, kContentType, kContentDisposition,
+ std::set<std::string>(), &context_));
+ host_.CancelBuildingBlob(kBlob1, IPCBlobCreationCancelCode::UNKNOWN,
+ &context_);
+ EXPECT_EQ(BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN,
+ host_.RegisterBlobUUID(kBlob2, kContentType, kContentDisposition,
+ {kBlob1}, &context_));
+ EXPECT_FALSE(host_.IsBeingBuilt(kBlob2));
+ EXPECT_FALSE(IsBeingBuiltInContext(kBlob2));
+ EXPECT_TRUE(context_.GetBlobDataFromUUID(kBlob2)->IsBroken());
};
-} // namespace
} // namespace storage
diff --git a/chromium/content/browser/blob_storage/blob_async_transport_request_builder_unittest.cc b/chromium/content/browser/blob_storage/blob_async_transport_request_builder_unittest.cc
new file mode 100644
index 00000000000..071a06bb23f
--- /dev/null
+++ b/chromium/content/browser/blob_storage/blob_async_transport_request_builder_unittest.cc
@@ -0,0 +1,356 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "storage/browser/blob/blob_async_transport_request_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage {
+namespace {
+
+const char kNewUUID[] = "newUUID";
+const base::FilePath kFuturePopulatingFilePath = base::FilePath::FromUTF8Unsafe(
+ std::string(BlobDataBuilder::kAppendFutureFileTemporaryFileName));
+const char kFakeBlobUUID[] = "fakeBlob";
+
+void AddMemoryItem(size_t length, std::vector<DataElement>* out) {
+ DataElement bytes;
+ bytes.SetToBytesDescription(length);
+ out->push_back(bytes);
+}
+
+void AddShortcutMemoryItem(size_t length, std::vector<DataElement>* out) {
+ DataElement bytes;
+ bytes.SetToAllocatedBytes(length);
+ for (size_t i = 0; i < length; i++) {
+ bytes.mutable_bytes()[i] = static_cast<char>(i);
+ }
+ out->push_back(bytes);
+}
+
+void AddBlobItem(std::vector<DataElement>* out) {
+ DataElement blob;
+ blob.SetToBlob(kFakeBlobUUID);
+ out->push_back(blob);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestNoMemoryItems) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ // Here we test that we don't do any requests when there are no memory items.
+ AddBlobItem(&infos);
+ AddBlobItem(&infos);
+ AddBlobItem(&infos);
+ strategy.InitializeForIPCRequests(100, // max_ipc_memory_size
+ 0, // blob_total_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(0u, strategy.file_sizes().size());
+ EXPECT_EQ(0u, strategy.requests().size());
+
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendBlob(kFakeBlobUUID);
+ expected_builder.AppendBlob(kFakeBlobUUID);
+ expected_builder.AppendBlob(kFakeBlobUUID);
+ EXPECT_EQ(expected_builder, builder);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestLargeBlockToFile) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ AddMemoryItem(305, &infos);
+ strategy.InitializeForFileRequests(400, // max_file_size
+ 305, // blob_total_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(1u, strategy.file_sizes().size());
+ EXPECT_EQ(305ul, strategy.file_sizes().at(0));
+ EXPECT_EQ(1u, strategy.requests().size());
+
+ auto& memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 305ull, 0u, 0ull),
+ memory_item_request.message);
+
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendFile(kFuturePopulatingFilePath, 0, 305,
+ base::Time::FromDoubleT(0));
+ EXPECT_EQ(expected_builder, builder);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestLargeBlockToFiles) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ AddMemoryItem(1000, &infos);
+ strategy.InitializeForFileRequests(400, // max_file_size
+ 1000, // blob_total_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(3u, strategy.file_sizes().size());
+ EXPECT_EQ(400ul, strategy.file_sizes().at(0));
+ EXPECT_EQ(400ul, strategy.file_sizes().at(1));
+ EXPECT_EQ(200ul, strategy.file_sizes().at(2));
+ EXPECT_EQ(3u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 400ull, 0u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(1);
+ EXPECT_EQ(1u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(1u, 0u, 400ull, 400ull, 1u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(2);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(2u, 0u, 800ull, 200ull, 2u, 0ull),
+ memory_item_request.message);
+
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendFile(kFuturePopulatingFilePath, 0, 400,
+ base::Time::FromDoubleT(0));
+ expected_builder.AppendFile(kFuturePopulatingFilePath, 0, 400,
+ base::Time::FromDoubleT(0));
+ expected_builder.AppendFile(kFuturePopulatingFilePath, 0, 200,
+ base::Time::FromDoubleT(0));
+ EXPECT_EQ(expected_builder, builder);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest,
+ TestLargeBlocksConsolidatingInFiles) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ // We should have 3 storage items for the memory, two files, 400 each.
+ // We end up with storage items:
+ // 1: File A, 300MB
+ // 2: Blob
+ // 3: File A, 100MB (300MB offset)
+ // 4: File B, 400MB
+ AddMemoryItem(300, &infos);
+ AddBlobItem(&infos);
+ AddMemoryItem(500, &infos);
+
+ strategy.InitializeForFileRequests(400, // max_file_size
+ 800, // blob_total_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(2u, strategy.file_sizes().size());
+ EXPECT_EQ(400ul, strategy.file_sizes().at(0));
+ EXPECT_EQ(400ul, strategy.file_sizes().at(1));
+ EXPECT_EQ(3u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 300ull, 0u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(1);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(1u, 2u, 0ull, 100ull, 0u, 300ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(2);
+ EXPECT_EQ(3u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(
+ BlobItemBytesRequest::CreateFileRequest(2u, 2u, 100ull, 400ull, 1u, 0ull),
+ memory_item_request.message);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestSharedMemorySegmentation) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ // For transport we should have 3 shared memories, and then storage in 3
+ // browser items.
+ AddMemoryItem(500, &infos);
+ strategy.InitializeForSharedMemoryRequests(200, // max_shared_memory_size
+ 500, // total_blob_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.file_sizes().size());
+ EXPECT_EQ(3u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(200u, strategy.shared_memory_sizes().at(0));
+ EXPECT_EQ(200u, strategy.shared_memory_sizes().at(1));
+ EXPECT_EQ(100u, strategy.shared_memory_sizes().at(2));
+ EXPECT_EQ(3u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull,
+ 200ull, 0u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(1);
+ EXPECT_EQ(1u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 0u, 200ull,
+ 200ull, 1u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(2);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 0u, 400ull,
+ 100ull, 2u, 0ull),
+ memory_item_request.message);
+
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendFutureData(200);
+ expected_builder.AppendFutureData(200);
+ expected_builder.AppendFutureData(100);
+ EXPECT_EQ(expected_builder, builder);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest,
+ TestSharedMemorySegmentationAndStorage) {
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ std::vector<DataElement> infos;
+
+ // For transport, we should have 2 shared memories, where the first one
+ // have half 0 and half 3, and then the last one has half 3.
+ //
+ // For storage, we should have 3 browser items that match the pre-transport
+ // version:
+ // 1: Bytes 100MB
+ // 2: Blob
+ // 3: Bytes 200MB
+ AddShortcutMemoryItem(100, &infos); // should have no behavior change
+ AddBlobItem(&infos);
+ AddMemoryItem(200, &infos);
+
+ strategy.InitializeForSharedMemoryRequests(200, // max_shared_memory_size
+ 300, // total_blob_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.file_sizes().size());
+ EXPECT_EQ(2u, strategy.shared_memory_sizes().size());
+ EXPECT_EQ(200u, strategy.shared_memory_sizes().at(0));
+ EXPECT_EQ(100u, strategy.shared_memory_sizes().at(1));
+ EXPECT_EQ(3u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull,
+ 100ull, 0u, 0ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(1);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 2u, 0ull,
+ 100ull, 0u, 100ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(2);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(100u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 2u, 100ull,
+ 100ull, 1u, 0ull),
+ memory_item_request.message);
+
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendFutureData(100);
+ expected_builder.AppendBlob(kFakeBlobUUID);
+ expected_builder.AppendFutureData(200);
+ EXPECT_EQ(expected_builder, builder);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestSimpleIPC) {
+ // Test simple IPC strategy, where size < max_ipc_memory_size and we have
+ // just one item.
+ std::vector<DataElement> infos;
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ AddMemoryItem(10, &infos);
+ AddBlobItem(&infos);
+
+ strategy.InitializeForIPCRequests(100, // max_ipc_memory_size
+ 10, // total_blob_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.file_sizes().size());
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ ASSERT_EQ(1u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull),
+ memory_item_request.message);
+}
+
+TEST(BlobAsyncTransportRequestBuilderTest, TestMultipleIPC) {
+ // Same as above, but with 2 items and a blob in-between.
+ std::vector<DataElement> infos;
+ BlobAsyncTransportRequestBuilder strategy;
+ BlobDataBuilder builder(kNewUUID);
+ AddShortcutMemoryItem(10, &infos); // should have no behavior change
+ AddBlobItem(&infos);
+ AddMemoryItem(80, &infos);
+
+ strategy.InitializeForIPCRequests(100, // max_ipc_memory_size
+ 90, // total_blob_size
+ infos, &builder);
+
+ EXPECT_EQ(0u, strategy.file_sizes().size());
+ EXPECT_EQ(0u, strategy.shared_memory_sizes().size());
+ ASSERT_EQ(2u, strategy.requests().size());
+
+ auto memory_item_request = strategy.requests().at(0);
+ EXPECT_EQ(0u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull),
+ memory_item_request.message);
+
+ memory_item_request = strategy.requests().at(1);
+ EXPECT_EQ(2u, memory_item_request.browser_item_index);
+ EXPECT_EQ(0u, memory_item_request.browser_item_offset);
+ EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(1u, 2u, 0ull, 80ull),
+ memory_item_request.message);
+
+ // We still populate future data, as the strategy assumes we will be
+ // requesting the data.
+ BlobDataBuilder expected_builder(kNewUUID);
+ expected_builder.AppendFutureData(10);
+ expected_builder.AppendBlob(kFakeBlobUUID);
+ expected_builder.AppendFutureData(80);
+ EXPECT_EQ(expected_builder, builder);
+}
+} // namespace
+} // namespace storage
diff --git a/chromium/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc b/chromium/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc
deleted file mode 100644
index 6318439e916..00000000000
--- a/chromium/content/browser/blob_storage/blob_async_transport_strategy_unittest.cc
+++ /dev/null
@@ -1,458 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "storage/browser/blob/blob_async_transport_strategy.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace storage {
-namespace {
-
-const char kNewUUID[] = "newUUID";
-const base::FilePath kFuturePopulatingFilePath = base::FilePath::FromUTF8Unsafe(
- std::string(BlobDataBuilder::kAppendFutureFileTemporaryFileName));
-const char kFakeBlobUUID[] = "fakeBlob";
-
-void AddMemoryItem(size_t length, std::vector<DataElement>* out) {
- DataElement bytes;
- bytes.SetToBytesDescription(length);
- out->push_back(bytes);
-}
-
-void AddShortcutMemoryItem(size_t length, std::vector<DataElement>* out) {
- DataElement bytes;
- bytes.SetToAllocatedBytes(length);
- for (size_t i = 0; i < length; i++) {
- bytes.mutable_bytes()[i] = static_cast<char>(i);
- }
- out->push_back(bytes);
-}
-
-void AddBlobItem(std::vector<DataElement>* out) {
- DataElement blob;
- blob.SetToBlob(kFakeBlobUUID);
- out->push_back(blob);
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestNoMemoryItems) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // Here we test that we don't do any requests when there are no memory items.
- AddBlobItem(&infos);
- AddBlobItem(&infos);
- AddBlobItem(&infos);
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_available
- kNewUUID, infos);
-
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(0u, strategy.handle_sizes().size());
- EXPECT_EQ(0u, strategy.requests().size());
-
- BlobDataBuilder builder(kNewUUID);
- builder.AppendBlob(kFakeBlobUUID);
- builder.AppendBlob(kFakeBlobUUID);
- builder.AppendBlob(kFakeBlobUUID);
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestLargeBlockToFile) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // Here we test our size > max_blob_in_memory_size (100),
- // and we save to one file. (size < max_file_size)
- AddMemoryItem(305, &infos);
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_available
- kNewUUID, infos);
-
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(1u, strategy.handle_sizes().size());
- EXPECT_EQ(305ul, strategy.handle_sizes().at(0));
- EXPECT_EQ(1u, strategy.requests().size());
-
- auto& memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 305ull, 0u, 0ull),
- memory_item_request.message);
-
- BlobDataBuilder builder(kNewUUID);
- builder.AppendFile(kFuturePopulatingFilePath, 0, 305,
- base::Time::FromDoubleT(0));
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestLargeBlockToFiles) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // Here we test our size > max_blob_in_memory_size (300),
- // and we save 3 files. (size > max_file_size)
- AddMemoryItem(1000, &infos);
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_available
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(3u, strategy.handle_sizes().size());
- EXPECT_EQ(400ul, strategy.handle_sizes().at(0));
- EXPECT_EQ(400ul, strategy.handle_sizes().at(1));
- EXPECT_EQ(200ul, strategy.handle_sizes().at(2));
- EXPECT_EQ(3u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 400ull, 0u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(1);
- EXPECT_EQ(1u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(1u, 0u, 400ull, 400ull, 1u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(2);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(2u, 0u, 800ull, 200ull, 2u, 0ull),
- memory_item_request.message);
-
- BlobDataBuilder builder(kNewUUID);
- builder.AppendFile(kFuturePopulatingFilePath, 0, 400,
- base::Time::FromDoubleT(0));
- builder.AppendFile(kFuturePopulatingFilePath, 0, 400,
- base::Time::FromDoubleT(0));
- builder.AppendFile(kFuturePopulatingFilePath, 0, 200,
- base::Time::FromDoubleT(0));
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestLargeBlocksConsolidatingInFiles) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // We should have 3 storage items for the memory, two files, 400 each.
- // We end up with storage items:
- // 1: File A, 300MB
- // 2: Blob
- // 3: File A, 100MB (300MB offset)
- // 4: File B, 400MB
- AddMemoryItem(300, &infos);
- AddBlobItem(&infos);
- AddMemoryItem(500, &infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_available
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(2u, strategy.handle_sizes().size());
- EXPECT_EQ(400ul, strategy.handle_sizes().at(0));
- EXPECT_EQ(400ul, strategy.handle_sizes().at(1));
- EXPECT_EQ(3u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(0u, 0u, 0ull, 300ull, 0u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(1);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(1u, 2u, 0ull, 100ull, 0u, 300ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(2);
- EXPECT_EQ(3u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(
- BlobItemBytesRequest::CreateFileRequest(2u, 2u, 100ull, 400ull, 1u, 0ull),
- memory_item_request.message);
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestSharedMemorySegmentation) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // For transport we should have 3 shared memories, and then storage in 3
- // browser items.
- // (size > max_shared_memory_size and size < max_blob_in_memory_size
- AddMemoryItem(500, &infos);
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 300, // max_file_size
- 5000, // disk_space_left
- 500, // memory_available
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(3u, strategy.handle_sizes().size());
- EXPECT_EQ(200u, strategy.handle_sizes().at(0));
- EXPECT_EQ(200u, strategy.handle_sizes().at(1));
- EXPECT_EQ(100u, strategy.handle_sizes().at(2));
- EXPECT_EQ(3u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull,
- 200ull, 0u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(1);
- EXPECT_EQ(1u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 0u, 200ull,
- 200ull, 1u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(2);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 0u, 400ull,
- 100ull, 2u, 0ull),
- memory_item_request.message);
-
- BlobDataBuilder builder(kNewUUID);
- builder.AppendFutureData(200);
- builder.AppendFutureData(200);
- builder.AppendFutureData(100);
-
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestSharedMemorySegmentationAndStorage) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // For transport, we should have 2 shared memories, where the first one
- // have half 0 and half 3, and then the last one has half 3.
- //
- // For storage, we should have 3 browser items that match the pre-transport
- // version:
- // 1: Bytes 100MB
- // 2: Blob
- // 3: Bytes 200MB
- AddShortcutMemoryItem(100, &infos); // should have no behavior change
- AddBlobItem(&infos);
- AddMemoryItem(200, &infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 300, // max_file_size
- 5000, // disk_space_left
- 300, // memory_available
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- EXPECT_EQ(2u, strategy.handle_sizes().size());
- EXPECT_EQ(200u, strategy.handle_sizes().at(0));
- EXPECT_EQ(100u, strategy.handle_sizes().at(1));
- EXPECT_EQ(3u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(0u, 0u, 0ull,
- 100ull, 0u, 0ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(1);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(1u, 2u, 0ull,
- 100ull, 0u, 100ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(2);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(100u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateSharedMemoryRequest(2u, 2u, 100ull,
- 100ull, 1u, 0ull),
- memory_item_request.message);
-
- BlobDataBuilder builder(kNewUUID);
- builder.AppendFutureData(100);
- builder.AppendBlob(kFakeBlobUUID);
- builder.AppendFutureData(200);
-
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestTooLarge) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // Our item is too large for disk, so error out.
- AddMemoryItem(5001, &infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_left
- kNewUUID, infos);
-
- EXPECT_EQ(0u, strategy.handle_sizes().size());
- EXPECT_EQ(0u, strategy.handle_sizes().size());
- EXPECT_EQ(0u, strategy.requests().size());
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_TOO_LARGE, strategy.error());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestNoDisk) {
- BlobAsyncTransportStrategy strategy;
- std::vector<DataElement> infos;
-
- // Our item is too large for memory, and we are in no_disk mode (incognito)
- AddMemoryItem(301, &infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 0, // disk_space_left
- 300, // memory_available
- kNewUUID, infos);
-
- EXPECT_EQ(0u, strategy.handle_sizes().size());
- EXPECT_EQ(0u, strategy.handle_sizes().size());
- EXPECT_EQ(0u, strategy.requests().size());
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_TOO_LARGE, strategy.error());
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestSimpleIPC) {
- // Test simple IPC strategy, where size < max_ipc_memory_size and we have
- // just one item.
- std::vector<DataElement> infos;
- BlobAsyncTransportStrategy strategy;
- AddMemoryItem(10, &infos);
- AddBlobItem(&infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_left
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- ASSERT_EQ(1u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull),
- memory_item_request.message);
-}
-
-TEST(BlobAsyncTransportStrategyTest, TestMultipleIPC) {
- // Same as above, but with 2 items and a blob in-between.
- std::vector<DataElement> infos;
- BlobAsyncTransportStrategy strategy;
- infos.clear();
- AddShortcutMemoryItem(10, &infos); // should have no behavior change
- AddBlobItem(&infos);
- AddMemoryItem(80, &infos);
-
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_left
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_NONE, strategy.error());
-
- ASSERT_EQ(2u, strategy.requests().size());
-
- auto memory_item_request = strategy.requests().at(0);
- EXPECT_EQ(0u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(0u, 0u, 0ull, 10ull),
- memory_item_request.message);
-
- memory_item_request = strategy.requests().at(1);
- EXPECT_EQ(2u, memory_item_request.browser_item_index);
- EXPECT_EQ(0u, memory_item_request.browser_item_offset);
- EXPECT_EQ(BlobItemBytesRequest::CreateIPCRequest(1u, 2u, 0ull, 80ull),
- memory_item_request.message);
-
- // We still populate future data, as the strategy assumes we will be
- // requesting the data.
- BlobDataBuilder builder(kNewUUID);
- builder.AppendFutureData(10);
- builder.AppendBlob(kFakeBlobUUID);
- builder.AppendFutureData(80);
-
- EXPECT_EQ(builder, *strategy.blob_builder());
-}
-
-TEST(BlobAsyncTransportStrategyTest, Shortcut) {
- std::vector<DataElement> infos;
- AddMemoryItem(100, &infos);
- AddBlobItem(&infos);
- EXPECT_FALSE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 200));
-
- infos.clear();
- AddShortcutMemoryItem(100, &infos);
- AddBlobItem(&infos);
- EXPECT_TRUE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 200));
-
- infos.clear();
- AddShortcutMemoryItem(100, &infos);
- EXPECT_FALSE(BlobAsyncTransportStrategy::ShouldBeShortcut(infos, 99));
-}
-} // namespace
-
-TEST(BlobAsyncTransportStrategyTest, TestInvalidParams) {
- std::vector<DataElement> infos;
- // In order to test uin64_t overflow, we would need to have an array with more
- // than size_t entries (for 32 byte stuff). So this would only happen if the
- // IPC was malformed. We instead have to friend this test from DataElement so
- // we can modify the length to be > size_t.
-
- // Test uint64_t overflow.
- BlobAsyncTransportStrategy strategy;
- AddMemoryItem(1, &infos);
- AddMemoryItem(1, &infos);
- infos.back().length_ = std::numeric_limits<uint64_t>::max();
- strategy.Initialize(100, // max_ipc_memory_size
- 200, // max_shared_memory_size
- 400, // max_file_size
- 5000, // disk_space_left
- 100, // memory_left
- kNewUUID, infos);
- EXPECT_EQ(BlobAsyncTransportStrategy::ERROR_INVALID_PARAMS,
- strategy.error());
-}
-} // namespace storage
diff --git a/chromium/content/browser/blob_storage/blob_dispatcher_host.cc b/chromium/content/browser/blob_storage/blob_dispatcher_host.cc
new file mode 100644
index 00000000000..d61653cdaf5
--- /dev/null
+++ b/chromium/content/browser/blob_storage/blob_dispatcher_host.cc
@@ -0,0 +1,370 @@
+// 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 "content/browser/blob_storage/blob_dispatcher_host.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/common/fileapi/webblob_messages.h"
+#include "ipc/ipc_platform_file.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_transport_result.h"
+#include "storage/common/blob_storage/blob_item_bytes_request.h"
+#include "storage/common/blob_storage/blob_item_bytes_response.h"
+#include "storage/common/data_element.h"
+#include "url/gurl.h"
+
+using storage::BlobStorageContext;
+using storage::BlobStorageRegistry;
+using storage::BlobTransportResult;
+using storage::IPCBlobCreationCancelCode;
+
+namespace content {
+namespace {
+
+// These are used for UMA stats, don't change.
+enum RefcountOperation {
+ BDH_DECREMENT = 0,
+ BDH_INCREMENT,
+ BDH_TRACING_ENUM_LAST
+};
+
+} // namespace
+
+BlobDispatcherHost::BlobDispatcherHost(
+ ChromeBlobStorageContext* blob_storage_context)
+ : BrowserMessageFilter(BlobMsgStart),
+ blob_storage_context_(blob_storage_context) {}
+
+BlobDispatcherHost::~BlobDispatcherHost() {
+ ClearHostFromBlobStorageContext();
+}
+
+void BlobDispatcherHost::OnChannelClosing() {
+ ClearHostFromBlobStorageContext();
+ public_blob_urls_.clear();
+ blobs_inuse_map_.clear();
+}
+
+bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BlobDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_RegisterBlobUUID, OnRegisterBlobUUID)
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_StartBuildingBlob, OnStartBuildingBlob)
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_MemoryItemResponse, OnMemoryItemResponse)
+ IPC_MESSAGE_HANDLER(BlobStorageMsg_CancelBuildingBlob, OnCancelBuildingBlob)
+ IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount, OnIncrementBlobRefCount)
+ IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount, OnDecrementBlobRefCount)
+ IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL, OnRegisterPublicBlobURL)
+ IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void BlobDispatcherHost::OnRegisterBlobUUID(
+ const std::string& uuid,
+ const std::string& content_type,
+ const std::string& content_disposition,
+ const std::set<std::string>& referenced_blob_uuids) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BlobStorageContext* context = this->context();
+ if (uuid.empty() || context->registry().HasEntry(uuid) ||
+ async_builder_.IsBeingBuilt(uuid)) {
+ bad_message::ReceivedBadMessage(this, bad_message::BDH_UUID_REGISTERED);
+ return;
+ }
+ blobs_inuse_map_[uuid] = 1;
+ BlobTransportResult result = async_builder_.RegisterBlobUUID(
+ uuid, content_type, content_disposition, referenced_blob_uuids, context);
+ switch (result) {
+ case BlobTransportResult::BAD_IPC:
+ blobs_inuse_map_.erase(uuid);
+ bad_message::ReceivedBadMessage(this,
+ bad_message::BDH_CONSTRUCTION_FAILED);
+ break;
+ case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN:
+ // The async builder builds the blob as broken, and we just need to send
+ // the cancel message back to the renderer.
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN));
+ break;
+ case BlobTransportResult::DONE:
+ break;
+ case BlobTransportResult::CANCEL_MEMORY_FULL:
+ case BlobTransportResult::CANCEL_FILE_ERROR:
+ case BlobTransportResult::CANCEL_UNKNOWN:
+ case BlobTransportResult::PENDING_RESPONSES:
+ NOTREACHED();
+ break;
+ }
+}
+
+void BlobDispatcherHost::OnStartBuildingBlob(
+ const std::string& uuid,
+ const std::vector<storage::DataElement>& descriptions) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (uuid.empty()) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ BlobStorageContext* context = this->context();
+ const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid);
+ if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) {
+ // We ignore messages for blobs that don't exist to handle the case where
+ // the renderer de-refs a blob that we're still constructing, and there are
+ // no references to that blob. We ignore broken as well, in the case where
+ // we decided to break a blob after RegisterBlobUUID is called.
+ // Second, if the last dereference of the blob happened on a different host,
+ // then we still haven't gotten rid of the 'building' state in the original
+ // host. So we call cancel, and send the message just in case that happens.
+ if (async_builder_.IsBeingBuilt(uuid)) {
+ async_builder_.CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING,
+ context);
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
+ }
+ return;
+ }
+ if (!async_builder_.IsBeingBuilt(uuid)) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ // |this| owns async_builder_ so using base::Unretained(this) is safe.
+ BlobTransportResult result = async_builder_.StartBuildingBlob(
+ uuid, descriptions, context->memory_available(), context,
+ base::Bind(&BlobDispatcherHost::SendMemoryRequest, base::Unretained(this),
+ uuid));
+ SendIPCResponse(uuid, result);
+}
+
+void BlobDispatcherHost::OnMemoryItemResponse(
+ const std::string& uuid,
+ const std::vector<storage::BlobItemBytesResponse>& responses) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (uuid.empty()) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ BlobStorageContext* context = this->context();
+ const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid);
+ if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) {
+ // We ignore messages for blobs that don't exist to handle the case where
+ // the renderer de-refs a blob that we're still constructing, and there are
+ // no references to that blob. We ignore broken as well, in the case where
+ // we decided to break a blob after sending the memory request.
+ // Note: if a blob is broken, then it can't be in the async_builder.
+ // Second, if the last dereference of the blob happened on a different host,
+ // then we still haven't gotten rid of the 'building' state in the original
+ // host. So we call cancel, and send the message just in case that happens.
+ if (async_builder_.IsBeingBuilt(uuid)) {
+ async_builder_.CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING,
+ context);
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
+ }
+ return;
+ }
+ if (!async_builder_.IsBeingBuilt(uuid)) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ BlobTransportResult result =
+ async_builder_.OnMemoryResponses(uuid, responses, context);
+ SendIPCResponse(uuid, result);
+}
+
+void BlobDispatcherHost::OnCancelBuildingBlob(
+ const std::string& uuid,
+ const storage::IPCBlobCreationCancelCode code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (uuid.empty()) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ BlobStorageContext* context = this->context();
+ const BlobStorageRegistry::Entry* entry = context->registry().GetEntry(uuid);
+ if (!entry || entry->state == BlobStorageRegistry::BlobState::BROKEN) {
+ // We ignore messages for blobs that don't exist to handle the case where
+ // the renderer de-refs a blob that we're still constructing, and there are
+ // no references to that blob. We ignore broken as well, in the case where
+ // we decided to break a blob and the renderer also decided to cancel.
+ // Note: if a blob is broken, then it can't be in the async_builder.
+ // Second, if the last dereference of the blob happened on a different host,
+ // then we still haven't gotten rid of the 'building' state in the original
+ // host. So we call cancel just in case this happens.
+ if (async_builder_.IsBeingBuilt(uuid)) {
+ async_builder_.CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING,
+ context);
+ }
+ return;
+ }
+ if (!async_builder_.IsBeingBuilt(uuid)) {
+ SendIPCResponse(uuid, BlobTransportResult::BAD_IPC);
+ return;
+ }
+ VLOG(1) << "Blob construction of " << uuid << " cancelled by renderer. "
+ << " Reason: " << static_cast<int>(code) << ".";
+ async_builder_.CancelBuildingBlob(uuid, code, context);
+}
+
+void BlobDispatcherHost::OnIncrementBlobRefCount(const std::string& uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BlobStorageContext* context = this->context();
+ if (uuid.empty()) {
+ bad_message::ReceivedBadMessage(
+ this, bad_message::BDH_INVALID_REFCOUNT_OPERATION);
+ return;
+ }
+ if (!context->registry().HasEntry(uuid)) {
+ UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_INCREMENT,
+ BDH_TRACING_ENUM_LAST);
+ return;
+ }
+ context->IncrementBlobRefCount(uuid);
+ blobs_inuse_map_[uuid] += 1;
+}
+
+void BlobDispatcherHost::OnDecrementBlobRefCount(const std::string& uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (uuid.empty()) {
+ bad_message::ReceivedBadMessage(
+ this, bad_message::BDH_INVALID_REFCOUNT_OPERATION);
+ return;
+ }
+ if (!IsInUseInHost(uuid)) {
+ UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidReference", BDH_DECREMENT,
+ BDH_TRACING_ENUM_LAST);
+ return;
+ }
+ BlobStorageContext* context = this->context();
+ context->DecrementBlobRefCount(uuid);
+ blobs_inuse_map_[uuid] -= 1;
+ if (blobs_inuse_map_[uuid] == 0) {
+ blobs_inuse_map_.erase(uuid);
+ // If the blob has been deleted in the context and we're still building it,
+ // this means we have no references waiting to read it. Clear the building
+ // state and send a cancel message to the renderer.
+ if (async_builder_.IsBeingBuilt(uuid) &&
+ !context->registry().HasEntry(uuid)) {
+ async_builder_.CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING,
+ context);
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING));
+ }
+ }
+}
+
+void BlobDispatcherHost::OnRegisterPublicBlobURL(const GURL& public_url,
+ const std::string& uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BlobStorageContext* context = this->context();
+ if (uuid.empty()) {
+ bad_message::ReceivedBadMessage(this,
+ bad_message::BDH_INVALID_URL_OPERATION);
+ return;
+ }
+ if (!IsInUseInHost(uuid) || context->registry().IsURLMapped(public_url)) {
+ UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidURLRegister", BDH_INCREMENT,
+ BDH_TRACING_ENUM_LAST);
+ return;
+ }
+ context->RegisterPublicBlobURL(public_url, uuid);
+ public_blob_urls_.insert(public_url);
+}
+
+void BlobDispatcherHost::OnRevokePublicBlobURL(const GURL& public_url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!public_url.is_valid()) {
+ bad_message::ReceivedBadMessage(this,
+ bad_message::BDH_INVALID_URL_OPERATION);
+ return;
+ }
+ if (!IsUrlRegisteredInHost(public_url)) {
+ UMA_HISTOGRAM_ENUMERATION("Storage.Blob.InvalidURLRegister", BDH_DECREMENT,
+ BDH_TRACING_ENUM_LAST);
+ return;
+ }
+ context()->RevokePublicBlobURL(public_url);
+ public_blob_urls_.erase(public_url);
+}
+
+storage::BlobStorageContext* BlobDispatcherHost::context() {
+ return blob_storage_context_->context();
+}
+
+void BlobDispatcherHost::SendMemoryRequest(
+ const std::string& uuid,
+ scoped_ptr<std::vector<storage::BlobItemBytesRequest>> requests,
+ scoped_ptr<std::vector<base::SharedMemoryHandle>> memory_handles,
+ scoped_ptr<std::vector<base::File>> files) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::vector<IPC::PlatformFileForTransit> file_handles;
+ // TODO(dmurph): Support file-backed blob transportation.
+ DCHECK(files->empty());
+ Send(new BlobStorageMsg_RequestMemoryItem(uuid, *requests, *memory_handles,
+ file_handles));
+}
+
+void BlobDispatcherHost::SendIPCResponse(const std::string& uuid,
+ storage::BlobTransportResult result) {
+ switch (result) {
+ case BlobTransportResult::BAD_IPC:
+ bad_message::ReceivedBadMessage(this,
+ bad_message::BDH_CONSTRUCTION_FAILED);
+ return;
+ case BlobTransportResult::CANCEL_MEMORY_FULL:
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::OUT_OF_MEMORY));
+ return;
+ case BlobTransportResult::CANCEL_FILE_ERROR:
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::FILE_WRITE_FAILED));
+ return;
+ case BlobTransportResult::CANCEL_REFERENCED_BLOB_BROKEN:
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN));
+ return;
+ case BlobTransportResult::CANCEL_UNKNOWN:
+ Send(new BlobStorageMsg_CancelBuildingBlob(
+ uuid, IPCBlobCreationCancelCode::UNKNOWN));
+ return;
+ case BlobTransportResult::PENDING_RESPONSES:
+ return;
+ case BlobTransportResult::DONE:
+ Send(new BlobStorageMsg_DoneBuildingBlob(uuid));
+ return;
+ }
+ NOTREACHED();
+}
+
+bool BlobDispatcherHost::IsInUseInHost(const std::string& uuid) {
+ return blobs_inuse_map_.find(uuid) != blobs_inuse_map_.end();
+}
+
+bool BlobDispatcherHost::IsUrlRegisteredInHost(const GURL& blob_url) {
+ return public_blob_urls_.find(blob_url) != public_blob_urls_.end();
+}
+
+void BlobDispatcherHost::ClearHostFromBlobStorageContext() {
+ BlobStorageContext* context = this->context();
+ for (const auto& url : public_blob_urls_) {
+ context->RevokePublicBlobURL(url);
+ }
+ for (const auto& uuid_refnum_pair : blobs_inuse_map_) {
+ for (int i = 0; i < uuid_refnum_pair.second; ++i)
+ context->DecrementBlobRefCount(uuid_refnum_pair.first);
+ }
+ async_builder_.CancelAll(context);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/blob_storage/blob_dispatcher_host.h b/chromium/content/browser/blob_storage/blob_dispatcher_host.h
new file mode 100644
index 00000000000..bf1a03cf8fb
--- /dev/null
+++ b/chromium/content/browser/blob_storage/blob_dispatcher_host.h
@@ -0,0 +1,148 @@
+// 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 CONTENT_BROWSER_BLOB_STORAGE_BLOB_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_BLOB_STORAGE_BLOB_DISPATCHER_HOST_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory_handle.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "storage/browser/blob/blob_async_builder_host.h"
+#include "storage/browser/blob/blob_transport_result.h"
+#include "storage/common/blob_storage/blob_storage_constants.h"
+
+class GURL;
+
+namespace IPC {
+class Sender;
+}
+
+namespace storage {
+class DataElement;
+class BlobDataBuilder;
+struct BlobItemBytesRequest;
+struct BlobItemBytesResponse;
+class BlobStorageContext;
+}
+
+namespace content {
+class ChromeBlobStorageContext;
+
+// This class's responsibility is to listen for and dispatch blob storage
+// messages and handle logistics of blob storage for a single child process.
+// When the child process terminates all blob references attributable to
+// that process go away upon destruction of the instance.
+// This lives in the browser process, is single threaded (IO thread), and there
+// is one per child process.
+class CONTENT_EXPORT BlobDispatcherHost : public BrowserMessageFilter {
+ public:
+ explicit BlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context);
+
+ // BrowserMessageFilter implementation.
+ void OnChannelClosing() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ protected:
+ ~BlobDispatcherHost() override;
+
+ // For testing use only.
+ void SetMemoryConstantsForTesting(size_t max_ipc_memory_size,
+ size_t max_shared_memory_size,
+ uint64_t max_file_size) {
+ async_builder_.SetMemoryConstantsForTesting(
+ max_ipc_memory_size, max_shared_memory_size, max_file_size);
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<BlobDispatcherHost>;
+ friend class BlobDispatcherHostTest;
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, EmptyUUIDs);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, MultipleTransfers);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, SharedMemoryTransfer);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, OnCancelBuildingBlob);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ BlobReferenceWhileConstructing);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ BlobReferenceWhileShortcutConstructing);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ BlobReferenceWhileConstructingCancelled);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, DecrementRefAfterRegister);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, DecrementRefAfterOnStart);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ DecrementRefAfterOnStartWithHandle);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ HostDisconnectAfterRegisterWithHandle);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, HostDisconnectAfterOnStart);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ HostDisconnectAfterOnMemoryResponse);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ CreateBlobWithBrokenReference);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ DeferenceBlobOnDifferentHost);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest, BuildingReferenceChain);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ BuildingReferenceChainWithCancel);
+ FRIEND_TEST_ALL_PREFIXES(BlobDispatcherHostTest,
+ BuildingReferenceChainWithSourceDeath);
+
+ typedef std::map<std::string, int> BlobReferenceMap;
+
+ void OnRegisterBlobUUID(const std::string& uuid,
+ const std::string& content_type,
+ const std::string& content_disposition,
+ const std::set<std::string>& referenced_blob_uuids);
+ void OnStartBuildingBlob(
+ const std::string& uuid,
+ const std::vector<storage::DataElement>& descriptions);
+ void OnMemoryItemResponse(
+ const std::string& uuid,
+ const std::vector<storage::BlobItemBytesResponse>& response);
+ void OnCancelBuildingBlob(const std::string& uuid,
+ const storage::IPCBlobCreationCancelCode code);
+
+ void OnIncrementBlobRefCount(const std::string& uuid);
+ void OnDecrementBlobRefCount(const std::string& uuid);
+ void OnRegisterPublicBlobURL(const GURL& public_url, const std::string& uuid);
+ void OnRevokePublicBlobURL(const GURL& public_url);
+
+ storage::BlobStorageContext* context();
+
+ void SendMemoryRequest(
+ const std::string& uuid,
+ scoped_ptr<std::vector<storage::BlobItemBytesRequest>> requests,
+ scoped_ptr<std::vector<base::SharedMemoryHandle>> memory_handles,
+ scoped_ptr<std::vector<base::File>> files);
+
+ // Send the appropriate IPC response to the renderer for the given result.
+ void SendIPCResponse(const std::string& uuid,
+ storage::BlobTransportResult result);
+
+ bool IsInUseInHost(const std::string& uuid);
+ bool IsUrlRegisteredInHost(const GURL& blob_url);
+
+ // Unregisters all blobs and urls that were registered in this host.
+ void ClearHostFromBlobStorageContext();
+
+ // Collection of blob ids and a count of how many usages
+ // of that id are attributable to this consumer.
+ BlobReferenceMap blobs_inuse_map_;
+
+ // The set of public blob urls coined by this consumer.
+ std::set<GURL> public_blob_urls_;
+
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+ storage::BlobAsyncBuilderHost async_builder_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlobDispatcherHost);
+};
+} // namespace content
+#endif // CONTENT_BROWSER_BLOB_STORAGE_BLOB_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/blob_storage/blob_dispatcher_host_unittest.cc b/chromium/content/browser/blob_storage/blob_dispatcher_host_unittest.cc
new file mode 100644
index 00000000000..43cdf8ad373
--- /dev/null
+++ b/chromium/content/browser/blob_storage/blob_dispatcher_host_unittest.cc
@@ -0,0 +1,1199 @@
+// 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 "content/browser/blob_storage/blob_dispatcher_host.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/run_loop.h"
+#include "base/tuple.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/common/fileapi/webblob_messages.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_sender.h"
+#include "ipc/ipc_test_sink.h"
+#include "ipc/message_filter.h"
+#include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/common/blob_storage/blob_item_bytes_request.h"
+#include "storage/common/blob_storage/blob_item_bytes_response.h"
+#include "storage/common/data_element.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using storage::BlobDataBuilder;
+using storage::BlobDataHandle;
+using storage::BlobItemBytesRequest;
+using storage::BlobItemBytesResponse;
+using storage::BlobStorageContext;
+using storage::BlobTransportResult;
+using storage::DataElement;
+using storage::IPCBlobCreationCancelCode;
+using RequestMemoryCallback =
+ storage::BlobAsyncBuilderHost::RequestMemoryCallback;
+
+namespace content {
+namespace {
+
+const char kContentType[] = "text/plain";
+const char kContentDisposition[] = "content_disposition";
+const char kData[] = "data!!";
+const size_t kDataSize = 6;
+
+const size_t kTestBlobStorageIPCThresholdBytes = 20;
+const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
+const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
+
+void ConstructionCompletePopulator(bool* succeeded_pointer,
+ IPCBlobCreationCancelCode* reason_pointer,
+ bool succeeded,
+ IPCBlobCreationCancelCode reason) {
+ *succeeded_pointer = succeeded;
+ *reason_pointer = reason;
+}
+
+class TestableBlobDispatcherHost : public BlobDispatcherHost {
+ public:
+ TestableBlobDispatcherHost(ChromeBlobStorageContext* blob_storage_context,
+ IPC::TestSink* sink)
+ : BlobDispatcherHost(blob_storage_context), sink_(sink) {
+ this->SetMemoryConstantsForTesting(kTestBlobStorageIPCThresholdBytes,
+ kTestBlobStorageMaxSharedMemoryBytes,
+ kTestBlobStorageMaxFileSizeBytes);
+ }
+
+ bool Send(IPC::Message* message) override { return sink_->Send(message); }
+
+ void ShutdownForBadMessage() override { shutdown_for_bad_message_ = true; }
+
+ bool shutdown_for_bad_message_ = false;
+
+ protected:
+ ~TestableBlobDispatcherHost() override {}
+
+ private:
+ friend class base::RefCountedThreadSafe<TestableBlobDispatcherHost>;
+
+ IPC::TestSink* sink_;
+};
+
+} // namespace
+
+class BlobDispatcherHostTest : public testing::Test {
+ protected:
+ BlobDispatcherHostTest()
+ : chrome_blob_storage_context_(
+ ChromeBlobStorageContext::GetFor(&browser_context_)) {
+ host_ =
+ new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_);
+ }
+ ~BlobDispatcherHostTest() override {}
+
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(switches::kDisableKillAfterBadIPC)) {
+ command_line->AppendSwitch(switches::kDisableKillAfterBadIPC);
+ }
+ // We run the run loop to initialize the chrome blob storage context.
+ base::RunLoop().RunUntilIdle();
+ context_ = chrome_blob_storage_context_->context();
+ DCHECK(context_);
+ }
+
+ void ExpectBlobNotExist(const std::string& id) {
+ EXPECT_FALSE(context_->registry().HasEntry(id));
+ EXPECT_FALSE(host_->IsInUseInHost(id));
+ EXPECT_FALSE(IsBeingBuiltInHost(id));
+ }
+
+ void AsyncShortcutBlobTransfer(const std::string& id) {
+ sink_.ClearMessages();
+ ExpectBlobNotExist(id);
+ host_->OnRegisterBlobUUID(id, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ DataElement element;
+ element.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(id, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ ExpectDone(id);
+ sink_.ClearMessages();
+ }
+
+ void AsyncBlobTransfer(const std::string& id) {
+ sink_.ClearMessages();
+ ExpectBlobNotExist(id);
+ host_->OnRegisterBlobUUID(id, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(id, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ // Expect our request.
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ ExpectRequest(id, expected_requests);
+ sink_.ClearMessages();
+
+ // Send results;
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+ host_->OnMemoryItemResponse(id, responses);
+ ExpectDone(id);
+ sink_.ClearMessages();
+ }
+
+ void ExpectAndResetBadMessage() {
+ EXPECT_TRUE(host_->shutdown_for_bad_message_);
+ host_->shutdown_for_bad_message_ = false;
+ }
+
+ void ExpectHandleEqualsData(BlobDataHandle* handle,
+ const std::vector<DataElement>& data) {
+ scoped_ptr<storage::BlobDataSnapshot> snapshot = handle->CreateSnapshot();
+ EXPECT_FALSE(handle->IsBeingBuilt());
+ for (size_t i = 0; i < data.size(); i++) {
+ const DataElement& expected = data[i];
+ const DataElement& actual = snapshot->items()[i]->data_element();
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ(data.size(), snapshot->items().size());
+ }
+
+ void ExpectRequest(
+ const std::string& expected_uuid,
+ const std::vector<BlobItemBytesRequest>& expected_requests) {
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
+ const IPC::Message* message =
+ sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID);
+ ASSERT_TRUE(message);
+ base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>,
+ std::vector<base::SharedMemoryHandle>,
+ std::vector<IPC::PlatformFileForTransit>>
+ args;
+ BlobStorageMsg_RequestMemoryItem::Read(message, &args);
+ EXPECT_EQ(expected_uuid, base::get<0>(args));
+ std::vector<BlobItemBytesRequest> requests = base::get<1>(args);
+ ASSERT_EQ(requests.size(), expected_requests.size());
+ for (size_t i = 0; i < expected_requests.size(); ++i) {
+ EXPECT_EQ(expected_requests[i], requests[i]);
+ }
+ }
+
+ void ExpectRequestWithSharedMemoryHandles(
+ const std::string& expected_uuid,
+ const std::vector<BlobItemBytesRequest>& expected_requests,
+ std::vector<base::SharedMemoryHandle>* shared_memory_handles) {
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
+ const IPC::Message* message =
+ sink_.GetUniqueMessageMatching(BlobStorageMsg_RequestMemoryItem::ID);
+ ASSERT_TRUE(message);
+ base::Tuple<std::string, std::vector<storage::BlobItemBytesRequest>,
+ std::vector<base::SharedMemoryHandle>,
+ std::vector<IPC::PlatformFileForTransit>>
+ args;
+ BlobStorageMsg_RequestMemoryItem::Read(message, &args);
+ EXPECT_EQ(expected_uuid, base::get<0>(args));
+ std::vector<BlobItemBytesRequest> requests = base::get<1>(args);
+ ASSERT_EQ(requests.size(), expected_requests.size());
+ for (size_t i = 0; i < expected_requests.size(); ++i) {
+ EXPECT_EQ(expected_requests[i], requests[i]);
+ }
+ *shared_memory_handles = std::move(base::get<2>(args));
+ }
+
+ void ExpectCancel(const std::string& expected_uuid,
+ IPCBlobCreationCancelCode code) {
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID));
+ const IPC::Message* message =
+ sink_.GetUniqueMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID);
+ ASSERT_TRUE(message);
+ base::Tuple<std::string, IPCBlobCreationCancelCode> args;
+ BlobStorageMsg_CancelBuildingBlob::Read(message, &args);
+ EXPECT_EQ(expected_uuid, base::get<0>(args));
+ EXPECT_EQ(code, base::get<1>(args));
+ }
+
+ void ExpectDone(const std::string& expected_uuid) {
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_RequestMemoryItem::ID));
+ EXPECT_FALSE(
+ sink_.GetFirstMessageMatching(BlobStorageMsg_CancelBuildingBlob::ID));
+ const IPC::Message* message =
+ sink_.GetUniqueMessageMatching(BlobStorageMsg_DoneBuildingBlob::ID);
+ base::Tuple<std::string> args;
+ BlobStorageMsg_DoneBuildingBlob::Read(message, &args);
+ EXPECT_EQ(expected_uuid, base::get<0>(args));
+ }
+
+ bool IsBeingBuiltInHost(const std::string& uuid) {
+ return host_->async_builder_.IsBeingBuilt(uuid);
+ }
+
+ IPC::TestSink sink_;
+ TestBrowserThreadBundle browser_thread_bundle_;
+ TestBrowserContext browser_context_;
+ ChromeBlobStorageContext* chrome_blob_storage_context_;
+ BlobStorageContext* context_ = nullptr;
+ scoped_refptr<TestableBlobDispatcherHost> host_;
+};
+
+TEST_F(BlobDispatcherHostTest, EmptyUUIDs) {
+ host_->OnRegisterBlobUUID("", "", "", std::set<std::string>());
+ ExpectAndResetBadMessage();
+ host_->OnStartBuildingBlob("", std::vector<DataElement>());
+ ExpectAndResetBadMessage();
+ host_->OnMemoryItemResponse("", std::vector<BlobItemBytesResponse>());
+ ExpectAndResetBadMessage();
+ host_->OnCancelBuildingBlob("", IPCBlobCreationCancelCode::UNKNOWN);
+ ExpectAndResetBadMessage();
+}
+
+TEST_F(BlobDispatcherHostTest, Shortcut) {
+ const std::string kId = "uuid1";
+ AsyncShortcutBlobTransfer(kId);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle);
+
+ DataElement expected;
+ expected.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {expected};
+ ExpectHandleEqualsData(handle.get(), elements);
+}
+
+TEST_F(BlobDispatcherHostTest, RegularTransfer) {
+ const std::string kId = "uuid1";
+ AsyncBlobTransfer(kId);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle);
+
+ DataElement expected;
+ expected.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {expected};
+ ExpectHandleEqualsData(handle.get(), elements);
+}
+
+TEST_F(BlobDispatcherHostTest, MultipleTransfers) {
+ const std::string kId = "uuid";
+ const int kNumIters = 10;
+ for (int i = 0; i < kNumIters; i++) {
+ std::string id = kId;
+ id += ('0' + i);
+ ExpectBlobNotExist(id);
+ host_->OnRegisterBlobUUID(id, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ }
+ sink_.ClearMessages();
+ for (int i = 0; i < kNumIters; i++) {
+ std::string id = kId;
+ id += ('0' + i);
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(id, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ // Expect our request.
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ ExpectRequest(id, expected_requests);
+ sink_.ClearMessages();
+ }
+ for (int i = 0; i < kNumIters; i++) {
+ std::string id = kId;
+ id += ('0' + i);
+ // Send results;
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+ host_->OnMemoryItemResponse(id, responses);
+ ExpectDone(id);
+ sink_.ClearMessages();
+ }
+}
+
+TEST_F(BlobDispatcherHostTest, SharedMemoryTransfer) {
+ const std::string kId = "uuid1";
+ const size_t kLargeSize = kTestBlobStorageMaxSharedMemoryBytes * 2;
+ std::vector<base::SharedMemoryHandle> shared_memory_handles;
+
+ ExpectBlobNotExist(kId);
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ // Grab the handle.
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ bool built = false;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+ EXPECT_FALSE(built);
+
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ DataElement element;
+ element.SetToBytesDescription(kLargeSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ // Expect our first request.
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateSharedMemoryRequest(
+ 0 /* request_number */, 0 /* renderer_item_index */,
+ 0 /* renderer_item_offset */,
+ static_cast<uint64_t>(
+ kTestBlobStorageMaxSharedMemoryBytes) /* size */,
+ 0 /* handle_index */, 0 /* handle_offset */)};
+ ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
+ &shared_memory_handles);
+ sink_.ClearMessages();
+
+ // Populate the shared memory.
+ EXPECT_EQ(1u, shared_memory_handles.size());
+ EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
+ {
+ base::SharedMemory memory(
+ base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
+ memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
+ std::memset(memory.memory(), 'X', kTestBlobStorageMaxSharedMemoryBytes);
+ memory.Close();
+ }
+
+ // Send the confirmation.
+ std::vector<BlobItemBytesResponse> responses = {BlobItemBytesResponse(0)};
+ host_->OnMemoryItemResponse(kId, responses);
+
+ // Expect our second request.
+ expected_requests = {BlobItemBytesRequest::CreateSharedMemoryRequest(
+ 1 /* request_number */, 0 /* renderer_item_index */,
+ static_cast<uint64_t>(
+ kTestBlobStorageMaxSharedMemoryBytes) /* renderer_item_offset */,
+ static_cast<uint64_t>(kTestBlobStorageMaxSharedMemoryBytes) /* size */,
+ 0 /* handle_index */, 0 /* handle_offset */)};
+ ExpectRequestWithSharedMemoryHandles(kId, expected_requests,
+ &shared_memory_handles);
+ sink_.ClearMessages();
+
+ // Populate the shared memory.
+ EXPECT_EQ(1u, shared_memory_handles.size());
+ EXPECT_TRUE(base::SharedMemory::IsHandleValid(shared_memory_handles[0]));
+ {
+ base::SharedMemory memory(
+ base::SharedMemory::DuplicateHandle(shared_memory_handles[0]), false);
+ memory.Map(kTestBlobStorageMaxSharedMemoryBytes);
+ std::memset(memory.memory(), 'Z', kTestBlobStorageMaxSharedMemoryBytes);
+ memory.Close();
+ }
+ // Send the confirmation.
+ responses = {BlobItemBytesResponse(1)};
+ host_->OnMemoryItemResponse(kId, responses);
+
+ ExpectDone(kId);
+ sink_.ClearMessages();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(built) << "Error code: " << static_cast<int>(error_code);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle);
+
+ DataElement expected;
+ expected.SetToAllocatedBytes(kLargeSize / 2);
+ std::memset(expected.mutable_bytes(), 'X', kLargeSize / 2);
+ elements = {expected};
+ std::memset(expected.mutable_bytes(), 'Z', kLargeSize / 2);
+ elements.push_back(expected);
+ ExpectHandleEqualsData(handle.get(), elements);
+}
+
+TEST_F(BlobDispatcherHostTest, OnCancelBuildingBlob) {
+ const std::string kId("id");
+ // We ignore blobs that are unknown, as it could have been cancelled earlier
+ // and the renderer didn't know about it yet.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ // Start building blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ // It should have requested memory here.
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ sink_.ClearMessages();
+
+ // Cancel in middle of construction.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(host_->IsInUseInHost(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+ // Check that's it's broken.
+ scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle->IsBroken());
+ handle.reset();
+ base::RunLoop().RunUntilIdle();
+
+ // Get rid of it in the host.
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ ExpectBlobNotExist(kId);
+
+ // Create blob again to verify we don't have any old construction state lying
+ // around.
+ AsyncBlobTransfer(kId);
+
+ // Check data.
+ handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle);
+ DataElement expected;
+ expected.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> expecteds = {expected};
+ ExpectHandleEqualsData(handle.get(), expecteds);
+
+ // Verify we can't cancel after the fact.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ ExpectAndResetBadMessage();
+}
+
+TEST_F(BlobDispatcherHostTest, BlobDataWithHostDeletion) {
+ // Build up a basic blob.
+ const std::string kId("id");
+ AsyncShortcutBlobTransfer(kId);
+ scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(handle);
+
+ // Kill the host.
+ host_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ // Should still be there due to the handle.
+ scoped_ptr<BlobDataHandle> another_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(another_handle);
+
+ // Should disappear after dropping both handles.
+ handle.reset();
+ another_handle.reset();
+ base::RunLoop().RunUntilIdle();
+
+ handle = context_->GetBlobDataFromUUID(kId);
+ EXPECT_FALSE(handle);
+}
+
+TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructing) {
+ const std::string kId("id");
+
+ // Start building blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ // Grab the handle.
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(blob_data_handle);
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ bool built = false;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ // Continue building.
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ sink_.ClearMessages();
+
+ // Send data.
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+ sink_.ClearMessages();
+ host_->OnMemoryItemResponse(kId, responses);
+
+ ExpectDone(kId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(built) << "Error code: " << static_cast<int>(error_code);
+}
+
+TEST_F(BlobDispatcherHostTest, BlobReferenceWhileShortcutConstructing) {
+ const std::string kId("id");
+
+ // Start building blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ // Grab the handle.
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(blob_data_handle);
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ bool built = false;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ // Continue building.
+ DataElement element;
+ element.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ ExpectDone(kId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(built) << "Error code: " << static_cast<int>(error_code);
+}
+
+TEST_F(BlobDispatcherHostTest, BlobReferenceWhileConstructingCancelled) {
+ const std::string kId("id");
+
+ // Start building blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ // Grab the handle.
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(blob_data_handle);
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ bool built = true;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ // Cancel in middle of construction.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(host_->IsInUseInHost(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+ EXPECT_TRUE(blob_data_handle->IsBroken());
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::UNKNOWN, error_code);
+ error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ built = true;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::UNKNOWN, error_code);
+
+ // Remove it.
+ blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ host_->OnDecrementBlobRefCount(kId);
+ ExpectBlobNotExist(kId);
+}
+
+TEST_F(BlobDispatcherHostTest, DecrementRefAfterRegister) {
+ const std::string kId("id");
+ // Decrement the refcount while building (renderer blob gc'd before
+ // construction was completed).
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+ ExpectCancel(kId,
+ IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
+ sink_.ClearMessages();
+
+ // Do the same, but this time grab a handle before we decrement.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(IsBeingBuiltInHost(kId));
+
+ // Finish up the blob, and verify we got the done message.
+ DataElement element;
+ element.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ ExpectDone(kId);
+ sink_.ClearMessages();
+ // Get rid of the handle, and verify it's gone.
+ blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ // Check that it's no longer around.
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStart) {
+ const std::string kId("id");
+
+ // Decrement the refcount while building, after we call OnStartBuildlingBlob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+ ExpectCancel(kId,
+ IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
+ sink_.ClearMessages();
+
+ // Do the same, but this time grab a handle to keep it alive.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ // Grab the handle before decrementing.
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(IsBeingBuiltInHost(kId));
+
+ // We finish the blob, and verify that we send 'Done' back to the renderer.
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+ host_->OnMemoryItemResponse(kId, responses);
+ ExpectDone(kId);
+ sink_.ClearMessages();
+ // Check that it's still around.
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+
+ // Get rid of the handle, and verify it's gone.
+ blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ // Check that it's no longer around.
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, DecrementRefAfterOnStartWithHandle) {
+ const std::string kId("id");
+ // Decrement the refcount while building, after we call
+ // OnStartBuildlingBlob, except we have another handle.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ bool built = true;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+
+ // Check that we got the expected request.
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(IsBeingBuiltInHost(kId));
+ // Decrement, simulating where the ref goes out of scope in renderer.
+ host_->OnDecrementBlobRefCount(kId);
+ // We still have the blob as it's not done.
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ EXPECT_TRUE(IsBeingBuiltInHost(kId));
+ // Cancel to clean up.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ // Run loop to propagate the handle decrement in the host.
+ base::RunLoop().RunUntilIdle();
+ // We still have the entry because of our earlier handle.
+ EXPECT_TRUE(context_->registry().HasEntry(kId));
+ EXPECT_FALSE(IsBeingBuiltInHost(kId));
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::UNKNOWN, error_code);
+ sink_.ClearMessages();
+
+ // Should disappear after dropping the handle.
+ EXPECT_TRUE(blob_data_handle->IsBroken());
+ blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, HostDisconnectAfterRegisterWithHandle) {
+ const std::string kId("id");
+
+ // Delete host with a handle to the blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ scoped_ptr<BlobDataHandle> blob_data_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(blob_data_handle->IsBeingBuilt());
+ bool built = true;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ blob_data_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+ // Get rid of host, which was doing the constructing.
+ host_ = nullptr;
+ EXPECT_FALSE(blob_data_handle->IsBeingBuilt());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::SOURCE_DIED_IN_TRANSIT, error_code);
+
+ // Should still be there due to the handle.
+ scoped_ptr<BlobDataHandle> another_handle =
+ context_->GetBlobDataFromUUID(kId);
+ EXPECT_TRUE(another_handle);
+
+ // Should disappear after dropping both handles.
+ blob_data_handle.reset();
+ another_handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnStart) {
+ const std::string kId("id");
+
+ // Host deleted after OnStartBuilding.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ host_->OnStartBuildingBlob(kId, elements);
+
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+ host_ = nullptr;
+ // We need to run the message loop because of the handle in the async builder.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, HostDisconnectAfterOnMemoryResponse) {
+ const std::string kId("id");
+
+ // Host deleted after OnMemoryItemResponse.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+
+ // Create list of two items.
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element, element};
+ host_->OnStartBuildingBlob(kId, elements);
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize),
+ BlobItemBytesRequest::CreateIPCRequest(1, 1, 0, kDataSize)};
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+
+ // Send just one response so the blob isn't 'done' yet.
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+ host_->OnMemoryItemResponse(kId, responses);
+ EXPECT_EQ(0u, sink_.message_count());
+
+ host_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, CreateBlobWithBrokenReference) {
+ const std::string kBrokenId("id1");
+ const std::string kReferencingId("id2");
+
+ // First, let's test a circular reference.
+ const std::string kCircularId("id1");
+ host_->OnRegisterBlobUUID(kCircularId, std::string(kContentType),
+ std::string(kContentDisposition), {kCircularId});
+ ExpectAndResetBadMessage();
+
+ // Next, test a blob that references a broken blob.
+ host_->OnRegisterBlobUUID(kBrokenId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ host_->OnCancelBuildingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ EXPECT_TRUE(context_->GetBlobDataFromUUID(kBrokenId)->IsBroken());
+
+ // Create referencing blob. We should be broken right away, but also ignore
+ // the subsequent OnStart message.
+ host_->OnRegisterBlobUUID(kReferencingId, std::string(kContentType),
+ std::string(kContentDisposition), {kBrokenId});
+ EXPECT_TRUE(context_->GetBlobDataFromUUID(kReferencingId)->IsBroken());
+ EXPECT_FALSE(IsBeingBuiltInHost(kReferencingId));
+ EXPECT_TRUE(context_->registry().HasEntry(kReferencingId));
+ ExpectCancel(kReferencingId,
+ IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN);
+ sink_.ClearMessages();
+
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ element.SetToBlob(kBrokenId);
+ elements.push_back(element);
+ host_->OnStartBuildingBlob(kReferencingId, elements);
+ EXPECT_EQ(0u, sink_.message_count());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(BlobDispatcherHostTest, DeferenceBlobOnDifferentHost) {
+ const std::string kId("id");
+ // Data elements for our transfer & checking messages.
+ DataElement element;
+ element.SetToBytesDescription(kDataSize);
+ std::vector<DataElement> elements = {element};
+ std::vector<BlobItemBytesRequest> expected_requests = {
+ BlobItemBytesRequest::CreateIPCRequest(0, 0, 0, kDataSize)};
+ BlobItemBytesResponse response(0);
+ std::memcpy(response.allocate_mutable_data(kDataSize), kData, kDataSize);
+ std::vector<BlobItemBytesResponse> responses = {response};
+
+ scoped_refptr<TestableBlobDispatcherHost> host2(
+ new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
+
+ // Delete host with another host having a referencing, then dereference on
+ // second host. Verify we're still building it on first host, and then
+ // verify that a building message from the renderer will kill it.
+
+ // Test OnStartBuilding after double dereference.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ host2->OnIncrementBlobRefCount(kId);
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(host_->IsInUseInHost(kId));
+ host2->OnDecrementBlobRefCount(kId);
+ // So no more blob in the context, but we're still being built in host 1.
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
+ host_->OnStartBuildingBlob(kId, elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ // We should be cleaned up.
+ EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
+ ExpectCancel(kId,
+ IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
+ sink_.ClearMessages();
+
+ // Same as above, but test OnMemoryItemResponse after double dereference.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ host2->OnIncrementBlobRefCount(kId);
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(host_->IsInUseInHost(kId));
+ host_->OnStartBuildingBlob(kId, elements);
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+
+ host2->OnDecrementBlobRefCount(kId);
+ // So no more blob in the context, but we're still being built in host 1.
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
+ host_->OnMemoryItemResponse(kId, responses);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ // We should be cleaned up.
+ EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
+ ExpectCancel(kId,
+ IPCBlobCreationCancelCode::BLOB_DEREFERENCED_WHILE_BUILDING);
+ sink_.ClearMessages();
+
+ // Same, but now for OnCancel.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ host2->OnIncrementBlobRefCount(kId);
+ host_->OnDecrementBlobRefCount(kId);
+ EXPECT_FALSE(host_->IsInUseInHost(kId));
+ host_->OnStartBuildingBlob(kId, elements);
+ ExpectRequest(kId, expected_requests);
+ sink_.ClearMessages();
+
+ host2->OnDecrementBlobRefCount(kId);
+ // So no more blob in the context, but we're still being built in host 1.
+ EXPECT_FALSE(context_->registry().HasEntry(kId));
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kId));
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ // We should be cleaned up.
+ EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kId));
+}
+
+TEST_F(BlobDispatcherHostTest, BuildingReferenceChain) {
+ const std::string kId("id");
+ const std::string kSameHostReferencingId("id2");
+ const std::string kDifferentHostReferencingId("id3");
+ // Data elements for our transfer & checking messages.
+ DataElement element;
+ element.SetToBytes(kData, kDataSize);
+ std::vector<DataElement> elements = {element};
+ DataElement referencing_element;
+ referencing_element.SetToBlob(kId);
+ std::vector<DataElement> referencing_elements = {referencing_element};
+ std::set<std::string> referenced_blobs_set = {kId};
+
+ scoped_refptr<TestableBlobDispatcherHost> host2(
+ new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
+
+ // We want to have a blob referencing another blob that is building, both on
+ // the same host and a different host. We should successfully build all blobs
+ // after the referenced blob is finished.
+
+ // First we start the referenced blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_TRUE(host_->IsInUseInHost(kId));
+
+ // Next we start the referencing blobs in both the same and different host.
+ host_->OnRegisterBlobUUID(kSameHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition),
+ referenced_blobs_set);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ host_->OnStartBuildingBlob(kSameHostReferencingId, referencing_elements);
+ EXPECT_FALSE(host_->shutdown_for_bad_message_);
+ ExpectDone(kSameHostReferencingId);
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kSameHostReferencingId));
+ sink_.ClearMessages();
+ // Now the other host.
+ host2->OnRegisterBlobUUID(
+ kDifferentHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition), referenced_blobs_set);
+ EXPECT_FALSE(host2->shutdown_for_bad_message_);
+ host2->OnStartBuildingBlob(kDifferentHostReferencingId, referencing_elements);
+ EXPECT_FALSE(host2->shutdown_for_bad_message_);
+ ExpectDone(kDifferentHostReferencingId);
+ EXPECT_TRUE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ sink_.ClearMessages();
+
+ // Now we finish the first blob, and we expect all blobs to finish.
+ host_->OnStartBuildingBlob(kId, elements);
+ ExpectDone(kId);
+ // We need to run the message loop to propagate the construction callbacks.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kSameHostReferencingId));
+ EXPECT_FALSE(
+ context_->GetBlobDataFromUUID(kSameHostReferencingId)->IsBroken());
+ EXPECT_FALSE(
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId)->IsBroken());
+ sink_.ClearMessages();
+
+ // Finally check that our data is correct in the child elements.
+ scoped_ptr<BlobDataHandle> handle =
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId);
+ ExpectHandleEqualsData(handle.get(), elements);
+}
+
+TEST_F(BlobDispatcherHostTest, BuildingReferenceChainWithCancel) {
+ const std::string kId("id");
+ const std::string kSameHostReferencingId("id2");
+ const std::string kDifferentHostReferencingId("id3");
+ // Data elements for our transfer & checking messages.
+ DataElement referencing_element;
+ referencing_element.SetToBlob(kId);
+ std::vector<DataElement> referencing_elements = {referencing_element};
+ std::set<std::string> referenced_blobs_set = {kId};
+
+ scoped_refptr<TestableBlobDispatcherHost> host2(
+ new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
+
+ // We want to have a blob referencing another blob that is building, both on
+ // the same host and a different host. After we cancel the first blob, the
+ // others should cancel as well.
+
+ // First we start the referenced blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_TRUE(host_->IsInUseInHost(kId));
+
+ // Next we start the referencing blobs in both the same and different host.
+ host_->OnRegisterBlobUUID(kSameHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition),
+ referenced_blobs_set);
+ host_->OnStartBuildingBlob(kSameHostReferencingId, referencing_elements);
+ ExpectDone(kSameHostReferencingId);
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kSameHostReferencingId));
+ sink_.ClearMessages();
+ // Now the other host.
+ host2->OnRegisterBlobUUID(
+ kDifferentHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition), referenced_blobs_set);
+ host2->OnStartBuildingBlob(kDifferentHostReferencingId, referencing_elements);
+ ExpectDone(kDifferentHostReferencingId);
+ EXPECT_TRUE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ sink_.ClearMessages();
+ bool built = false;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId)
+ ->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ // Now we cancel the first blob, and we expect all blobs to cancel.
+ host_->OnCancelBuildingBlob(kId, IPCBlobCreationCancelCode::UNKNOWN);
+ // We need to run the message loop to propagate the construction callbacks.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ EXPECT_FALSE(host_->async_builder_.IsBeingBuilt(kSameHostReferencingId));
+ EXPECT_TRUE(
+ context_->GetBlobDataFromUUID(kSameHostReferencingId)->IsBroken());
+ EXPECT_TRUE(
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId)->IsBroken());
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::REFERENCED_BLOB_BROKEN, error_code);
+ sink_.ClearMessages();
+}
+
+TEST_F(BlobDispatcherHostTest, BuildingReferenceChainWithSourceDeath) {
+ const std::string kId("id");
+ const std::string kSameHostReferencingId("id2");
+ const std::string kDifferentHostReferencingId("id3");
+ // Data elements for our transfer & checking messages.
+ DataElement referencing_element;
+ referencing_element.SetToBlob(kId);
+ std::vector<DataElement> referencing_elements = {referencing_element};
+ std::set<std::string> referenced_blobs_set = {kId};
+
+ scoped_refptr<TestableBlobDispatcherHost> host2(
+ new TestableBlobDispatcherHost(chrome_blob_storage_context_, &sink_));
+
+ // We want to have a blob referencing another blob that is building, both on
+ // the same host and a different host. When we destroy the host, the other
+ // blob should cancel, as well as the blob on the other host.
+
+ // First we start the referenced blob.
+ host_->OnRegisterBlobUUID(kId, std::string(kContentType),
+ std::string(kContentDisposition),
+ std::set<std::string>());
+ EXPECT_TRUE(host_->IsInUseInHost(kId));
+
+ // Next we start the referencing blobs in both the same and different host.
+ host_->OnRegisterBlobUUID(kSameHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition),
+ referenced_blobs_set);
+ host_->OnStartBuildingBlob(kSameHostReferencingId, referencing_elements);
+ ExpectDone(kSameHostReferencingId);
+ EXPECT_TRUE(host_->async_builder_.IsBeingBuilt(kSameHostReferencingId));
+ sink_.ClearMessages();
+ // Now the other host.
+ host2->OnRegisterBlobUUID(
+ kDifferentHostReferencingId, std::string(kContentType),
+ std::string(kContentDisposition), referenced_blobs_set);
+ host2->OnStartBuildingBlob(kDifferentHostReferencingId, referencing_elements);
+ ExpectDone(kDifferentHostReferencingId);
+ EXPECT_TRUE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ sink_.ClearMessages();
+
+ // Grab handles & add listeners.
+ bool built = true;
+ IPCBlobCreationCancelCode error_code = IPCBlobCreationCancelCode::UNKNOWN;
+ scoped_ptr<BlobDataHandle> blob_handle = context_->GetBlobDataFromUUID(kId);
+ blob_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &built, &error_code));
+
+ bool same_host_built = true;
+ IPCBlobCreationCancelCode same_host_error_code =
+ IPCBlobCreationCancelCode::UNKNOWN;
+ scoped_ptr<BlobDataHandle> same_host_blob_handle =
+ context_->GetBlobDataFromUUID(kSameHostReferencingId);
+ same_host_blob_handle->RunOnConstructionComplete(base::Bind(
+ &ConstructionCompletePopulator, &same_host_built, &same_host_error_code));
+
+ bool other_host_built = true;
+ IPCBlobCreationCancelCode other_host_error_code =
+ IPCBlobCreationCancelCode::UNKNOWN;
+ scoped_ptr<BlobDataHandle> other_host_blob_handle =
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId);
+ other_host_blob_handle->RunOnConstructionComplete(
+ base::Bind(&ConstructionCompletePopulator, &other_host_built,
+ &other_host_error_code));
+
+ // Now we kill the host.
+ host_ = nullptr;
+ // We need to run the message loop to propagate the construction callbacks.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(host2->async_builder_.IsBeingBuilt(kDifferentHostReferencingId));
+ EXPECT_TRUE(
+ context_->GetBlobDataFromUUID(kSameHostReferencingId)->IsBroken());
+ EXPECT_TRUE(
+ context_->GetBlobDataFromUUID(kDifferentHostReferencingId)->IsBroken());
+
+ // Check our callbacks
+ EXPECT_FALSE(built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::SOURCE_DIED_IN_TRANSIT, error_code);
+ EXPECT_FALSE(same_host_built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::SOURCE_DIED_IN_TRANSIT,
+ same_host_error_code);
+ EXPECT_FALSE(other_host_built);
+ EXPECT_EQ(IPCBlobCreationCancelCode::SOURCE_DIED_IN_TRANSIT,
+ other_host_error_code);
+
+ sink_.ClearMessages();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/blob_storage/blob_storage_registry_unittest.cc b/chromium/content/browser/blob_storage/blob_storage_registry_unittest.cc
index 9ff10d69700..918554202b0 100644
--- a/chromium/content/browser/blob_storage/blob_storage_registry_unittest.cc
+++ b/chromium/content/browser/blob_storage/blob_storage_registry_unittest.cc
@@ -15,36 +15,33 @@ using BlobState = BlobStorageRegistry::BlobState;
TEST(BlobStorageRegistry, UUIDRegistration) {
const std::string kBlob1 = "Blob1";
+ const std::string kType = "type1";
+ const std::string kDisposition = "disp1";
BlobStorageRegistry registry;
EXPECT_FALSE(registry.DeleteEntry(kBlob1));
EXPECT_EQ(0u, registry.blob_count());
- Entry* entry = registry.CreateEntry(kBlob1);
+ Entry* entry = registry.CreateEntry(kBlob1, kType, kDisposition);
ASSERT_NE(nullptr, entry);
- EXPECT_EQ(BlobState::RESERVED, entry->state);
+ EXPECT_EQ(BlobState::PENDING, entry->state);
+ EXPECT_EQ(kType, entry->content_type);
+ EXPECT_EQ(kDisposition, entry->content_disposition);
EXPECT_EQ(1u, entry->refcount);
- EXPECT_FALSE(entry->exceeded_memory);
EXPECT_FALSE(entry->data.get() || entry->data_builder.get());
- EXPECT_EQ(0u, entry->construction_complete_callbacks.size());
+ EXPECT_EQ(0u, entry->build_completion_callbacks.size());
EXPECT_EQ(entry, registry.GetEntry(kBlob1));
EXPECT_TRUE(registry.DeleteEntry(kBlob1));
- entry = registry.CreateEntry(kBlob1);
+ entry = registry.CreateEntry(kBlob1, kType, kDisposition);
- EXPECT_TRUE(entry->TestAndSetState(BlobState::RESERVED,
- BlobState::ASYNC_TRANSPORTATION));
- EXPECT_FALSE(
- entry->TestAndSetState(BlobState::CONSTRUCTION, BlobState::RESERVED));
- EXPECT_FALSE(entry->TestAndSetState(BlobState::ACTIVE, BlobState::RESERVED));
- EXPECT_TRUE(entry->TestAndSetState(BlobState::ASYNC_TRANSPORTATION,
- BlobState::CONSTRUCTION));
- EXPECT_EQ(BlobState::CONSTRUCTION, entry->state);
EXPECT_EQ(1u, registry.blob_count());
}
TEST(BlobStorageRegistry, URLRegistration) {
const std::string kBlob = "Blob1";
+ const std::string kType = "type1";
+ const std::string kDisposition = "disp1";
const std::string kBlob2 = "Blob2";
const GURL kURL = GURL("blob://Blob1");
const GURL kURL2 = GURL("blob://Blob2");
@@ -55,7 +52,7 @@ TEST(BlobStorageRegistry, URLRegistration) {
EXPECT_FALSE(registry.DeleteURLMapping(kURL, nullptr));
EXPECT_FALSE(registry.CreateUrlMapping(kURL, kBlob));
EXPECT_EQ(0u, registry.url_count());
- Entry* entry = registry.CreateEntry(kBlob);
+ Entry* entry = registry.CreateEntry(kBlob, kType, kDisposition);
EXPECT_FALSE(registry.IsURLMapped(kURL));
EXPECT_TRUE(registry.CreateUrlMapping(kURL, kBlob));
@@ -68,7 +65,7 @@ TEST(BlobStorageRegistry, URLRegistration) {
EXPECT_EQ(kBlob, uuid);
EXPECT_EQ(1u, registry.url_count());
- registry.CreateEntry(kBlob2);
+ registry.CreateEntry(kBlob2, kType, kDisposition);
EXPECT_TRUE(registry.CreateUrlMapping(kURL2, kBlob2));
EXPECT_EQ(2u, registry.url_count());
EXPECT_TRUE(registry.DeleteURLMapping(kURL2, &uuid));
diff --git a/chromium/content/browser/bluetooth/README.md b/chromium/content/browser/bluetooth/README.md
new file mode 100644
index 00000000000..6e55bcd73b3
--- /dev/null
+++ b/chromium/content/browser/bluetooth/README.md
@@ -0,0 +1,24 @@
+Bluetooth in Content
+====================
+
+`content/*/bluetooth` implements [Web Bluetooth][WB] using the
+`device/bluetooth` code module.
+
+[WB]: https://webbluetoothcg.github.io/web-bluetooth/
+
+Testing
+--------------------------------------------------------------------------------
+
+Bluetooth layout tests in `third_party/WebKit/LayoutTests/bluetooth/` rely on
+fake Bluetooth implementation classes constructed in
+`content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider`.
+These tests span JavaScript binding to the `device/bluetooth` API layer.
+
+
+Design Documents
+--------------------------------------------------------------------------------
+
+See: [Class Diagram of Web Bluetooth through Bluetooth Android][Class]
+
+[Class]: https://sites.google.com/a/chromium.org/dev/developers/design-documents/bluetooth-design-docs/web-bluetooth-through-bluetooth-android-class-diagram
+
diff --git a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.cc b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
index 9075fe82bb3..cd2e78929a3 100644
--- a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
+++ b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
+#include "content/browser/bluetooth/bluetooth_blacklist.h"
#include "content/common/bluetooth/bluetooth_scan_filter.h"
#include "crypto/random.h"
#include "device/bluetooth/bluetooth_uuid.h"
@@ -55,18 +56,28 @@ const std::string& BluetoothAllowedDevicesMap::AddDevice(
// https://w3c.github.io/webappsec-secure-contexts/
CHECK(!origin.unique());
- if (ContainsKey(origin_to_device_address_to_id_map_[origin],
- device_address)) {
+ auto device_address_to_id_map = origin_to_device_address_to_id_map_[origin];
+ auto id_iter = device_address_to_id_map.find(device_address);
+ if (id_iter != device_address_to_id_map.end()) {
VLOG(1) << "Device already in map of allowed devices.";
+ const auto& device_id = id_iter->second;
+
+ AddUnionOfServicesTo(
+ filters, optional_services,
+ &origin_to_device_id_to_services_map_[origin][device_id]);
+
return origin_to_device_address_to_id_map_[origin][device_address];
}
- const std::string device_id = GenerateDeviceId(origin);
+ const std::string device_id = GenerateDeviceId();
VLOG(1) << "Id generated for device: " << device_id;
origin_to_device_address_to_id_map_[origin][device_address] = device_id;
origin_to_device_id_to_address_map_[origin][device_id] = device_address;
- origin_to_device_id_to_services_map_[origin][device_id] =
- UnionOfServices(filters, optional_services);
+ AddUnionOfServicesTo(
+ filters, optional_services,
+ &origin_to_device_id_to_services_map_[origin][device_id]);
+
+ CHECK(device_id_set_.insert(device_id).second);
return origin_to_device_address_to_id_map_[origin][device_address];
}
@@ -88,6 +99,9 @@ void BluetoothAllowedDevicesMap::RemoveDevice(
CHECK(origin_to_device_id_to_address_map_.erase(origin));
CHECK(origin_to_device_id_to_services_map_.erase(origin));
}
+
+ // 3. Remove from set of ids.
+ CHECK(device_id_set_.erase(device_id));
}
const std::string& BluetoothAllowedDevicesMap::GetDeviceId(
@@ -123,33 +137,48 @@ const std::string& BluetoothAllowedDevicesMap::GetDeviceAddress(
: id_iter->second;
}
-std::string BluetoothAllowedDevicesMap::GenerateDeviceId(
- const url::Origin& origin) {
- std::string device_id = GetBase64Id();
- auto id_map_iter = origin_to_device_id_to_address_map_.find(origin);
- if (id_map_iter == origin_to_device_id_to_address_map_.end()) {
- return device_id;
+bool BluetoothAllowedDevicesMap::IsOriginAllowedToAccessService(
+ const url::Origin& origin,
+ const std::string& device_id,
+ const std::string& service_uuid) const {
+ if (BluetoothBlacklist::Get().IsExcluded(BluetoothUUID(service_uuid)))
+ return false;
+
+ auto id_map_iter = origin_to_device_id_to_services_map_.find(origin);
+ if (id_map_iter == origin_to_device_id_to_services_map_.end()) {
+ return false;
}
- while (ContainsKey(id_map_iter->second, device_id)) {
+
+ const auto& device_id_to_services_map = id_map_iter->second;
+
+ auto id_iter = device_id_to_services_map.find(device_id);
+
+ return id_iter == device_id_to_services_map.end()
+ ? false
+ : ContainsKey(id_iter->second, service_uuid);
+}
+
+std::string BluetoothAllowedDevicesMap::GenerateDeviceId() {
+ std::string device_id = GetBase64Id();
+ while (ContainsKey(device_id_set_, device_id)) {
LOG(WARNING) << "Generated repeated id.";
device_id = GetBase64Id();
}
return device_id;
}
-std::set<std::string> BluetoothAllowedDevicesMap::UnionOfServices(
+void BluetoothAllowedDevicesMap::AddUnionOfServicesTo(
const std::vector<BluetoothScanFilter>& filters,
- const std::vector<BluetoothUUID>& optional_services) {
- std::set<std::string> unionOfServices;
+ const std::vector<device::BluetoothUUID>& optional_services,
+ std::set<std::string>* unionOfServices) {
for (const auto& filter : filters) {
for (const BluetoothUUID& uuid : filter.services) {
- unionOfServices.insert(uuid.canonical_value());
+ unionOfServices->insert(uuid.canonical_value());
}
}
for (const BluetoothUUID& uuid : optional_services) {
- unionOfServices.insert(uuid.canonical_value());
+ unionOfServices->insert(uuid.canonical_value());
}
- return unionOfServices;
}
} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.h b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.h
index d8672979eeb..32823593a37 100644
--- a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.h
+++ b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map.h
@@ -25,15 +25,14 @@ struct BluetoothScanFilter;
// their services.
//
// |AddDevice| generates device ids, which are random strings that are unique
-// for each (origin, device address) pair.
+// in the map.
class CONTENT_EXPORT BluetoothAllowedDevicesMap final {
public:
BluetoothAllowedDevicesMap();
~BluetoothAllowedDevicesMap();
// Adds the Bluetooth Device with |device_address| to the map of allowed
- // devices for that origin. Generates and returns a device id for the
- // (|origin|, |device_address|) pair.
+ // devices for that origin. Generates and returns a device id.
const std::string& AddDevice(
const url::Origin& origin,
const std::string& device_address,
@@ -45,12 +44,8 @@ class CONTENT_EXPORT BluetoothAllowedDevicesMap final {
void RemoveDevice(const url::Origin& origin,
const std::string& device_address);
- // TODO(ortuno): Add function to check if origin is allowed to access
- // a device's service and add tests for that function.
- // https://crbug.com/493460
-
// Returns the Bluetooth Device's id for |origin|. Returns an empty string
- // if the origin is not allowed to access the device.
+ // if |origin| is not allowed to access the device.
const std::string& GetDeviceId(const url::Origin& origin,
const std::string& device_address);
@@ -59,17 +54,24 @@ class CONTENT_EXPORT BluetoothAllowedDevicesMap final {
const std::string& GetDeviceAddress(const url::Origin& origin,
const std::string& device_id);
+ // Returns true if the origin has previously been granted access to
+ // the service.
+ bool IsOriginAllowedToAccessService(const url::Origin& origin,
+ const std::string& device_id,
+ const std::string& service_uuid) const;
+
private:
typedef std::map<std::string, std::string> DeviceAddressToIdMap;
typedef std::map<std::string, std::string> DeviceIdToAddressMap;
typedef std::map<std::string, std::set<std::string>> DeviceIdToServicesMap;
- // Returns an id guaranteed to be unique for the origin. The id is randomly
+ // Returns an id guaranteed to be unique for the map. The id is randomly
// generated so that an origin can't guess the id used in another origin.
- std::string GenerateDeviceId(const url::Origin& origin);
- std::set<std::string> UnionOfServices(
+ std::string GenerateDeviceId();
+ void AddUnionOfServicesTo(
const std::vector<BluetoothScanFilter>& filters,
- const std::vector<device::BluetoothUUID>& optional_services);
+ const std::vector<device::BluetoothUUID>& optional_services,
+ std::set<std::string>* unionOfServices);
std::map<url::Origin, DeviceAddressToIdMap>
origin_to_device_address_to_id_map_;
@@ -77,6 +79,9 @@ class CONTENT_EXPORT BluetoothAllowedDevicesMap final {
origin_to_device_id_to_address_map_;
std::map<url::Origin, DeviceIdToServicesMap>
origin_to_device_id_to_services_map_;
+
+ // Keep track of all device_ids in the map.
+ std::set<std::string> device_id_set_;
};
} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
index 2d5243a1d5f..925d1a1393f 100644
--- a/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
+++ b/chromium/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
@@ -10,153 +10,390 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using device::BluetoothUUID;
+
namespace content {
namespace {
-const url::Origin test_origin1(GURL("https://www.example1.com"));
-const url::Origin test_origin2(GURL("https://www.example2.com"));
-
-const std::string device_address1 = "00:00:00";
-const std::string device_address2 = "11:11:11";
-
-const std::vector<content::BluetoothScanFilter> filters =
+const url::Origin kTestOrigin1(GURL("https://www.example1.com"));
+const url::Origin kTestOrigin2(GURL("https://www.example2.com"));
+
+const std::string kDeviceAddress1 = "00:00:00";
+const std::string kDeviceAddress2 = "11:11:11";
+
+const char kGlucoseUUIDString[] = "00001808-0000-1000-8000-00805f9b34fb";
+const char kHeartRateUUIDString[] = "0000180d-0000-1000-8000-00805f9b34fb";
+const char kBatteryServiceUUIDString[] = "0000180f-0000-1000-8000-00805f9b34fb";
+const char kBloodPressureUUIDString[] = "00001813-0000-1000-8000-00805f9b34fb";
+const char kCyclingPowerUUIDString[] = "00001818-0000-1000-8000-00805f9b34fb";
+const BluetoothUUID kGlucoseUUID(kGlucoseUUIDString);
+const BluetoothUUID kHeartRateUUID(kHeartRateUUIDString);
+const BluetoothUUID kBatteryServiceUUID(kBatteryServiceUUIDString);
+const BluetoothUUID kBloodPressureUUID(kBloodPressureUUIDString);
+const BluetoothUUID kCyclingPowerUUID(kCyclingPowerUUIDString);
+
+const std::vector<content::BluetoothScanFilter> kEmptyFilters =
std::vector<BluetoothScanFilter>();
-const std::vector<device::BluetoothUUID> optional_services =
+const std::vector<device::BluetoothUUID> kEmptyOptionalServices =
std::vector<device::BluetoothUUID>();
} // namespace
-class BluetoothAllowedDevicesMapTest : public testing::Test {};
-
-TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMap) {
+TEST(BluetoothAllowedDevicesMapTest, AddDeviceToMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
// Test that we can retrieve the device address/id.
EXPECT_EQ(device_id,
- allowed_devices_map.GetDeviceId(test_origin1, device_address1));
- EXPECT_EQ(device_address1,
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+ EXPECT_EQ(kDeviceAddress1,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id));
}
-TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMapTwice) {
+TEST(BluetoothAllowedDevicesMapTest, AddDeviceToMapTwice) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id1 = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
const std::string& device_id2 = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
EXPECT_EQ(device_id1, device_id2);
// Test that we can retrieve the device address/id.
EXPECT_EQ(device_id1,
- allowed_devices_map.GetDeviceId(test_origin1, device_address1));
- EXPECT_EQ(device_address1,
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id1));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
+ EXPECT_EQ(kDeviceAddress1,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
}
-TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromSameOriginToMap) {
+TEST(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromSameOriginToMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id1 = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
const std::string& device_id2 = allowed_devices_map.AddDevice(
- test_origin1, device_address2, filters, optional_services);
+ kTestOrigin1, kDeviceAddress2, kEmptyFilters, kEmptyOptionalServices);
EXPECT_NE(device_id1, device_id2);
// Test that we can retrieve the device address/id.
EXPECT_EQ(device_id1,
- allowed_devices_map.GetDeviceId(test_origin1, device_address1));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
EXPECT_EQ(device_id2,
- allowed_devices_map.GetDeviceId(test_origin1, device_address2));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress2));
- EXPECT_EQ(device_address1,
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id1));
- EXPECT_EQ(device_address2,
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id2));
+ EXPECT_EQ(kDeviceAddress1,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
+ EXPECT_EQ(kDeviceAddress2,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id2));
}
-TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromTwoOriginsToMap) {
+TEST(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromTwoOriginsToMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id1 = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
const std::string& device_id2 = allowed_devices_map.AddDevice(
- test_origin2, device_address2, filters, optional_services);
+ kTestOrigin2, kDeviceAddress2, kEmptyFilters, kEmptyOptionalServices);
EXPECT_NE(device_id1, device_id2);
// Test that the wrong origin doesn't have access to the device.
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceId(test_origin1, device_address2));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress2));
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceId(test_origin2, device_address1));
+ allowed_devices_map.GetDeviceId(kTestOrigin2, kDeviceAddress1));
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id2));
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id2));
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceAddress(test_origin2, device_id1));
+ allowed_devices_map.GetDeviceAddress(kTestOrigin2, device_id1));
// Test that we can retrieve the device address/id.
EXPECT_EQ(device_id1,
- allowed_devices_map.GetDeviceId(test_origin1, device_address1));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, kDeviceAddress1));
EXPECT_EQ(device_id2,
- allowed_devices_map.GetDeviceId(test_origin2, device_address2));
+ allowed_devices_map.GetDeviceId(kTestOrigin2, kDeviceAddress2));
- EXPECT_EQ(device_address1,
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id1));
- EXPECT_EQ(device_address2,
- allowed_devices_map.GetDeviceAddress(test_origin2, device_id2));
+ EXPECT_EQ(kDeviceAddress1,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id1));
+ EXPECT_EQ(kDeviceAddress2,
+ allowed_devices_map.GetDeviceAddress(kTestOrigin2, device_id2));
}
-TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceFromTwoOriginsToMap) {
+TEST(BluetoothAllowedDevicesMapTest, AddDeviceFromTwoOriginsToMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id1 = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
const std::string& device_id2 = allowed_devices_map.AddDevice(
- test_origin2, device_address1, filters, optional_services);
+ kTestOrigin2, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
EXPECT_NE(device_id1, device_id2);
// Test that the wrong origin doesn't have access to the device.
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceAddress(test_origin1, device_id2));
+ allowed_devices_map.GetDeviceAddress(kTestOrigin1, device_id2));
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceAddress(test_origin2, device_id1));
+ allowed_devices_map.GetDeviceAddress(kTestOrigin2, device_id1));
}
-TEST_F(BluetoothAllowedDevicesMapTest, AddRemoveAddDeviceToMap) {
+TEST(BluetoothAllowedDevicesMapTest, AddRemoveAddDeviceToMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string device_id_first_time = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
- allowed_devices_map.RemoveDevice(test_origin1, device_address1);
+ allowed_devices_map.RemoveDevice(kTestOrigin1, kDeviceAddress1);
const std::string device_id_second_time = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
EXPECT_NE(device_id_first_time, device_id_second_time);
}
-TEST_F(BluetoothAllowedDevicesMapTest, RemoveDeviceFromMap) {
+TEST(BluetoothAllowedDevicesMapTest, RemoveDeviceFromMap) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
- allowed_devices_map.RemoveDevice(test_origin1, device_address1);
+ allowed_devices_map.RemoveDevice(kTestOrigin1, kDeviceAddress1);
EXPECT_EQ(base::EmptyString(),
- allowed_devices_map.GetDeviceId(test_origin1, device_id));
+ allowed_devices_map.GetDeviceId(kTestOrigin1, device_id));
EXPECT_EQ(base::EmptyString(), allowed_devices_map.GetDeviceAddress(
- test_origin1, device_address1));
+ kTestOrigin1, kDeviceAddress1));
+}
+
+TEST(BluetoothAllowedDevicesMapTest, AllowedServices_OneOriginOneDevice) {
+ BluetoothAllowedDevicesMap allowed_devices_map;
+
+ // Setup device.
+ BluetoothScanFilter scanFilter1;
+ scanFilter1.services.push_back(kGlucoseUUID);
+ BluetoothScanFilter scanFilter2;
+ scanFilter2.services.push_back(kHeartRateUUID);
+
+ std::vector<BluetoothScanFilter> filters;
+ filters.push_back(scanFilter1);
+ filters.push_back(scanFilter2);
+
+ std::vector<BluetoothUUID> optional_services;
+ optional_services.push_back(kBatteryServiceUUID);
+ optional_services.push_back(kHeartRateUUID);
+
+ // Add to map.
+ const std::string device_id1 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters, optional_services);
+
+ // Access allowed services.
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+
+ // Try to access a non-allowed service.
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBloodPressureUUIDString));
+
+ // Try to access allowed services after removing device.
+ allowed_devices_map.RemoveDevice(kTestOrigin1, kDeviceAddress1);
+
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+
+ // Add device back.
+ const std::string device_id2 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters, kEmptyOptionalServices);
+
+ // Access allowed services.
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kGlucoseUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kHeartRateUUIDString));
+
+ // Try to access a non-allowed service.
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kBatteryServiceUUIDString));
+
+ // Try to access services from old device.
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+}
+
+TEST(BluetoothAllowedDevicesMapTest, AllowedServices_OneOriginTwoDevices) {
+ BluetoothAllowedDevicesMap allowed_devices_map;
+
+ // Setup request for device #1.
+ BluetoothScanFilter scanFilter1;
+ scanFilter1.services.push_back(kGlucoseUUID);
+ std::vector<BluetoothScanFilter> filters1;
+ filters1.push_back(scanFilter1);
+
+ std::vector<BluetoothUUID> optional_services1;
+ optional_services1.push_back(kHeartRateUUID);
+
+ // Setup request for device #2.
+ BluetoothScanFilter scanFilter2;
+ scanFilter2.services.push_back(kBatteryServiceUUID);
+ std::vector<BluetoothScanFilter> filters2;
+ filters2.push_back(scanFilter2);
+
+ std::vector<BluetoothUUID> optional_services2;
+ optional_services2.push_back(kBloodPressureUUID);
+
+ // Add devices to map.
+ const std::string& device_id1 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters1, optional_services1);
+ const std::string& device_id2 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress2, filters2, optional_services2);
+
+ // Access allowed services.
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kBatteryServiceUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kBloodPressureUUIDString));
+
+ // Try to access non-allowed services.
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBloodPressureUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kCyclingPowerUUIDString));
+
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kHeartRateUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kCyclingPowerUUIDString));
+}
+
+TEST(BluetoothAllowedDevicesMapTest, AllowedServices_TwoOriginsOneDevice) {
+ BluetoothAllowedDevicesMap allowed_devices_map;
+ // Setup request #1 for device.
+ BluetoothScanFilter scanFilter1;
+ scanFilter1.services.push_back(kGlucoseUUID);
+ std::vector<BluetoothScanFilter> filters1;
+ filters1.push_back(scanFilter1);
+
+ std::vector<BluetoothUUID> optional_services1;
+ optional_services1.push_back(kHeartRateUUID);
+
+ // Setup request #2 for device.
+ BluetoothScanFilter scanFilter2;
+ scanFilter2.services.push_back(kBatteryServiceUUID);
+ std::vector<BluetoothScanFilter> filters2;
+ filters2.push_back(scanFilter2);
+
+ std::vector<BluetoothUUID> optional_services2;
+ optional_services2.push_back(kBloodPressureUUID);
+
+ // Add devices to map.
+ const std::string& device_id1 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters1, optional_services1);
+ const std::string& device_id2 = allowed_devices_map.AddDevice(
+ kTestOrigin2, kDeviceAddress1, filters2, optional_services2);
+
+ // Access allowed services.
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id2, kBatteryServiceUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id2, kBloodPressureUUIDString));
+
+ // Try to access non-allowed services.
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBloodPressureUUIDString));
+
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kHeartRateUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kBatteryServiceUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id2, kBloodPressureUUIDString));
+
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id2, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id2, kHeartRateUUIDString));
+
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id1, kGlucoseUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id1, kHeartRateUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id1, kBatteryServiceUUIDString));
+ EXPECT_FALSE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin2, device_id1, kBloodPressureUUIDString));
+}
+
+TEST(BluetoothAllowedDevicesMapTest, MergeServices) {
+ BluetoothAllowedDevicesMap allowed_devices_map;
+
+ // Setup first request.
+ BluetoothScanFilter scanFilter1;
+ scanFilter1.services.push_back(kGlucoseUUID);
+ std::vector<BluetoothScanFilter> filters1;
+ filters1.push_back(scanFilter1);
+ std::vector<BluetoothUUID> optional_services1;
+ optional_services1.push_back(kBatteryServiceUUID);
+
+ // Add to map.
+ const std::string device_id1 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters1, optional_services1);
+
+ // Setup second request.
+ BluetoothScanFilter scanFilter2;
+ scanFilter2.services.push_back(kHeartRateUUID);
+ std::vector<BluetoothScanFilter> filters2;
+ filters2.push_back(scanFilter2);
+ std::vector<BluetoothUUID> optional_services2;
+ optional_services2.push_back(kBloodPressureUUID);
+
+ // Add to map again.
+ const std::string device_id2 = allowed_devices_map.AddDevice(
+ kTestOrigin1, kDeviceAddress1, filters2, optional_services2);
+
+ EXPECT_EQ(device_id1, device_id2);
+
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kGlucoseUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBatteryServiceUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kHeartRateUUIDString));
+ EXPECT_TRUE(allowed_devices_map.IsOriginAllowedToAccessService(
+ kTestOrigin1, device_id1, kBloodPressureUUIDString));
}
-TEST_F(BluetoothAllowedDevicesMapTest, CorrectIdFormat) {
+TEST(BluetoothAllowedDevicesMapTest, CorrectIdFormat) {
BluetoothAllowedDevicesMap allowed_devices_map;
const std::string& device_id = allowed_devices_map.AddDevice(
- test_origin1, device_address1, filters, optional_services);
+ kTestOrigin1, kDeviceAddress1, kEmptyFilters, kEmptyOptionalServices);
EXPECT_TRUE(device_id.size() == 24)
<< "Expected Lenghth of a 128bit string encoded to Base64.";
diff --git a/chromium/content/browser/bluetooth/bluetooth_blacklist.cc b/chromium/content/browser/bluetooth/bluetooth_blacklist.cc
new file mode 100644
index 00000000000..c9edc5e3806
--- /dev/null
+++ b/chromium/content/browser/bluetooth/bluetooth_blacklist.cc
@@ -0,0 +1,185 @@
+// 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 "content/browser/bluetooth/bluetooth_blacklist.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_split.h"
+#include "content/common/bluetooth/bluetooth_scan_filter.h"
+#include "content/public/browser/content_browser_client.h"
+
+using device::BluetoothUUID;
+
+namespace {
+
+static base::LazyInstance<content::BluetoothBlacklist>::Leaky g_singleton =
+ LAZY_INSTANCE_INITIALIZER;
+
+void RecordUMAParsedNonEmptyString(bool success) {
+ UMA_HISTOGRAM_BOOLEAN("Bluetooth.Web.Blacklist.ParsedNonEmptyString",
+ success);
+}
+
+} // namespace
+
+namespace content {
+
+BluetoothBlacklist::~BluetoothBlacklist() {}
+
+// static
+BluetoothBlacklist& BluetoothBlacklist::Get() {
+ return g_singleton.Get();
+}
+
+void BluetoothBlacklist::Add(const device::BluetoothUUID& uuid, Value value) {
+ CHECK(uuid.IsValid());
+ auto insert_result = blacklisted_uuids_.insert(std::make_pair(uuid, value));
+ bool inserted = insert_result.second;
+ if (!inserted) {
+ Value& stored = insert_result.first->second;
+ if (stored != value)
+ stored = Value::EXCLUDE;
+ }
+}
+
+void BluetoothBlacklist::Add(base::StringPiece blacklist_string) {
+ if (blacklist_string.empty())
+ return;
+ base::StringPairs kv_pairs;
+ bool parsed_values = false;
+ bool invalid_values = false;
+ SplitStringIntoKeyValuePairs(blacklist_string,
+ ':', // Key-value delimiter
+ ',', // Key-value pair delimiter
+ &kv_pairs);
+ for (const auto& pair : kv_pairs) {
+ BluetoothUUID uuid(pair.first);
+ if (uuid.IsValid() && pair.second.size() == 1u) {
+ switch (pair.second[0]) {
+ case 'e':
+ Add(uuid, Value::EXCLUDE);
+ parsed_values = true;
+ continue;
+ case 'r':
+ Add(uuid, Value::EXCLUDE_READS);
+ parsed_values = true;
+ continue;
+ case 'w':
+ Add(uuid, Value::EXCLUDE_WRITES);
+ parsed_values = true;
+ continue;
+ }
+ }
+ invalid_values = true;
+ }
+ RecordUMAParsedNonEmptyString(parsed_values && !invalid_values);
+}
+
+bool BluetoothBlacklist::IsExcluded(const BluetoothUUID& uuid) const {
+ CHECK(uuid.IsValid());
+ const auto& it = blacklisted_uuids_.find(uuid);
+ if (it == blacklisted_uuids_.end())
+ return false;
+ return it->second == Value::EXCLUDE;
+}
+
+bool BluetoothBlacklist::IsExcluded(
+ const std::vector<content::BluetoothScanFilter>& filters) {
+ for (const BluetoothScanFilter& filter : filters) {
+ for (const BluetoothUUID& service : filter.services) {
+ if (IsExcluded(service)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BluetoothBlacklist::IsExcludedFromReads(const BluetoothUUID& uuid) const {
+ CHECK(uuid.IsValid());
+ const auto& it = blacklisted_uuids_.find(uuid);
+ if (it == blacklisted_uuids_.end())
+ return false;
+ return it->second == Value::EXCLUDE || it->second == Value::EXCLUDE_READS;
+}
+
+bool BluetoothBlacklist::IsExcludedFromWrites(const BluetoothUUID& uuid) const {
+ CHECK(uuid.IsValid());
+ const auto& it = blacklisted_uuids_.find(uuid);
+ if (it == blacklisted_uuids_.end())
+ return false;
+ return it->second == Value::EXCLUDE || it->second == Value::EXCLUDE_WRITES;
+}
+
+void BluetoothBlacklist::RemoveExcludedUuids(
+ std::vector<device::BluetoothUUID>* uuids) {
+ auto it = uuids->begin();
+ while (it != uuids->end()) {
+ if (IsExcluded(*it)) {
+ it = uuids->erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+void BluetoothBlacklist::ResetToDefaultValuesForTest() {
+ blacklisted_uuids_.clear();
+ PopulateWithDefaultValues();
+ PopulateWithServerProvidedValues();
+}
+
+BluetoothBlacklist::BluetoothBlacklist() {
+ PopulateWithDefaultValues();
+ PopulateWithServerProvidedValues();
+}
+
+void BluetoothBlacklist::PopulateWithDefaultValues() {
+ blacklisted_uuids_.clear();
+
+ // Testing from Layout Tests Note:
+ //
+ // Random UUIDs for object & exclude permutations that do not exist in the
+ // standard blacklist are included to facilitate integration testing from
+ // Layout Tests. Unit tests can dynamically modify the blacklist, but don't
+ // offer the full integration test to the Web Bluetooth Javascript bindings.
+ //
+ // This is done for simplicity as opposed to exposing a testing API that can
+ // add to the blacklist over time, which would be over engineered.
+ //
+ // Remove testing UUIDs if the specified blacklist is updated to include UUIDs
+ // that match the specific permutations.
+ DCHECK(BluetoothUUID("00001800-0000-1000-8000-00805f9b34fb") ==
+ BluetoothUUID("1800"));
+
+ // Blacklist UUIDs updated 2016-04-07 from:
+ // https://github.com/WebBluetoothCG/registries/blob/master/gatt_blacklist.txt
+ // Short UUIDs are used for readability of this list.
+ //
+ // Services:
+ Add(BluetoothUUID("1812"), Value::EXCLUDE);
+ Add(BluetoothUUID("00001530-1212-efde-1523-785feabcd123"), Value::EXCLUDE);
+ Add(BluetoothUUID("f000ffc0-0451-4000-b000-000000000000"), Value::EXCLUDE);
+ // Characteristics:
+ Add(BluetoothUUID("2a02"), Value::EXCLUDE_WRITES);
+ Add(BluetoothUUID("2a03"), Value::EXCLUDE);
+ Add(BluetoothUUID("2a25"), Value::EXCLUDE);
+ // Characteristics for Layout Tests:
+ Add(BluetoothUUID("bad1c9a2-9a5b-4015-8b60-1579bbbf2135"),
+ Value::EXCLUDE_READS);
+ // Descriptors:
+ Add(BluetoothUUID("2902"), Value::EXCLUDE_WRITES);
+ Add(BluetoothUUID("2903"), Value::EXCLUDE_WRITES);
+ // Descriptors for Layout Tests:
+ Add(BluetoothUUID("bad2ddcf-60db-45cd-bef9-fd72b153cf7c"), Value::EXCLUDE);
+ Add(BluetoothUUID("bad3ec61-3cc3-4954-9702-7977df514114"),
+ Value::EXCLUDE_READS);
+}
+
+void BluetoothBlacklist::PopulateWithServerProvidedValues() {
+ Add(GetContentClient()->browser()->GetWebBluetoothBlacklist());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_blacklist.h b/chromium/content/browser/bluetooth/bluetooth_blacklist.h
new file mode 100644
index 00000000000..d363d86cfb9
--- /dev/null
+++ b/chromium/content/browser/bluetooth/bluetooth_blacklist.h
@@ -0,0 +1,104 @@
+// 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 CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_BLACKLIST_H_
+#define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_BLACKLIST_H_
+
+#include <map>
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "content/common/content_export.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace content {
+
+struct BluetoothScanFilter;
+
+// Implements the Web Bluetooth Blacklist policy as defined in the Web Bluetooth
+// specification:
+// https://webbluetoothcg.github.io/web-bluetooth/#the-gatt-blacklist
+//
+// Client code may query UUIDs to determine if they are excluded from use by the
+// blacklist.
+//
+// Singleton access via Get() enforces only one copy of blacklist.
+class CONTENT_EXPORT BluetoothBlacklist final {
+ public:
+ // Blacklist value terminology from Web Bluetooth specification:
+ // https://webbluetoothcg.github.io/web-bluetooth/#the-gatt-blacklist
+ enum class Value {
+ EXCLUDE, // Implies EXCLUDE_READS and EXCLUDE_WRITES.
+ EXCLUDE_READS, // Excluded from read operations.
+ EXCLUDE_WRITES // Excluded from write operations.
+ };
+
+ ~BluetoothBlacklist();
+
+ // Returns a singleton instance of the blacklist.
+ static BluetoothBlacklist& Get();
+
+ // Adds a UUID to the blacklist to be excluded from operations, merging with
+ // any previous value and resulting in the strictest exclusion rule from the
+ // combination of the two, E.G.:
+ // Add(uuid, EXCLUDE_READS);
+ // Add(uuid, EXCLUDE_WRITES);
+ // IsExcluded(uuid); // true.
+ // Requires UUID to be valid.
+ void Add(const device::BluetoothUUID&, Value);
+
+ // Adds UUIDs to the blacklist by parsing a blacklist string and calling
+ // Add(uuid, value).
+ //
+ // The blacklist string format is defined at
+ // ContentBrowserClient::GetWebBluetoothBlacklist().
+ //
+ // Malformed pairs in the string are ignored, including invalid UUID or
+ // exclusion values. Duplicate UUIDs follow Add()'s merging rule.
+ void Add(base::StringPiece blacklist_string);
+
+ // Returns if a UUID is excluded from all operations. UUID must be valid.
+ bool IsExcluded(const device::BluetoothUUID&) const;
+
+ // Returns if any UUID in a set of filters is excluded from all operations.
+ // UUID must be valid.
+ bool IsExcluded(const std::vector<content::BluetoothScanFilter>&);
+
+ // Returns if a UUID is excluded from read operations. UUID must be valid.
+ bool IsExcludedFromReads(const device::BluetoothUUID&) const;
+
+ // Returns if a UUID is excluded from write operations. UUID must be valid.
+ bool IsExcludedFromWrites(const device::BluetoothUUID&) const;
+
+ // Modifies a list of UUIDs, removing any UUIDs with Value::EXCLUDE.
+ void RemoveExcludedUuids(std::vector<device::BluetoothUUID>*);
+
+ // Size of blacklist.
+ size_t size() { return blacklisted_uuids_.size(); }
+
+ void ResetToDefaultValuesForTest();
+
+ private:
+ // friend LazyInstance to permit access to private constructor.
+ friend base::DefaultLazyInstanceTraits<BluetoothBlacklist>;
+
+ BluetoothBlacklist();
+
+ void PopulateWithDefaultValues();
+
+ // Populates blacklist with values obtained dynamically from a server, able
+ // to be updated without shipping new executable versions.
+ void PopulateWithServerProvidedValues();
+
+ // Map of UUID to blacklisted value.
+ std::map<device::BluetoothUUID, Value> blacklisted_uuids_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothBlacklist);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_BLACKLIST_H_
diff --git a/chromium/content/browser/bluetooth/bluetooth_blacklist_unittest.cc b/chromium/content/browser/bluetooth/bluetooth_blacklist_unittest.cc
new file mode 100644
index 00000000000..b0ed9c2c6a1
--- /dev/null
+++ b/chromium/content/browser/bluetooth/bluetooth_blacklist_unittest.cc
@@ -0,0 +1,398 @@
+// 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 "content/browser/bluetooth/bluetooth_blacklist.h"
+
+#include "content/common/bluetooth/bluetooth_scan_filter.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothUUID;
+
+namespace content {
+
+class BluetoothBlacklistTest : public ::testing::Test {
+ public:
+ BluetoothBlacklistTest() : list_(BluetoothBlacklist::Get()) {
+ // Because BluetoothBlacklist is used via a singleton instance, the data
+ // must be reset for each test.
+ list_.ResetToDefaultValuesForTest();
+ }
+ BluetoothBlacklist& list_;
+};
+
+TEST_F(BluetoothBlacklistTest, NonExcludedUUID) {
+ BluetoothUUID non_excluded_uuid("00000000-0000-0000-0000-000000000000");
+ EXPECT_FALSE(list_.IsExcluded(non_excluded_uuid));
+ EXPECT_FALSE(list_.IsExcludedFromReads(non_excluded_uuid));
+ EXPECT_FALSE(list_.IsExcludedFromWrites(non_excluded_uuid));
+}
+
+TEST_F(BluetoothBlacklistTest, ExcludeUUID) {
+ BluetoothUUID excluded_uuid("eeee");
+ list_.Add(excluded_uuid, BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(list_.IsExcluded(excluded_uuid));
+ EXPECT_TRUE(list_.IsExcludedFromReads(excluded_uuid));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(excluded_uuid));
+}
+
+TEST_F(BluetoothBlacklistTest, ExcludeReadsUUID) {
+ BluetoothUUID exclude_reads_uuid("eeee");
+ list_.Add(exclude_reads_uuid, BluetoothBlacklist::Value::EXCLUDE_READS);
+ EXPECT_FALSE(list_.IsExcluded(exclude_reads_uuid));
+ EXPECT_TRUE(list_.IsExcludedFromReads(exclude_reads_uuid));
+ EXPECT_FALSE(list_.IsExcludedFromWrites(exclude_reads_uuid));
+}
+
+TEST_F(BluetoothBlacklistTest, ExcludeWritesUUID) {
+ BluetoothUUID exclude_writes_uuid("eeee");
+ list_.Add(exclude_writes_uuid, BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ EXPECT_FALSE(list_.IsExcluded(exclude_writes_uuid));
+ EXPECT_FALSE(list_.IsExcludedFromReads(exclude_writes_uuid));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(exclude_writes_uuid));
+}
+
+TEST_F(BluetoothBlacklistTest, InvalidUUID) {
+ BluetoothUUID empty_string_uuid("");
+ EXPECT_DEATH_IF_SUPPORTED(
+ list_.Add(empty_string_uuid, BluetoothBlacklist::Value::EXCLUDE), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcluded(empty_string_uuid), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcludedFromReads(empty_string_uuid), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcludedFromWrites(empty_string_uuid), "");
+
+ BluetoothUUID invalid_string_uuid("Not a valid UUID string.");
+ EXPECT_DEATH_IF_SUPPORTED(
+ list_.Add(invalid_string_uuid, BluetoothBlacklist::Value::EXCLUDE), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcluded(invalid_string_uuid), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcludedFromReads(invalid_string_uuid), "");
+ EXPECT_DEATH_IF_SUPPORTED(list_.IsExcludedFromWrites(invalid_string_uuid),
+ "");
+}
+
+// Abreviated UUIDs used to create, or test against, the blacklist work
+// correctly compared to full UUIDs.
+TEST_F(BluetoothBlacklistTest, AbreviatedUUIDs) {
+ list_.Add(BluetoothUUID("aaaa"), BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(
+ list_.IsExcluded(BluetoothUUID("0000aaaa-0000-1000-8000-00805f9b34fb")));
+
+ list_.Add(BluetoothUUID("0000bbbb-0000-1000-8000-00805f9b34fb"),
+ BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("bbbb")));
+}
+
+// Tests permutations of previous values and then Add() with a new value,
+// requiring result to be strictest result of the combination.
+TEST_F(BluetoothBlacklistTest, Add_MergingExcludeValues) {
+ list_.Add(BluetoothUUID("ee01"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("ee01"), BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee01")));
+
+ list_.Add(BluetoothUUID("ee02"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("ee02"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee02")));
+
+ list_.Add(BluetoothUUID("ee03"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("ee03"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee03")));
+
+ list_.Add(BluetoothUUID("ee04"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ list_.Add(BluetoothUUID("ee04"), BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee04")));
+
+ list_.Add(BluetoothUUID("ee05"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ list_.Add(BluetoothUUID("ee05"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("ee05")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("ee05")));
+
+ list_.Add(BluetoothUUID("ee06"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ list_.Add(BluetoothUUID("ee06"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee06")));
+
+ list_.Add(BluetoothUUID("ee07"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ list_.Add(BluetoothUUID("ee07"), BluetoothBlacklist::Value::EXCLUDE);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee07")));
+
+ list_.Add(BluetoothUUID("ee08"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ list_.Add(BluetoothUUID("ee08"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("ee08")));
+
+ list_.Add(BluetoothUUID("ee09"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ list_.Add(BluetoothUUID("ee09"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("ee09")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("ee09")));
+}
+
+// Tests Add() with string that contains many UUID:exclusion value pairs,
+// checking that the correct blacklist entries are created for them.
+TEST_F(BluetoothBlacklistTest, Add_StringWithValidEntries) {
+ list_.Add(
+ "0001:e,0002:r,0003:w, " // Single items.
+ "0004:r,0004:r, " // Duplicate items.
+ "0005:r,0005:w, " // Items that merge.
+ "00000006:e, " // 8 char UUID.
+ "00000007-0000-1000-8000-00805f9b34fb:e");
+
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0001")));
+
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("0002")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("0002")));
+
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("0003")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("0003")));
+
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("0004")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("0004")));
+
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0005")));
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0006")));
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0007")));
+}
+
+// Tests Add() with strings that contain no valid UUID:exclusion value.
+TEST_F(BluetoothBlacklistTest, Add_StringsWithNoValidEntries) {
+ size_t previous_list_size = list_.size();
+ list_.Add("");
+ list_.Add("~!@#$%^&*()-_=+[]{}/*-");
+ list_.Add(":");
+ list_.Add(",");
+ list_.Add(",,");
+ list_.Add(",:,");
+ list_.Add("1234:");
+ list_.Add("1234:q");
+ list_.Add("1234:E");
+ list_.Add("1234:R");
+ list_.Add("1234:W");
+ list_.Add("1234:ee");
+ list_.Add("1234 :e");
+ list_.Add("1234: e");
+ list_.Add("1:e");
+ list_.Add("1:r");
+ list_.Add("1:w");
+ list_.Add("00001800-0000-1000-8000-00805f9b34fb:ee");
+ list_.Add("z0001800-0000-1000-8000-00805f9b34fb:e");
+ list_.Add("☯");
+ EXPECT_EQ(previous_list_size, list_.size());
+}
+
+// Tests Add() with strings that contain exactly one valid UUID:exclusion value
+// pair, and optionally other issues in the string that are ignored.
+TEST_F(BluetoothBlacklistTest, Add_StringsWithOneValidEntry) {
+ size_t previous_list_size = list_.size();
+ list_.Add("0001:e");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0001")));
+
+ list_.Add("00000002:e");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0002")));
+
+ list_.Add("00000003-0000-1000-8000-00805f9b34fb:e");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0003")));
+
+ list_.Add(" 0004:e ");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0004")));
+
+ list_.Add(", 0005:e ,");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0005")));
+
+ list_.Add(":, 0006:e ,,no");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0006")));
+
+ list_.Add("0007:, 0008:e");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0008")));
+
+ list_.Add("\r\n0009:e\n\r");
+ EXPECT_EQ(++previous_list_size, list_.size());
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("0009")));
+}
+
+TEST_F(BluetoothBlacklistTest, IsExcluded_BluetoothScanFilter_ReturnsFalse) {
+ list_.Add(BluetoothUUID("eeee"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("ee01"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ list_.Add(BluetoothUUID("ee02"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ {
+ std::vector<BluetoothScanFilter> empty_filters;
+ EXPECT_FALSE(list_.IsExcluded(empty_filters));
+ }
+ {
+ std::vector<BluetoothScanFilter> single_empty_filter(1);
+ EXPECT_EQ(0u, single_empty_filter[0].services.size());
+ EXPECT_FALSE(list_.IsExcluded(single_empty_filter));
+ }
+ {
+ std::vector<BluetoothScanFilter> single_non_matching_filter(1);
+ single_non_matching_filter[0].services.push_back(BluetoothUUID("0000"));
+ EXPECT_FALSE(list_.IsExcluded(single_non_matching_filter));
+ }
+ {
+ std::vector<BluetoothScanFilter> multiple_non_matching_filter(2);
+ multiple_non_matching_filter[0].services.push_back(BluetoothUUID("0000"));
+ multiple_non_matching_filter[0].services.push_back(BluetoothUUID("ee01"));
+ multiple_non_matching_filter[1].services.push_back(BluetoothUUID("ee02"));
+ multiple_non_matching_filter[1].services.push_back(BluetoothUUID("0003"));
+ EXPECT_FALSE(list_.IsExcluded(multiple_non_matching_filter));
+ }
+}
+
+TEST_F(BluetoothBlacklistTest, IsExcluded_BluetoothScanFilter_ReturnsTrue) {
+ list_.Add(BluetoothUUID("eeee"), BluetoothBlacklist::Value::EXCLUDE);
+ {
+ std::vector<BluetoothScanFilter> single_matching_filter(1);
+ single_matching_filter[0].services.push_back(BluetoothUUID("eeee"));
+ EXPECT_TRUE(list_.IsExcluded(single_matching_filter));
+ }
+ {
+ std::vector<BluetoothScanFilter> first_matching_filter(2);
+ first_matching_filter[0].services.push_back(BluetoothUUID("eeee"));
+ first_matching_filter[0].services.push_back(BluetoothUUID("0001"));
+ first_matching_filter[1].services.push_back(BluetoothUUID("0002"));
+ first_matching_filter[1].services.push_back(BluetoothUUID("0003"));
+ EXPECT_TRUE(list_.IsExcluded(first_matching_filter));
+ }
+ {
+ std::vector<BluetoothScanFilter> last_matching_filter(2);
+ last_matching_filter[0].services.push_back(BluetoothUUID("0001"));
+ last_matching_filter[0].services.push_back(BluetoothUUID("0001"));
+ last_matching_filter[1].services.push_back(BluetoothUUID("0002"));
+ last_matching_filter[1].services.push_back(BluetoothUUID("eeee"));
+ EXPECT_TRUE(list_.IsExcluded(last_matching_filter));
+ }
+ {
+ std::vector<BluetoothScanFilter> multiple_matching_filter(2);
+ multiple_matching_filter[0].services.push_back(BluetoothUUID("eeee"));
+ multiple_matching_filter[0].services.push_back(BluetoothUUID("eeee"));
+ multiple_matching_filter[1].services.push_back(BluetoothUUID("eeee"));
+ multiple_matching_filter[1].services.push_back(BluetoothUUID("eeee"));
+ EXPECT_TRUE(list_.IsExcluded(multiple_matching_filter));
+ }
+}
+
+TEST_F(BluetoothBlacklistTest, RemoveExcludedUuids_NonMatching) {
+ list_.Add(BluetoothUUID("eeee"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("ee01"), BluetoothBlacklist::Value::EXCLUDE_READS);
+ list_.Add(BluetoothUUID("ee02"), BluetoothBlacklist::Value::EXCLUDE_WRITES);
+ {
+ std::vector<BluetoothUUID> empty;
+ std::vector<BluetoothUUID> expected_empty;
+ list_.RemoveExcludedUuids(&empty);
+ EXPECT_EQ(expected_empty, empty);
+ }
+ {
+ std::vector<BluetoothUUID> single_non_matching;
+ single_non_matching.push_back(BluetoothUUID("0000"));
+
+ std::vector<BluetoothUUID> expected_copy(single_non_matching);
+
+ list_.RemoveExcludedUuids(&single_non_matching);
+ EXPECT_EQ(expected_copy, single_non_matching);
+ }
+ {
+ std::vector<BluetoothUUID> multiple_non_matching;
+ multiple_non_matching.push_back(BluetoothUUID("0000"));
+ multiple_non_matching.push_back(BluetoothUUID("ee01"));
+ multiple_non_matching.push_back(BluetoothUUID("ee02"));
+ multiple_non_matching.push_back(BluetoothUUID("0003"));
+
+ std::vector<BluetoothUUID> expected_copy(multiple_non_matching);
+
+ list_.RemoveExcludedUuids(&multiple_non_matching);
+ EXPECT_EQ(expected_copy, multiple_non_matching);
+ }
+}
+
+TEST_F(BluetoothBlacklistTest, RemoveExcludedUuids_Matching) {
+ list_.Add(BluetoothUUID("eeee"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("eee2"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("eee3"), BluetoothBlacklist::Value::EXCLUDE);
+ list_.Add(BluetoothUUID("eee4"), BluetoothBlacklist::Value::EXCLUDE);
+ {
+ std::vector<BluetoothUUID> single_matching;
+ single_matching.push_back(BluetoothUUID("eeee"));
+
+ std::vector<BluetoothUUID> expected_empty;
+
+ list_.RemoveExcludedUuids(&single_matching);
+ EXPECT_EQ(expected_empty, single_matching);
+ }
+ {
+ std::vector<BluetoothUUID> single_matching_of_many;
+ single_matching_of_many.push_back(BluetoothUUID("0000"));
+ single_matching_of_many.push_back(BluetoothUUID("eeee"));
+ single_matching_of_many.push_back(BluetoothUUID("0001"));
+
+ std::vector<BluetoothUUID> expected;
+ expected.push_back(BluetoothUUID("0000"));
+ expected.push_back(BluetoothUUID("0001"));
+
+ list_.RemoveExcludedUuids(&single_matching_of_many);
+ EXPECT_EQ(expected, single_matching_of_many);
+ }
+ {
+ std::vector<BluetoothUUID> all_matching_of_many;
+ all_matching_of_many.push_back(BluetoothUUID("eee2"));
+ all_matching_of_many.push_back(BluetoothUUID("eee4"));
+ all_matching_of_many.push_back(BluetoothUUID("eee3"));
+ all_matching_of_many.push_back(BluetoothUUID("eeee"));
+
+ std::vector<BluetoothUUID> expected_empty;
+
+ list_.RemoveExcludedUuids(&all_matching_of_many);
+ EXPECT_EQ(expected_empty, all_matching_of_many);
+ }
+}
+
+TEST_F(BluetoothBlacklistTest, VerifyDefaultBlacklistSize) {
+ // When adding items to the blacklist the new values should be added in the
+ // tests below for each exclusion type.
+ EXPECT_EQ(11u, list_.size());
+}
+
+TEST_F(BluetoothBlacklistTest, VerifyDefaultExcludeList) {
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("1800")));
+ EXPECT_FALSE(list_.IsExcluded(BluetoothUUID("1801")));
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("1812")));
+ EXPECT_TRUE(
+ list_.IsExcluded(BluetoothUUID("00001530-1212-efde-1523-785feabcd123")));
+ EXPECT_TRUE(
+ list_.IsExcluded(BluetoothUUID("f000ffc0-0451-4000-b000-000000000000")));
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("2a03")));
+ EXPECT_TRUE(list_.IsExcluded(BluetoothUUID("2a25")));
+ EXPECT_TRUE(
+ list_.IsExcluded(BluetoothUUID("bad2ddcf-60db-45cd-bef9-fd72b153cf7c")));
+}
+
+TEST_F(BluetoothBlacklistTest, VerifyDefaultExcludeReadList) {
+ EXPECT_FALSE(list_.IsExcludedFromReads(BluetoothUUID("1800")));
+ EXPECT_FALSE(list_.IsExcludedFromReads(BluetoothUUID("1801")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("1812")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("2a03")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(BluetoothUUID("2a25")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(
+ BluetoothUUID("bad1c9a2-9a5b-4015-8b60-1579bbbf2135")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(
+ BluetoothUUID("bad2ddcf-60db-45cd-bef9-fd72b153cf7c")));
+ EXPECT_TRUE(list_.IsExcludedFromReads(
+ BluetoothUUID("bad3ec61-3cc3-4954-9702-7977df514114")));
+}
+
+TEST_F(BluetoothBlacklistTest, VerifyDefaultExcludeWriteList) {
+ EXPECT_FALSE(list_.IsExcludedFromWrites(BluetoothUUID("1800")));
+ EXPECT_FALSE(list_.IsExcludedFromWrites(BluetoothUUID("1801")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("1812")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a02")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a03")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2a25")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2902")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(BluetoothUUID("2903")));
+ EXPECT_TRUE(list_.IsExcludedFromWrites(
+ BluetoothUUID("bad2ddcf-60db-45cd-bef9-fd72b153cf7c")));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index 85bf81e0003..f8444caec79 100644
--- a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -20,10 +20,11 @@
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/bad_message.h"
-#include "content/browser/bluetooth/bluetooth_metrics.h"
+#include "content/browser/bluetooth/bluetooth_blacklist.h"
#include "content/browser/bluetooth/first_device_bluetooth_chooser.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/common/bluetooth/bluetooth_messages.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "device/bluetooth/bluetooth_adapter.h"
@@ -116,94 +117,94 @@ WebBluetoothError TranslateConnectError(
switch (error_code) {
case device::BluetoothDevice::ERROR_UNKNOWN:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::UNKNOWN);
- return WebBluetoothError::ConnectUnknownError;
+ return WebBluetoothError::CONNECT_UNKNOWN_ERROR;
case device::BluetoothDevice::ERROR_INPROGRESS:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::IN_PROGRESS);
- return WebBluetoothError::ConnectAlreadyInProgress;
+ return WebBluetoothError::CONNECT_ALREADY_IN_PROGRESS;
case device::BluetoothDevice::ERROR_FAILED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::FAILED);
- return WebBluetoothError::ConnectUnknownFailure;
+ return WebBluetoothError::CONNECT_UNKNOWN_FAILURE;
case device::BluetoothDevice::ERROR_AUTH_FAILED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_FAILED);
- return WebBluetoothError::ConnectAuthFailed;
+ return WebBluetoothError::CONNECT_AUTH_FAILED;
case device::BluetoothDevice::ERROR_AUTH_CANCELED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_CANCELED);
- return WebBluetoothError::ConnectAuthCanceled;
+ return WebBluetoothError::CONNECT_AUTH_CANCELED;
case device::BluetoothDevice::ERROR_AUTH_REJECTED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_REJECTED);
- return WebBluetoothError::ConnectAuthRejected;
+ return WebBluetoothError::CONNECT_AUTH_REJECTED;
case device::BluetoothDevice::ERROR_AUTH_TIMEOUT:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_TIMEOUT);
- return WebBluetoothError::ConnectAuthTimeout;
+ return WebBluetoothError::CONNECT_AUTH_TIMEOUT;
case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::UNSUPPORTED_DEVICE);
- return WebBluetoothError::ConnectUnsupportedDevice;
+ return WebBluetoothError::CONNECT_UNSUPPORTED_DEVICE;
case device::BluetoothDevice::ERROR_ATTRIBUTE_LENGTH_INVALID:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::ATTRIBUTE_LENGTH_INVALID);
- return WebBluetoothError::ConnectAttributeLengthInvalid;
+ return WebBluetoothError::CONNECT_ATTRIBUTE_LENGTH_INVALID;
case device::BluetoothDevice::ERROR_CONNECTION_CONGESTED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::CONNECTION_CONGESTED);
- return WebBluetoothError::ConnectConnectionCongested;
+ return WebBluetoothError::CONNECT_CONNECTION_CONGESTED;
case device::BluetoothDevice::ERROR_INSUFFICIENT_ENCRYPTION:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::INSUFFICIENT_ENCRYPTION);
- return WebBluetoothError::ConnectInsufficientEncryption;
+ return WebBluetoothError::CONNECT_INSUFFICIENT_ENCRYPTION;
case device::BluetoothDevice::ERROR_OFFSET_INVALID:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::OFFSET_INVALID);
- return WebBluetoothError::ConnectOffsetInvalid;
+ return WebBluetoothError::CONNECT_OFFSET_INVALID;
case device::BluetoothDevice::ERROR_READ_NOT_PERMITTED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::READ_NOT_PERMITTED);
- return WebBluetoothError::ConnectReadNotPermitted;
+ return WebBluetoothError::CONNECT_READ_NOT_PERMITTED;
case device::BluetoothDevice::ERROR_REQUEST_NOT_SUPPORTED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::REQUEST_NOT_SUPPORTED);
- return WebBluetoothError::ConnectRequestNotSupported;
+ return WebBluetoothError::CONNECT_REQUEST_NOT_SUPPORTED;
case device::BluetoothDevice::ERROR_WRITE_NOT_PERMITTED:
RecordConnectGATTOutcome(UMAConnectGATTOutcome::WRITE_NOT_PERMITTED);
- return WebBluetoothError::ConnectWriteNotPermitted;
+ return WebBluetoothError::CONNECT_WRITE_NOT_PERMITTED;
case device::BluetoothDevice::NUM_CONNECT_ERROR_CODES:
NOTREACHED();
- return WebBluetoothError::UntranslatedConnectErrorCode;
+ return WebBluetoothError::UNTRANSLATED_CONNECT_ERROR_CODE;
}
NOTREACHED();
- return WebBluetoothError::UntranslatedConnectErrorCode;
+ return WebBluetoothError::UNTRANSLATED_CONNECT_ERROR_CODE;
}
-blink::WebBluetoothError TranslateGATTError(
+WebBluetoothError TranslateGATTError(
BluetoothGattService::GattErrorCode error_code,
UMAGATTOperation operation) {
switch (error_code) {
case BluetoothGattService::GATT_ERROR_UNKNOWN:
RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN);
- return blink::WebBluetoothError::GATTUnknownError;
+ return blink::WebBluetoothError::GATT_UNKNOWN_ERROR;
case BluetoothGattService::GATT_ERROR_FAILED:
RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED);
- return blink::WebBluetoothError::GATTUnknownFailure;
+ return blink::WebBluetoothError::GATT_UNKNOWN_FAILURE;
case BluetoothGattService::GATT_ERROR_IN_PROGRESS:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::IN_PROGRESS);
- return blink::WebBluetoothError::GATTOperationInProgress;
+ return blink::WebBluetoothError::GATT_OPERATION_IN_PROGRESS;
case BluetoothGattService::GATT_ERROR_INVALID_LENGTH:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::INVALID_LENGTH);
- return blink::WebBluetoothError::GATTInvalidAttributeLength;
+ return blink::WebBluetoothError::GATT_INVALID_ATTRIBUTE_LENGTH;
case BluetoothGattService::GATT_ERROR_NOT_PERMITTED:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::NOT_PERMITTED);
- return blink::WebBluetoothError::GATTNotPermitted;
+ return blink::WebBluetoothError::GATT_NOT_PERMITTED;
case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::NOT_AUTHORIZED);
- return blink::WebBluetoothError::GATTNotAuthorized;
+ return blink::WebBluetoothError::GATT_NOT_AUTHORIZED;
case BluetoothGattService::GATT_ERROR_NOT_PAIRED:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::NOT_PAIRED);
- return blink::WebBluetoothError::GATTNotPaired;
+ return blink::WebBluetoothError::GATT_NOT_PAIRED;
case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED:
RecordGATTOperationOutcome(operation,
UMAGATTOperationOutcome::NOT_SUPPORTED);
- return blink::WebBluetoothError::GATTNotSupported;
+ return blink::WebBluetoothError::GATT_NOT_SUPPORTED;
}
NOTREACHED();
- return blink::WebBluetoothError::GATTUntranslatedErrorCode;
+ return blink::WebBluetoothError::GATT_UNTRANSLATED_ERROR_CODE;
}
void StopDiscoverySession(
@@ -232,6 +233,34 @@ std::vector<BluetoothGattService*> GetPrimaryServicesByUUID(
return services;
}
+UMARequestDeviceOutcome OutcomeFromChooserEvent(BluetoothChooser::Event event) {
+ switch (event) {
+ case BluetoothChooser::Event::DENIED_PERMISSION:
+ return UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_DENIED_PERMISSION;
+ case BluetoothChooser::Event::CANCELLED:
+ return UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_CANCELLED;
+ case BluetoothChooser::Event::SHOW_OVERVIEW_HELP:
+ return UMARequestDeviceOutcome::BLUETOOTH_OVERVIEW_HELP_LINK_PRESSED;
+ case BluetoothChooser::Event::SHOW_ADAPTER_OFF_HELP:
+ return UMARequestDeviceOutcome::ADAPTER_OFF_HELP_LINK_PRESSED;
+ case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP:
+ return UMARequestDeviceOutcome::NEED_LOCATION_HELP_LINK_PRESSED;
+ case BluetoothChooser::Event::SELECTED:
+ // We can't know if we are going to send a success message yet because
+ // the device could have vanished. This event should be histogramed
+ // manually after checking if the device is still around.
+ NOTREACHED();
+ return UMARequestDeviceOutcome::SUCCESS;
+ case BluetoothChooser::Event::RESCAN:
+ // Rescanning doesn't result in a IPC message for the request being sent
+ // so no need to histogram it.
+ NOTREACHED();
+ return UMARequestDeviceOutcome::SUCCESS;
+ }
+ NOTREACHED();
+ return UMARequestDeviceOutcome::SUCCESS;
+}
+
} // namespace
BluetoothDispatcherHost::BluetoothDispatcherHost(int render_process_id)
@@ -251,14 +280,11 @@ BluetoothDispatcherHost::BluetoothDispatcherHost(int render_process_id)
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ connected_devices_map_.reset(new ConnectedDevicesMap(render_process_id));
+
// Bind all future weak pointers to the UI thread.
weak_ptr_on_ui_thread_ = weak_ptr_factory_.GetWeakPtr();
weak_ptr_on_ui_thread_.get(); // Associates with UI thread.
-
- if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
- BluetoothAdapterFactory::GetAdapter(
- base::Bind(&BluetoothDispatcherHost::set_adapter,
- weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothDispatcherHost::OnDestruct() const {
@@ -278,11 +304,13 @@ bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice)
- IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_GATTServerConnect, OnGATTServerConnect)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_GATTServerDisconnect,
+ OnGATTServerDisconnect)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic)
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristics, OnGetCharacteristics)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue)
- IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_StartNotifications, OnStartNotifications)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_StopNotifications, OnStopNotifications)
IPC_MESSAGE_HANDLER(BluetoothHostMsg_RegisterCharacteristic,
@@ -321,7 +349,8 @@ void BluetoothDispatcherHost::SetBluetoothAdapterForTesting(
characteristic_to_service_.clear();
characteristic_id_to_notify_session_.clear();
active_characteristic_threads_.clear();
- connections_.clear();
+ connected_devices_map_.reset(new ConnectedDevicesMap(render_process_id_));
+ allowed_devices_map_ = BluetoothAllowedDevicesMap();
}
set_adapter(std::move(mock_adapter));
@@ -339,11 +368,13 @@ struct BluetoothDispatcherHost::RequestDeviceSession {
public:
RequestDeviceSession(int thread_id,
int request_id,
+ int frame_routing_id,
url::Origin origin,
const std::vector<BluetoothScanFilter>& filters,
const std::vector<BluetoothUUID>& optional_services)
: thread_id(thread_id),
request_id(request_id),
+ frame_routing_id(frame_routing_id),
origin(origin),
filters(filters),
optional_services(optional_services) {}
@@ -370,6 +401,7 @@ struct BluetoothDispatcherHost::RequestDeviceSession {
const int thread_id;
const int request_id;
+ const int frame_routing_id;
const url::Origin origin;
const std::vector<BluetoothScanFilter> filters;
const std::vector<BluetoothUUID> optional_services;
@@ -377,40 +409,31 @@ struct BluetoothDispatcherHost::RequestDeviceSession {
scoped_ptr<device::BluetoothDiscoverySession> discovery_session;
};
-struct BluetoothDispatcherHost::CacheQueryResult {
- CacheQueryResult()
- : device(nullptr),
- service(nullptr),
- characteristic(nullptr),
- outcome(CacheQueryOutcome::SUCCESS) {}
- CacheQueryResult(CacheQueryOutcome outcome)
- : device(nullptr),
- service(nullptr),
- characteristic(nullptr),
- outcome(outcome) {}
- ~CacheQueryResult() {}
- WebBluetoothError GetWebError() const {
- switch (outcome) {
- case CacheQueryOutcome::SUCCESS:
- case CacheQueryOutcome::BAD_RENDERER:
- NOTREACHED();
- return WebBluetoothError::DeviceNoLongerInRange;
- case CacheQueryOutcome::NO_DEVICE:
- return WebBluetoothError::DeviceNoLongerInRange;
- case CacheQueryOutcome::NO_SERVICE:
- return WebBluetoothError::ServiceNoLongerExists;
- case CacheQueryOutcome::NO_CHARACTERISTIC:
- return WebBluetoothError::CharacteristicNoLongerExists;
- }
- NOTREACHED();
- return WebBluetoothError::DeviceNoLongerInRange;
- }
+BluetoothDispatcherHost::CacheQueryResult::CacheQueryResult() {}
- device::BluetoothDevice* device;
- device::BluetoothGattService* service;
- device::BluetoothGattCharacteristic* characteristic;
- CacheQueryOutcome outcome;
-};
+BluetoothDispatcherHost::CacheQueryResult::CacheQueryResult(
+ CacheQueryOutcome outcome)
+ : outcome(outcome) {}
+
+BluetoothDispatcherHost::CacheQueryResult::~CacheQueryResult() {}
+
+WebBluetoothError BluetoothDispatcherHost::CacheQueryResult::GetWebError()
+ const {
+ switch (outcome) {
+ case CacheQueryOutcome::SUCCESS:
+ case CacheQueryOutcome::BAD_RENDERER:
+ NOTREACHED();
+ return WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE;
+ case CacheQueryOutcome::NO_DEVICE:
+ return WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE;
+ case CacheQueryOutcome::NO_SERVICE:
+ return WebBluetoothError::SERVICE_NO_LONGER_EXISTS;
+ case CacheQueryOutcome::NO_CHARACTERISTIC:
+ return WebBluetoothError::CHARACTERISTIC_NO_LONGER_EXISTS;
+ }
+ NOTREACHED();
+ return WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE;
+}
struct BluetoothDispatcherHost::PrimaryServicesRequest {
enum CallingFunction { GET_PRIMARY_SERVICE, GET_PRIMARY_SERVICES };
@@ -431,10 +454,74 @@ struct BluetoothDispatcherHost::PrimaryServicesRequest {
CallingFunction func;
};
+BluetoothDispatcherHost::ConnectedDevicesMap::ConnectedDevicesMap(
+ int render_process_id)
+ : render_process_id_(render_process_id) {}
+
+BluetoothDispatcherHost::ConnectedDevicesMap::~ConnectedDevicesMap() {
+ for (auto frame_id_device_id : frame_ids_device_ids_) {
+ DecrementBluetoothConnectedDeviceCount(frame_id_device_id.first);
+ }
+}
+
+bool BluetoothDispatcherHost::ConnectedDevicesMap::HasActiveConnection(
+ const std::string& device_id) {
+ auto connection_iter = device_id_to_connection_map_.find(device_id);
+ if (connection_iter != device_id_to_connection_map_.end()) {
+ return connection_iter->second->IsConnected();
+ }
+ return false;
+}
+
+void BluetoothDispatcherHost::ConnectedDevicesMap::InsertOrReplace(
+ int frame_routing_id,
+ const std::string& device_id,
+ scoped_ptr<device::BluetoothGattConnection> connection) {
+ auto connection_iter = device_id_to_connection_map_.find(device_id);
+ if (connection_iter == device_id_to_connection_map_.end()) {
+ IncrementBluetoothConnectedDeviceCount(frame_routing_id);
+ frame_ids_device_ids_.insert(std::make_pair(frame_routing_id, device_id));
+ } else {
+ device_id_to_connection_map_.erase(connection_iter);
+ }
+ device_id_to_connection_map_[device_id] = std::move(connection);
+}
+
+void BluetoothDispatcherHost::ConnectedDevicesMap::Remove(
+ int frame_routing_id,
+ const std::string& device_id) {
+ if (device_id_to_connection_map_.erase(device_id)) {
+ VLOG(1) << "Disconnecting device: " << device_id;
+ DecrementBluetoothConnectedDeviceCount(frame_routing_id);
+ frame_ids_device_ids_.erase(std::make_pair(frame_routing_id, device_id));
+ }
+}
+
+void BluetoothDispatcherHost::ConnectedDevicesMap::
+ IncrementBluetoothConnectedDeviceCount(int frame_routing_id) {
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id);
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderFrameHost(render_frame_host));
+ if (web_contents) {
+ web_contents->IncrementBluetoothConnectedDeviceCount();
+ }
+}
+
+void BluetoothDispatcherHost::ConnectedDevicesMap::
+ DecrementBluetoothConnectedDeviceCount(int frame_routing_id) {
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id);
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderFrameHost(render_frame_host));
+ if (web_contents) {
+ web_contents->DecrementBluetoothConnectedDeviceCount();
+ }
+}
+
void BluetoothDispatcherHost::set_adapter(
scoped_refptr<device::BluetoothAdapter> adapter) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- connections_.clear();
if (adapter_.get())
adapter_->RemoveObserver(this);
adapter_ = adapter;
@@ -488,9 +575,21 @@ void BluetoothDispatcherHost::AdapterPoweredChanged(
&request_device_sessions_);
!iter.IsAtEnd(); iter.Advance()) {
RequestDeviceSession* session = iter.GetCurrentValue();
+
+ // Stop ongoing discovery session if power is off.
+ if (!powered && session->discovery_session) {
+ StopDiscoverySession(std::move(session->discovery_session));
+ }
+
if (session->chooser)
session->chooser->SetAdapterPresence(presence);
}
+
+ // Stop the timer so that we don't change the state of the chooser
+ // when timer expires.
+ if (!powered) {
+ discovery_session_timer_.Stop();
+ }
}
void BluetoothDispatcherHost::DeviceAdded(device::BluetoothAdapter* adapter,
@@ -548,7 +647,7 @@ void BluetoothDispatcherHost::GattServicesDiscovered(
UMAGetPrimaryServiceOutcome::NOT_FOUND);
Send(new BluetoothMsg_GetPrimaryServiceError(
request.thread_id, request.request_id,
- WebBluetoothError::ServiceNotFound));
+ WebBluetoothError::SERVICE_NOT_FOUND));
}
break;
case PrimaryServicesRequest::GET_PRIMARY_SERVICES:
@@ -606,118 +705,29 @@ void BluetoothDispatcherHost::OnRequestDevice(
RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::REQUEST_DEVICE);
RecordRequestDeviceArguments(filters, optional_services);
- VLOG(1) << "requestDevice called with the following filters: ";
- for (const BluetoothScanFilter& filter : filters) {
- VLOG(1) << "Name: " << filter.name;
- VLOG(1) << "Name Prefix: " << filter.namePrefix;
- VLOG(1) << "Services:";
- VLOG(1) << "\t[";
- for (const BluetoothUUID& service : filter.services)
- VLOG(1) << "\t\t" << service.value();
- VLOG(1) << "\t]";
- }
-
- VLOG(1) << "requestDevice called with the following optional services: ";
- for (const BluetoothUUID& service : optional_services)
- VLOG(1) << "\t" << service.value();
-
- RenderFrameHostImpl* render_frame_host =
- RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id);
-
- if (!render_frame_host) {
- DLOG(WARNING)
- << "Got a requestDevice IPC without a matching RenderFrameHost: "
- << render_process_id_ << ", " << frame_routing_id;
- RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_RENDER_FRAME);
- Send(new BluetoothMsg_RequestDeviceError(
- thread_id, request_id, WebBluetoothError::RequestDeviceWithoutFrame));
- return;
- }
-
- if (!adapter_) {
- VLOG(1) << "No BluetoothAdapter. Can't serve requestDevice.";
+ if (!adapter_.get()) {
+ if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
+ BluetoothAdapterFactory::GetAdapter(base::Bind(
+ &BluetoothDispatcherHost::OnGetAdapter, weak_ptr_on_ui_thread_,
+ base::Bind(&BluetoothDispatcherHost::OnRequestDeviceImpl,
+ weak_ptr_on_ui_thread_, thread_id, request_id,
+ frame_routing_id, filters, optional_services)));
+ return;
+ }
RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_BLUETOOTH_ADAPTER);
Send(new BluetoothMsg_RequestDeviceError(
- thread_id, request_id, WebBluetoothError::NoBluetoothAdapter));
- return;
- }
-
- if (!adapter_->IsPresent()) {
- VLOG(1) << "Bluetooth Adapter not present. Can't serve requestDevice.";
- RecordRequestDeviceOutcome(
- UMARequestDeviceOutcome::BLUETOOTH_ADAPTER_NOT_PRESENT);
- Send(new BluetoothMsg_RequestDeviceError(
- thread_id, request_id, WebBluetoothError::NoBluetoothAdapter));
+ thread_id, request_id, WebBluetoothError::NO_BLUETOOTH_ADAPTER));
return;
}
-
- // The renderer should never send empty filters.
- if (HasEmptyOrInvalidFilter(filters)) {
- bad_message::ReceivedBadMessage(this,
- bad_message::BDH_EMPTY_OR_INVALID_FILTERS);
- return;
- }
-
- // Create storage for the information that backs the chooser, and show the
- // chooser.
- RequestDeviceSession* const session = new RequestDeviceSession(
- thread_id, request_id, render_frame_host->GetLastCommittedOrigin(),
- filters, optional_services);
- int chooser_id = request_device_sessions_.Add(session);
-
- BluetoothChooser::EventHandler chooser_event_handler =
- base::Bind(&BluetoothDispatcherHost::OnBluetoothChooserEvent,
- weak_ptr_on_ui_thread_, chooser_id);
- if (WebContents* web_contents =
- WebContents::FromRenderFrameHost(render_frame_host)) {
- if (WebContentsDelegate* delegate = web_contents->GetDelegate()) {
- session->chooser = delegate->RunBluetoothChooser(
- web_contents, chooser_event_handler,
- // TODO(ortuno): Replace with GetLastCommittedOrigin.
- // http://crbug.com/577451
- render_frame_host->GetLastCommittedURL().GetOrigin());
- }
- }
- if (!session->chooser) {
- LOG(WARNING)
- << "No Bluetooth chooser implementation; falling back to first device.";
- session->chooser.reset(
- new FirstDeviceBluetoothChooser(chooser_event_handler));
- }
-
- if (!session->chooser->CanAskForScanningPermission()) {
- VLOG(1) << "Closing immediately because Chooser cannot obtain permission.";
- OnBluetoothChooserEvent(chooser_id,
- BluetoothChooser::Event::DENIED_PERMISSION, "");
- return;
- }
-
- // Populate the initial list of devices.
- VLOG(1) << "Populating " << adapter_->GetDevices().size()
- << " devices in chooser " << chooser_id;
- for (const device::BluetoothDevice* device : adapter_->GetDevices()) {
- VLOG(1) << "\t" << device->GetAddress();
- session->AddFilteredDevice(*device);
- }
-
- if (!session->chooser) {
- // If the dialog's closing, no need to do any of the rest of this.
- return;
- }
-
- if (!adapter_->IsPowered()) {
- session->chooser->SetAdapterPresence(
- BluetoothChooser::AdapterPresence::POWERED_OFF);
- return;
- }
-
- StartDeviceDiscovery(session, chooser_id);
+ OnRequestDeviceImpl(thread_id, request_id, frame_routing_id, filters,
+ optional_services);
}
-void BluetoothDispatcherHost::OnConnectGATT(int thread_id,
- int request_id,
- int frame_routing_id,
- const std::string& device_id) {
+void BluetoothDispatcherHost::OnGATTServerConnect(
+ int thread_id,
+ int request_id,
+ int frame_routing_id,
+ const std::string& device_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT);
const base::TimeTicks start_time = base::TimeTicks::Now();
@@ -727,20 +737,53 @@ void BluetoothDispatcherHost::OnConnectGATT(int thread_id,
if (query_result.outcome != CacheQueryOutcome::SUCCESS) {
RecordConnectGATTOutcome(query_result.outcome);
- Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id,
- query_result.GetWebError()));
+ Send(new BluetoothMsg_GATTServerConnectError(thread_id, request_id,
+ query_result.GetWebError()));
+ return;
+ }
+
+ // If we are already connected no need to connect again.
+ if (connected_devices_map_->HasActiveConnection(device_id)) {
+ VLOG(1) << "Already connected.";
+ Send(new BluetoothMsg_GATTServerConnectSuccess(thread_id, request_id));
return;
}
query_result.device->CreateGattConnection(
base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated,
- weak_ptr_on_ui_thread_, thread_id, request_id, device_id,
- start_time),
+ weak_ptr_on_ui_thread_, thread_id, request_id,
+ frame_routing_id, device_id, start_time),
base::Bind(&BluetoothDispatcherHost::OnCreateGATTConnectionError,
weak_ptr_on_ui_thread_, thread_id, request_id, device_id,
start_time));
}
+void BluetoothDispatcherHost::OnGATTServerDisconnect(
+ int thread_id,
+ int frame_routing_id,
+ const std::string& device_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RecordWebBluetoothFunctionCall(
+ UMAWebBluetoothFunction::REMOTE_GATT_SERVER_DISCONNECT);
+
+ // Frames can send a disconnect request after they've started navigating,
+ // making calls to GetLastCommitted origin invalid. Because we still need
+ // to disconnect the device, otherwise we would leave users with no other
+ // option to disconnect than closing the tab, we purposefully don't
+ // check if the frame has permission to interact with the device.
+
+ // The last BluetoothGattConnection for a device closes the connection when
+ // it's destroyed.
+
+ // This only catches disconnections from the renderer. If the device
+ // disconnects by itself, or the renderer frame has been deleted
+ // due to navigation, we will not hide the indicator.
+ // TODO(ortuno): Once we move to Frame and Mojo we will be able
+ // to observe the frame's lifetime and hide the indicator when necessary.
+ // http://crbug.com/508771
+ connected_devices_map_->Remove(frame_routing_id, device_id);
+}
+
void BluetoothDispatcherHost::OnGetPrimaryService(
int thread_id,
int request_id,
@@ -751,8 +794,13 @@ void BluetoothDispatcherHost::OnGetPrimaryService(
RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_PRIMARY_SERVICE);
RecordGetPrimaryServiceService(BluetoothUUID(service_uuid));
- // TODO(ortuno): Check if service_uuid is in "allowed services"
- // https://crbug.com/493460
+ if (!allowed_devices_map_.IsOriginAllowedToAccessService(
+ GetOrigin(frame_routing_id), device_id, service_uuid)) {
+ Send(new BluetoothMsg_GetPrimaryServiceError(
+ thread_id, request_id,
+ WebBluetoothError::NOT_ALLOWED_TO_ACCESS_SERVICE));
+ return;
+ }
const CacheQueryResult query_result =
QueryCacheForDevice(GetOrigin(frame_routing_id), device_id);
@@ -792,7 +840,7 @@ void BluetoothDispatcherHost::OnGetPrimaryService(
VLOG(1) << "Service not found in device.";
RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::NOT_FOUND);
Send(new BluetoothMsg_GetPrimaryServiceError(
- thread_id, request_id, WebBluetoothError::ServiceNotFound));
+ thread_id, request_id, WebBluetoothError::SERVICE_NOT_FOUND));
return;
}
@@ -814,6 +862,16 @@ void BluetoothDispatcherHost::OnGetCharacteristic(
RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC);
RecordGetCharacteristicCharacteristic(characteristic_uuid);
+ // Check Blacklist for characteristic_uuid.
+ if (BluetoothBlacklist::Get().IsExcluded(
+ BluetoothUUID(characteristic_uuid))) {
+ RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::BLACKLISTED);
+ Send(new BluetoothMsg_GetCharacteristicError(
+ thread_id, request_id,
+ WebBluetoothError::BLACKLISTED_CHARACTERISTIC_UUID));
+ return;
+ }
+
const CacheQueryResult query_result =
QueryCacheForService(GetOrigin(frame_routing_id), service_instance_id);
@@ -852,59 +910,98 @@ void BluetoothDispatcherHost::OnGetCharacteristic(
}
RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::NOT_FOUND);
Send(new BluetoothMsg_GetCharacteristicError(
- thread_id, request_id, WebBluetoothError::CharacteristicNotFound));
+ thread_id, request_id, WebBluetoothError::CHARACTERISTIC_NOT_FOUND));
}
-void BluetoothDispatcherHost::OnReadValue(
+void BluetoothDispatcherHost::OnGetCharacteristics(
int thread_id,
int request_id,
int frame_routing_id,
- const std::string& characteristic_instance_id) {
+ const std::string& service_instance_id,
+ const std::string& characteristics_uuid) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RecordWebBluetoothFunctionCall(
- UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE);
+ UMAWebBluetoothFunction::SERVICE_GET_CHARACTERISTICS);
+ RecordGetCharacteristicsCharacteristic(characteristics_uuid);
+
+ // Check Blacklist for characteristics_uuid.
+ if (!characteristics_uuid.empty() &&
+ BluetoothBlacklist::Get().IsExcluded(
+ BluetoothUUID(characteristics_uuid))) {
+ RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome::BLACKLISTED);
+ Send(new BluetoothMsg_GetCharacteristicsError(
+ thread_id, request_id,
+ WebBluetoothError::BLACKLISTED_CHARACTERISTIC_UUID));
+ return;
+ }
- const CacheQueryResult query_result = QueryCacheForCharacteristic(
- GetOrigin(frame_routing_id), characteristic_instance_id);
+ const CacheQueryResult query_result =
+ QueryCacheForService(GetOrigin(frame_routing_id), service_instance_id);
if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) {
return;
}
if (query_result.outcome != CacheQueryOutcome::SUCCESS) {
- RecordCharacteristicReadValueOutcome(query_result.outcome);
- Send(new BluetoothMsg_ReadCharacteristicValueError(
- thread_id, request_id, query_result.GetWebError()));
+ RecordGetCharacteristicsOutcome(query_result.outcome);
+ Send(new BluetoothMsg_GetCharacteristicsError(thread_id, request_id,
+ query_result.GetWebError()));
return;
}
- query_result.characteristic->ReadRemoteCharacteristic(
- base::Bind(&BluetoothDispatcherHost::OnCharacteristicValueRead,
- weak_ptr_on_ui_thread_, thread_id, request_id),
- base::Bind(&BluetoothDispatcherHost::OnCharacteristicReadValueError,
- weak_ptr_on_ui_thread_, thread_id, request_id));
+ std::vector<std::string> characteristics_instance_ids;
+ std::vector<std::string> characteristics_uuids;
+ std::vector<uint32_t> characteristics_properties;
+
+ for (BluetoothGattCharacteristic* characteristic :
+ query_result.service->GetCharacteristics()) {
+ if (!BluetoothBlacklist::Get().IsExcluded(characteristic->GetUUID()) &&
+ (characteristics_uuid.empty() ||
+ characteristics_uuid == characteristic->GetUUID().canonical_value())) {
+ const std::string& characteristic_instance_id =
+ characteristic->GetIdentifier();
+
+ characteristics_instance_ids.push_back(characteristic_instance_id);
+ characteristics_uuids.push_back(
+ characteristic->GetUUID().canonical_value());
+ characteristics_properties.push_back(
+ static_cast<uint32_t>(characteristic->GetProperties()));
+
+ auto insert_result = characteristic_to_service_.insert(
+ make_pair(characteristic_instance_id, service_instance_id));
+
+ // If value is already in map, DCHECK it's valid.
+ if (!insert_result.second)
+ DCHECK(insert_result.first->second == service_instance_id);
+ }
+ }
+
+ if (!characteristics_instance_ids.empty()) {
+ RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome::SUCCESS);
+ Send(new BluetoothMsg_GetCharacteristicsSuccess(
+ thread_id, request_id, characteristics_instance_ids,
+ characteristics_uuids, characteristics_properties));
+ return;
+ }
+ RecordGetCharacteristicsOutcome(
+ characteristics_uuid.empty()
+ ? UMAGetCharacteristicOutcome::NO_CHARACTERISTICS
+ : UMAGetCharacteristicOutcome::NOT_FOUND);
+ Send(new BluetoothMsg_GetCharacteristicsError(
+ thread_id, request_id,
+ characteristics_uuid.empty()
+ ? WebBluetoothError::NO_CHARACTERISTICS_FOUND
+ : WebBluetoothError::CHARACTERISTIC_NOT_FOUND));
}
-void BluetoothDispatcherHost::OnWriteValue(
+void BluetoothDispatcherHost::OnReadValue(
int thread_id,
int request_id,
int frame_routing_id,
- const std::string& characteristic_instance_id,
- const std::vector<uint8_t>& value) {
+ const std::string& characteristic_instance_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RecordWebBluetoothFunctionCall(
- UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE);
-
- // Length check per step 3 of writeValue algorithm:
- // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharacteristic-writevalue
- // We perform the length check on the renderer side. So if we
- // get a value with length > 512, we can assume it's a hostile
- // renderer and kill it.
- if (value.size() > 512) {
- bad_message::ReceivedBadMessage(
- this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH);
- return;
- }
+ UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE);
const CacheQueryResult query_result = QueryCacheForCharacteristic(
GetOrigin(frame_routing_id), characteristic_instance_id);
@@ -914,16 +1011,24 @@ void BluetoothDispatcherHost::OnWriteValue(
}
if (query_result.outcome != CacheQueryOutcome::SUCCESS) {
- RecordCharacteristicWriteValueOutcome(query_result.outcome);
- Send(new BluetoothMsg_WriteCharacteristicValueError(
+ RecordCharacteristicReadValueOutcome(query_result.outcome);
+ Send(new BluetoothMsg_ReadCharacteristicValueError(
thread_id, request_id, query_result.GetWebError()));
return;
}
- query_result.characteristic->WriteRemoteCharacteristic(
- value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess,
- weak_ptr_on_ui_thread_, thread_id, request_id),
- base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed,
+ if (BluetoothBlacklist::Get().IsExcludedFromReads(
+ query_result.characteristic->GetUUID())) {
+ RecordCharacteristicReadValueOutcome(UMAGATTOperationOutcome::BLACKLISTED);
+ Send(new BluetoothMsg_ReadCharacteristicValueError(
+ thread_id, request_id, WebBluetoothError::BLACKLISTED_READ));
+ return;
+ }
+
+ query_result.characteristic->ReadRemoteCharacteristic(
+ base::Bind(&BluetoothDispatcherHost::OnCharacteristicValueRead,
+ weak_ptr_on_ui_thread_, thread_id, request_id),
+ base::Bind(&BluetoothDispatcherHost::OnCharacteristicReadValueError,
weak_ptr_on_ui_thread_, thread_id, request_id));
}
@@ -1028,6 +1133,181 @@ void BluetoothDispatcherHost::OnUnregisterCharacteristicObject(
}
}
+void BluetoothDispatcherHost::OnGetAdapter(
+ base::Closure continuation,
+ scoped_refptr<device::BluetoothAdapter> adapter) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ set_adapter(adapter);
+ continuation.Run();
+}
+
+void BluetoothDispatcherHost::OnRequestDeviceImpl(
+ int thread_id,
+ int request_id,
+ int frame_routing_id,
+ const std::vector<BluetoothScanFilter>& filters,
+ const std::vector<BluetoothUUID>& optional_services) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ VLOG(1) << "requestDevice called with the following filters: ";
+ for (const BluetoothScanFilter& filter : filters) {
+ VLOG(1) << "Name: " << filter.name;
+ VLOG(1) << "Name Prefix: " << filter.namePrefix;
+ VLOG(1) << "Services:";
+ VLOG(1) << "\t[";
+ for (const BluetoothUUID& service : filter.services)
+ VLOG(1) << "\t\t" << service.value();
+ VLOG(1) << "\t]";
+ }
+
+ VLOG(1) << "requestDevice called with the following optional services: ";
+ for (const BluetoothUUID& service : optional_services)
+ VLOG(1) << "\t" << service.value();
+
+ // Check blacklist to reject invalid filters and adjust optional_services.
+ if (BluetoothBlacklist::Get().IsExcluded(filters)) {
+ RecordRequestDeviceOutcome(
+ UMARequestDeviceOutcome::BLACKLISTED_SERVICE_IN_FILTER);
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id,
+ WebBluetoothError::REQUEST_DEVICE_WITH_BLACKLISTED_UUID));
+ return;
+ }
+ std::vector<BluetoothUUID> optional_services_blacklist_filtered(
+ optional_services);
+ BluetoothBlacklist::Get().RemoveExcludedUuids(
+ &optional_services_blacklist_filtered);
+
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id);
+ WebContents* web_contents =
+ WebContents::FromRenderFrameHost(render_frame_host);
+
+ if (!render_frame_host || !web_contents) {
+ DLOG(WARNING) << "Got a requestDevice IPC without a matching "
+ << "RenderFrameHost or WebContents: " << render_process_id_
+ << ", " << frame_routing_id;
+ RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_RENDER_FRAME);
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id,
+ WebBluetoothError::REQUEST_DEVICE_WITHOUT_FRAME));
+ return;
+ }
+
+ const url::Origin requesting_origin =
+ render_frame_host->GetLastCommittedOrigin();
+ const url::Origin embedding_origin =
+ web_contents->GetMainFrame()->GetLastCommittedOrigin();
+
+ // TODO(crbug.com/518042): Enforce correctly-delegated permissions instead of
+ // matching origins. When relaxing this, take care to handle non-sandboxed
+ // unique origins.
+ if (!embedding_origin.IsSameOriginWith(requesting_origin)) {
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id,
+ WebBluetoothError::REQUEST_DEVICE_FROM_CROSS_ORIGIN_IFRAME));
+ return;
+ }
+ // The above also excludes unique origins, which are not even same-origin with
+ // themselves.
+ DCHECK(!requesting_origin.unique());
+
+ DCHECK(adapter_.get());
+
+ if (!adapter_->IsPresent()) {
+ VLOG(1) << "Bluetooth Adapter not present. Can't serve requestDevice.";
+ RecordRequestDeviceOutcome(
+ UMARequestDeviceOutcome::BLUETOOTH_ADAPTER_NOT_PRESENT);
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id, WebBluetoothError::NO_BLUETOOTH_ADAPTER));
+ return;
+ }
+
+ // The renderer should never send empty filters.
+ if (HasEmptyOrInvalidFilter(filters)) {
+ bad_message::ReceivedBadMessage(this,
+ bad_message::BDH_EMPTY_OR_INVALID_FILTERS);
+ return;
+ }
+
+ switch (GetContentClient()->browser()->AllowWebBluetooth(
+ web_contents->GetBrowserContext(), requesting_origin, embedding_origin)) {
+ case ContentBrowserClient::AllowWebBluetoothResult::BLOCK_POLICY: {
+ RecordRequestDeviceOutcome(
+ UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_POLICY_DISABLED);
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id,
+ WebBluetoothError::CHOOSER_NOT_SHOWN_API_LOCALLY_DISABLED));
+ return;
+ }
+ case ContentBrowserClient::AllowWebBluetoothResult::
+ BLOCK_GLOBALLY_DISABLED: {
+ // Log to the developer console.
+ web_contents->GetMainFrame()->AddMessageToConsole(
+ content::CONSOLE_MESSAGE_LEVEL_LOG,
+ "Bluetooth permission has been blocked.");
+ // Block requests.
+ RecordRequestDeviceOutcome(
+ UMARequestDeviceOutcome::BLUETOOTH_GLOBALLY_DISABLED);
+ Send(new BluetoothMsg_RequestDeviceError(
+ thread_id, request_id,
+ WebBluetoothError::CHOOSER_NOT_SHOWN_API_GLOBALLY_DISABLED));
+ return;
+ }
+ case ContentBrowserClient::AllowWebBluetoothResult::ALLOW:
+ break;
+ }
+
+ // Create storage for the information that backs the chooser, and show the
+ // chooser.
+ RequestDeviceSession* const session = new RequestDeviceSession(
+ thread_id, request_id, frame_routing_id, requesting_origin, filters,
+ optional_services_blacklist_filtered);
+ int chooser_id = request_device_sessions_.Add(session);
+
+ BluetoothChooser::EventHandler chooser_event_handler =
+ base::Bind(&BluetoothDispatcherHost::OnBluetoothChooserEvent,
+ weak_ptr_on_ui_thread_, chooser_id);
+ if (WebContentsDelegate* delegate = web_contents->GetDelegate()) {
+ session->chooser =
+ delegate->RunBluetoothChooser(render_frame_host, chooser_event_handler);
+ }
+ if (!session->chooser) {
+ LOG(WARNING)
+ << "No Bluetooth chooser implementation; falling back to first device.";
+ session->chooser.reset(
+ new FirstDeviceBluetoothChooser(chooser_event_handler));
+ }
+
+ if (!session->chooser->CanAskForScanningPermission()) {
+ VLOG(1) << "Closing immediately because Chooser cannot obtain permission.";
+ OnBluetoothChooserEvent(chooser_id,
+ BluetoothChooser::Event::DENIED_PERMISSION, "");
+ return;
+ }
+
+ // Populate the initial list of devices.
+ VLOG(1) << "Populating " << adapter_->GetDevices().size()
+ << " devices in chooser " << chooser_id;
+ for (const device::BluetoothDevice* device : adapter_->GetDevices()) {
+ VLOG(1) << "\t" << device->GetAddress();
+ session->AddFilteredDevice(*device);
+ }
+
+ if (!session->chooser) {
+ // If the dialog's closing, no need to do any of the rest of this.
+ return;
+ }
+
+ if (!adapter_->IsPowered()) {
+ session->chooser->SetAdapterPresence(
+ BluetoothChooser::AdapterPresence::POWERED_OFF);
+ return;
+ }
+
+ StartDeviceDiscovery(session, chooser_id);
+}
+
void BluetoothDispatcherHost::OnDiscoverySessionStarted(
int chooser_id,
scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
@@ -1074,38 +1354,35 @@ void BluetoothDispatcherHost::OnBluetoothChooserEvent(
switch (event) {
case BluetoothChooser::Event::RESCAN:
StartDeviceDiscovery(session, chooser_id);
- break;
+ // No need to close the chooser so we return.
+ return;
case BluetoothChooser::Event::DENIED_PERMISSION:
case BluetoothChooser::Event::CANCELLED:
- case BluetoothChooser::Event::SELECTED: {
- // Synchronously ensure nothing else calls into the chooser after it has
- // asked to be closed.
- session->chooser.reset();
-
- // Yield to the event loop to make sure we don't destroy the session
- // within a BluetoothDispatcherHost stack frame.
- if (!base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&BluetoothDispatcherHost::FinishClosingChooser,
- weak_ptr_on_ui_thread_, chooser_id, event,
- device_id))) {
- LOG(WARNING) << "No TaskRunner; not closing requestDevice dialog.";
- }
+ case BluetoothChooser::Event::SELECTED:
break;
- }
case BluetoothChooser::Event::SHOW_OVERVIEW_HELP:
- ShowBluetoothOverviewLink();
- break;
- case BluetoothChooser::Event::SHOW_PAIRING_HELP:
- ShowBluetoothPairingLink();
+ VLOG(1) << "Overview Help link pressed.";
break;
case BluetoothChooser::Event::SHOW_ADAPTER_OFF_HELP:
- ShowBluetoothAdapterOffLink();
+ VLOG(1) << "Adapter Off Help link pressed.";
break;
case BluetoothChooser::Event::SHOW_NEED_LOCATION_HELP:
- ShowNeedLocationLink();
+ VLOG(1) << "Need Location Help link pressed.";
break;
}
+
+ // Synchronously ensure nothing else calls into the chooser after it has
+ // asked to be closed.
+ session->chooser.reset();
+
+ // Yield to the event loop to make sure we don't destroy the session
+ // within a BluetoothDispatcherHost stack frame.
+ if (!base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothDispatcherHost::FinishClosingChooser,
+ weak_ptr_on_ui_thread_, chooser_id, event, device_id))) {
+ LOG(WARNING) << "No TaskRunner; not closing requestDevice dialog.";
+ }
}
void BluetoothDispatcherHost::FinishClosingChooser(
@@ -1116,13 +1393,12 @@ void BluetoothDispatcherHost::FinishClosingChooser(
RequestDeviceSession* session = request_device_sessions_.Lookup(chooser_id);
DCHECK(session) << "Session removed unexpectedly.";
- if (event == BluetoothChooser::Event::CANCELLED) {
- RecordRequestDeviceOutcome(
- UMARequestDeviceOutcome::BLUETOOTH_CHOOSER_CANCELLED);
- VLOG(1) << "Bluetooth chooser cancelled";
+ if ((event != BluetoothChooser::Event::DENIED_PERMISSION) &&
+ (event != BluetoothChooser::Event::SELECTED)) {
+ RecordRequestDeviceOutcome(OutcomeFromChooserEvent(event));
Send(new BluetoothMsg_RequestDeviceError(
session->thread_id, session->request_id,
- WebBluetoothError::ChooserCancelled));
+ WebBluetoothError::CHOOSER_CANCELLED));
request_device_sessions_.Remove(chooser_id);
return;
}
@@ -1132,7 +1408,7 @@ void BluetoothDispatcherHost::FinishClosingChooser(
VLOG(1) << "Bluetooth chooser denied permission";
Send(new BluetoothMsg_RequestDeviceError(
session->thread_id, session->request_id,
- WebBluetoothError::ChooserDeniedPermission));
+ WebBluetoothError::CHOOSER_NOT_SHOWN_USER_DENIED_PERMISSION_TO_SCAN));
request_device_sessions_.Remove(chooser_id);
return;
}
@@ -1147,20 +1423,29 @@ void BluetoothDispatcherHost::FinishClosingChooser(
RecordRequestDeviceOutcome(UMARequestDeviceOutcome::CHOSEN_DEVICE_VANISHED);
Send(new BluetoothMsg_RequestDeviceError(
session->thread_id, session->request_id,
- WebBluetoothError::ChosenDeviceVanished));
+ WebBluetoothError::CHOSEN_DEVICE_VANISHED));
request_device_sessions_.Remove(chooser_id);
return;
}
- VLOG(1) << "Device: " << device->GetName();
- VLOG(1) << "UUIDs: ";
- for (BluetoothUUID uuid : device->GetUUIDs())
- VLOG(1) << "\t" << uuid.canonical_value();
-
const std::string& device_id_for_origin = allowed_devices_map_.AddDevice(
session->origin, device->GetAddress(), session->filters,
session->optional_services);
+ VLOG(1) << "Device: " << device->GetName();
+ VLOG(1) << "UUIDs: ";
+
+ device::BluetoothDevice::UUIDList filtered_uuids;
+ for (BluetoothUUID uuid : device->GetUUIDs()) {
+ if (allowed_devices_map_.IsOriginAllowedToAccessService(
+ session->origin, device_id_for_origin, uuid.canonical_value())) {
+ VLOG(1) << "\t Allowed: " << uuid.canonical_value();
+ filtered_uuids.push_back(uuid);
+ } else {
+ VLOG(1) << "\t Not Allowed: " << uuid.canonical_value();
+ }
+ }
+
content::BluetoothDevice device_ipc(
device_id_for_origin, // id
device->GetName(), // name
@@ -1174,7 +1459,7 @@ void BluetoothDispatcherHost::FinishClosingChooser(
device->GetProductID(), // product_id
device->GetDeviceID(), // product_version
content::BluetoothDevice::UUIDsFromBluetoothUUIDs(
- device->GetUUIDs())); // uuids
+ filtered_uuids)); // uuids
RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS);
Send(new BluetoothMsg_RequestDeviceSuccess(session->thread_id,
session->request_id, device_ipc));
@@ -1184,14 +1469,16 @@ void BluetoothDispatcherHost::FinishClosingChooser(
void BluetoothDispatcherHost::OnGATTConnectionCreated(
int thread_id,
int request_id,
+ int frame_routing_id,
const std::string& device_id,
base::TimeTicks start_time,
scoped_ptr<device::BluetoothGattConnection> connection) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- connections_.push_back(std::move(connection));
RecordConnectGATTTimeSuccess(base::TimeTicks::Now() - start_time);
RecordConnectGATTOutcome(UMAConnectGATTOutcome::SUCCESS);
- Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id, device_id));
+ connected_devices_map_->InsertOrReplace(frame_routing_id, device_id,
+ std::move(connection));
+ Send(new BluetoothMsg_GATTServerConnectSuccess(thread_id, request_id));
}
void BluetoothDispatcherHost::OnCreateGATTConnectionError(
@@ -1206,8 +1493,8 @@ void BluetoothDispatcherHost::OnCreateGATTConnectionError(
// https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt
RecordConnectGATTTimeFailed(base::TimeTicks::Now() - start_time);
// RecordConnectGATTOutcome is called by TranslateConnectError.
- Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id,
- TranslateConnectError(error_code)));
+ Send(new BluetoothMsg_GATTServerConnectError(
+ thread_id, request_id, TranslateConnectError(error_code)));
}
void BluetoothDispatcherHost::AddToServicesMapAndSendGetPrimaryServiceSuccess(
@@ -1249,24 +1536,6 @@ void BluetoothDispatcherHost::OnCharacteristicReadValueError(
TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_READ)));
}
-void BluetoothDispatcherHost::OnWriteValueSuccess(int thread_id,
- int request_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::SUCCESS);
- Send(new BluetoothMsg_WriteCharacteristicValueSuccess(thread_id, request_id));
-}
-
-void BluetoothDispatcherHost::OnWriteValueFailed(
- int thread_id,
- int request_id,
- device::BluetoothGattService::GattErrorCode error_code) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // TranslateGATTError calls RecordGATTOperationOutcome.
- Send(new BluetoothMsg_WriteCharacteristicValueError(
- thread_id, request_id,
- TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE)));
-}
-
void BluetoothDispatcherHost::OnStartNotifySessionSuccess(
int thread_id,
int request_id,
@@ -1355,6 +1624,12 @@ BluetoothDispatcherHost::QueryCacheForService(
result.service = result.device->GetGattService(service_instance_id);
if (result.service == nullptr) {
result.outcome = CacheQueryOutcome::NO_SERVICE;
+ } else if (!allowed_devices_map_.IsOriginAllowedToAccessService(
+ origin, device_id,
+ result.service->GetUUID().canonical_value())) {
+ bad_message::ReceivedBadMessage(
+ this, bad_message::BDH_SERVICE_NOT_ALLOWED_FOR_ORIGIN);
+ return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER);
}
return result;
}
@@ -1408,24 +1683,4 @@ bool BluetoothDispatcherHost::CanFrameAccessCharacteristicInstance(
.outcome != CacheQueryOutcome::BAD_RENDERER;
}
-void BluetoothDispatcherHost::ShowBluetoothOverviewLink() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NOTIMPLEMENTED();
-}
-
-void BluetoothDispatcherHost::ShowBluetoothPairingLink() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NOTIMPLEMENTED();
-}
-
-void BluetoothDispatcherHost::ShowBluetoothAdapterOffLink() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NOTIMPLEMENTED();
-}
-
-void BluetoothDispatcherHost::ShowNeedLocationLink() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NOTIMPLEMENTED();
-}
-
} // namespace content
diff --git a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h
index 7bae29ca931..e3a4d6178bd 100644
--- a/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h
+++ b/chromium/content/browser/bluetooth/bluetooth_dispatcher_host.h
@@ -14,6 +14,8 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h"
+#include "content/browser/bluetooth/bluetooth_metrics.h"
+#include "content/common/bluetooth/bluetooth_messages.h"
#include "content/public/browser/bluetooth_chooser.h"
#include "content/public/browser/browser_message_filter.h"
#include "device/bluetooth/bluetooth_adapter.h"
@@ -53,6 +55,29 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
void SetBluetoothAdapterForTesting(
scoped_refptr<device::BluetoothAdapter> mock_adapter);
+ // TODO(ortuno): We temporarily make this a public struct so that
+ // both BluetoothDispatcherHost and WebBluetoothServiceImpl can use it,
+ // while we move functions from BluetoothDispatcherHost to
+ // WebBluetoothServiceImpl.
+ // https://crbug.com/508771
+ struct CacheQueryResult {
+ CacheQueryResult();
+ CacheQueryResult(CacheQueryOutcome outcome);
+ ~CacheQueryResult();
+ blink::WebBluetoothError GetWebError() const;
+ device::BluetoothDevice* device = nullptr;
+ device::BluetoothGattService* service = nullptr;
+ device::BluetoothGattCharacteristic* characteristic = nullptr;
+ CacheQueryOutcome outcome = CacheQueryOutcome::SUCCESS;
+ };
+
+ // Queries the platform cache for a characteristic with
+ // |characteristic_instance_id|. Fills in the |outcome| field, and |device|,
+ // |service| and |characteristic| fields if successful.
+ CacheQueryResult QueryCacheForCharacteristic(
+ const url::Origin& origin,
+ const std::string& characteristic_instance_id);
+
protected:
~BluetoothDispatcherHost() override;
@@ -60,10 +85,32 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
friend class base::DeleteHelper<BluetoothDispatcherHost>;
friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
- struct CacheQueryResult;
struct RequestDeviceSession;
struct PrimaryServicesRequest;
+ // Map to keep track of connections. Inserting and removing connections
+ // will update the Web Contents for the frame. Upon destruction
+ // the map will clear Web Contents of Bluetooth connections.
+ struct ConnectedDevicesMap {
+ ConnectedDevicesMap(int render_process_id);
+ ~ConnectedDevicesMap();
+ bool HasActiveConnection(const std::string& device_id);
+ void InsertOrReplace(
+ int frame_routing_id,
+ const std::string& device_id,
+ scoped_ptr<device::BluetoothGattConnection> connection);
+ void Remove(int frame_routing_id, const std::string& device_id);
+ void IncrementBluetoothConnectedDeviceCount(int frame_routing_id);
+ void DecrementBluetoothConnectedDeviceCount(int frame_routing_id);
+
+ int render_process_id_;
+ std::unordered_map<std::string, scoped_ptr<device::BluetoothGattConnection>>
+ device_id_to_connection_map_;
+ // Keeps track of which frame is connected to which device so that
+ // we can clean up the WebContents in our destructor.
+ std::set<std::pair<int, std::string>> frame_ids_device_ids_;
+ };
+
// Set |adapter_| to a BluetoothAdapter instance and register observers,
// releasing references to previous |adapter_|.
void set_adapter(scoped_refptr<device::BluetoothAdapter> adapter);
@@ -103,10 +150,13 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
int frame_routing_id,
const std::vector<content::BluetoothScanFilter>& filters,
const std::vector<device::BluetoothUUID>& optional_services);
- void OnConnectGATT(int thread_id,
- int request_id,
- int frame_routing_id,
- const std::string& device_id);
+ void OnGATTServerConnect(int thread_id,
+ int request_id,
+ int frame_routing_id,
+ const std::string& device_id);
+ void OnGATTServerDisconnect(int thread_id,
+ int frame_routing_id,
+ const std::string& device_id);
void OnGetPrimaryService(int thread_id,
int request_id,
int frame_routing_id,
@@ -117,15 +167,15 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
int frame_routing_id,
const std::string& service_instance_id,
const std::string& characteristic_uuid);
+ void OnGetCharacteristics(int thread_id,
+ int request_id,
+ int frame_routing_id,
+ const std::string& service_instance_id,
+ const std::string& characteristics_uuid);
void OnReadValue(int thread_id,
int request_id,
int frame_routing_id,
const std::string& characteristic_instance_id);
- void OnWriteValue(int thread_id,
- int request_id,
- int frame_routing_id,
- const std::string& characteristic_instance_id,
- const std::vector<uint8_t>& value);
void OnStartNotifications(int thread_id,
int request_id,
int frame_routing_id,
@@ -143,6 +193,17 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
int frame_routing_id,
const std::string& characteristic_instance_id);
+ // Callbacks for BluetoothDevice::OnRequestDevice.
+ // If necessary, the adapter must be obtained before continuing to Impl.
+ void OnGetAdapter(base::Closure continuation,
+ scoped_refptr<device::BluetoothAdapter> adapter);
+ void OnRequestDeviceImpl(
+ int thread_id,
+ int request_id,
+ int frame_routing_id,
+ const std::vector<content::BluetoothScanFilter>& filters,
+ const std::vector<device::BluetoothUUID>& optional_services);
+
// Callbacks for BluetoothAdapter::StartDiscoverySession.
void OnDiscoverySessionStarted(
int chooser_id,
@@ -165,6 +226,7 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
void OnGATTConnectionCreated(
int thread_id,
int request_id,
+ int frame_routing_id,
const std::string& device_id,
base::TimeTicks start_time,
scoped_ptr<device::BluetoothGattConnection> connection);
@@ -191,12 +253,6 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
int request_id,
device::BluetoothGattService::GattErrorCode);
- // Callbacks for BluetoothGattCharacteristic::WriteRemoteCharacteristic.
- void OnWriteValueSuccess(int thread_id, int request_id);
- void OnWriteValueFailed(int thread_id,
- int request_id,
- device::BluetoothGattService::GattErrorCode);
-
// Callbacks for BluetoothGattCharacteristic::StartNotifySession.
void OnStartNotifySessionSuccess(
int thread_id,
@@ -228,12 +284,6 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
// in the |outcome| field, and |device| and |service| fields if successful.
CacheQueryResult QueryCacheForService(const url::Origin& origin,
const std::string& service_instance_id);
- // Queries the platform cache for a characteristic with
- // |characteristic_instance_id|. Fills in the |outcome| field, and |device|,
- // |service| and |characteristic| fields if successful.
- CacheQueryResult QueryCacheForCharacteristic(
- const url::Origin& origin,
- const std::string& characteristic_instance_id);
// Adds the PrimaryServicesRequest to the vector of pending services requests
// for that device.
@@ -251,12 +301,6 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
int frame_routing_id,
const std::string& characteristic_instance_id);
- // Show help pages from the chooser dialog.
- void ShowBluetoothOverviewLink();
- void ShowBluetoothPairingLink();
- void ShowBluetoothAdapterOffLink();
- void ShowNeedLocationLink();
-
int render_process_id_;
// Maps a (thread_id,request_id) to information about its requestDevice call,
@@ -297,9 +341,8 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
// sessions when other sessions are active.
base::Timer discovery_session_timer_;
- // Retain BluetoothGattConnection objects to keep connections open.
- // TODO(scheib): Destroy as connections are closed. http://crbug.com/539643
- ScopedVector<device::BluetoothGattConnection> connections_;
+ // Retains BluetoothGattConnection objects to keep connections open.
+ scoped_ptr<ConnectedDevicesMap> connected_devices_map_;
// Map of device_address's to primary-services requests that need responses
// when that device's service discovery completes.
diff --git a/chromium/content/browser/bluetooth/bluetooth_metrics.cc b/chromium/content/browser/bluetooth/bluetooth_metrics.cc
index ef829203bba..32f7c73dfa7 100644
--- a/chromium/content/browser/bluetooth/bluetooth_metrics.cc
+++ b/chromium/content/browser/bluetooth/bluetooth_metrics.cc
@@ -97,7 +97,7 @@ void RecordRequestDeviceArguments(
RecordUnionOfServices(filters, optional_services);
}
-// connectGATT
+// GATTServer.Connect
void RecordConnectGATTOutcome(UMAConnectGATTOutcome outcome) {
UMA_HISTOGRAM_ENUMERATION("Bluetooth.Web.ConnectGATT.Outcome",
@@ -150,7 +150,8 @@ void RecordGetCharacteristicOutcome(CacheQueryOutcome outcome) {
switch (outcome) {
case CacheQueryOutcome::SUCCESS:
case CacheQueryOutcome::BAD_RENDERER:
- NOTREACHED() << "No need to record a success or renderer crash";
+ // No need to record a success or renderer crash.
+ NOTREACHED();
return;
case CacheQueryOutcome::NO_DEVICE:
RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::NO_DEVICE);
@@ -169,6 +170,38 @@ void RecordGetCharacteristicCharacteristic(const std::string& characteristic) {
HashUUID(characteristic));
}
+// getCharacteristics
+
+void RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome outcome) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Bluetooth.Web.GetCharacteristics.Outcome", static_cast<int>(outcome),
+ static_cast<int>(UMAGetCharacteristicOutcome::COUNT));
+}
+
+void RecordGetCharacteristicsOutcome(CacheQueryOutcome outcome) {
+ switch (outcome) {
+ case CacheQueryOutcome::SUCCESS:
+ case CacheQueryOutcome::BAD_RENDERER:
+ // No need to record a success or renderer crash.
+ NOTREACHED();
+ return;
+ case CacheQueryOutcome::NO_DEVICE:
+ RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome::NO_DEVICE);
+ return;
+ case CacheQueryOutcome::NO_SERVICE:
+ RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome::NO_SERVICE);
+ return;
+ case CacheQueryOutcome::NO_CHARACTERISTIC:
+ NOTREACHED();
+ return;
+ }
+}
+
+void RecordGetCharacteristicsCharacteristic(const std::string& characteristic) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Bluetooth.Web.GetCharacteristics.Characteristic",
+ HashUUID(characteristic));
+}
+
// GATT Operations
void RecordGATTOperationOutcome(UMAGATTOperation operation,
@@ -195,7 +228,8 @@ static UMAGATTOperationOutcome TranslateCacheQueryOutcomeToGATTOperationOutcome(
switch (outcome) {
case CacheQueryOutcome::SUCCESS:
case CacheQueryOutcome::BAD_RENDERER:
- NOTREACHED() << "No need to record success or renderer crash";
+ // No need to record a success or renderer crash.
+ NOTREACHED();
return UMAGATTOperationOutcome::NOT_SUPPORTED;
case CacheQueryOutcome::NO_DEVICE:
return UMAGATTOperationOutcome::NO_DEVICE;
diff --git a/chromium/content/browser/bluetooth/bluetooth_metrics.h b/chromium/content/browser/bluetooth/bluetooth_metrics.h
index fa508590177..872008b8513 100644
--- a/chromium/content/browser/bluetooth/bluetooth_metrics.h
+++ b/chromium/content/browser/bluetooth/bluetooth_metrics.h
@@ -31,6 +31,8 @@ enum class UMAWebBluetoothFunction {
CHARACTERISTIC_WRITE_VALUE = 5,
CHARACTERISTIC_START_NOTIFICATIONS = 6,
CHARACTERISTIC_STOP_NOTIFICATIONS = 7,
+ REMOTE_GATT_SERVER_DISCONNECT = 8,
+ SERVICE_GET_CHARACTERISTICS = 9,
// NOTE: Add new actions immediately above this line. Make sure to update
// the enum list in tools/metrics/histograms/histograms.xml accordingly.
COUNT
@@ -62,6 +64,12 @@ enum class UMARequestDeviceOutcome {
CHOSEN_DEVICE_VANISHED = 8,
BLUETOOTH_CHOOSER_CANCELLED = 9,
BLUETOOTH_CHOOSER_DENIED_PERMISSION = 10,
+ BLACKLISTED_SERVICE_IN_FILTER = 11,
+ BLUETOOTH_OVERVIEW_HELP_LINK_PRESSED = 12,
+ ADAPTER_OFF_HELP_LINK_PRESSED = 13,
+ NEED_LOCATION_HELP_LINK_PRESSED = 14,
+ BLUETOOTH_CHOOSER_POLICY_DISABLED = 15,
+ BLUETOOTH_GLOBALLY_DISABLED = 16,
// NOTE: Add new requestDevice() outcomes immediately above this line. Make
// sure to update the enum list in
// tools/metrics/histograms/histograms.xml accordingly.
@@ -145,6 +153,8 @@ enum class UMAGetCharacteristicOutcome {
NO_DEVICE = 1,
NO_SERVICE = 2,
NOT_FOUND = 3,
+ BLACKLISTED = 4,
+ NO_CHARACTERISTICS = 5,
// Note: Add new outcomes immediately above this line.
// Make sure to update the enum list in
// tools/metrisc/histogram/histograms.xml accordingly.
@@ -160,6 +170,17 @@ void RecordGetCharacteristicOutcome(CacheQueryOutcome outcome);
// Records the UUID of the characteristic used when calling getCharacteristic.
void RecordGetCharacteristicCharacteristic(const std::string& characteristic);
+// getCharacteristics() Metrics
+// There should be a call to this function for every call to
+// Send(BluetoothMsg_GetCharacteristicsSuccess) and
+// Send(BluetoothMsg_GetCharacteristicsError).
+void RecordGetCharacteristicsOutcome(UMAGetCharacteristicOutcome outcome);
+// Records the outcome of the cache query for getCharacteristics. Should only be
+// called if QueryCacheForService fails.
+void RecordGetCharacteristicsOutcome(CacheQueryOutcome outcome);
+// Records the UUID of the characteristic used when calling getCharacteristic.
+void RecordGetCharacteristicsCharacteristic(const std::string& characteristic);
+
// GATT Operations Metrics
// These are the possible outcomes when performing GATT operations i.e.
@@ -178,6 +199,7 @@ enum UMAGATTOperationOutcome {
NOT_AUTHORIZED = 10,
NOT_PAIRED = 11,
NOT_SUPPORTED = 12,
+ BLACKLISTED = 13,
// Note: Add new GATT Outcomes immediately above this line.
// Make sure to update the enum list in
// tools/metrics/histograms/histograms.xml accordingly.
diff --git a/chromium/content/browser/bluetooth/web_bluetooth_service_impl.cc b/chromium/content/browser/bluetooth/web_bluetooth_service_impl.cc
new file mode 100644
index 00000000000..ea627d222e0
--- /dev/null
+++ b/chromium/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -0,0 +1,156 @@
+// 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 "content/browser/bluetooth/web_bluetooth_service_impl.h"
+
+#include <vector>
+
+#include "content/browser/bluetooth/bluetooth_blacklist.h"
+#include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/browser/render_frame_host.h"
+#include "device/bluetooth/bluetooth_gatt_characteristic.h"
+
+using device::BluetoothGattService;
+
+namespace content {
+
+namespace {
+
+blink::mojom::WebBluetoothError TranslateGATTErrorAndRecord(
+ BluetoothGattService::GattErrorCode error_code,
+ UMAGATTOperation operation) {
+ switch (error_code) {
+ case BluetoothGattService::GATT_ERROR_UNKNOWN:
+ RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN);
+ return blink::mojom::WebBluetoothError::GATT_UNKNOWN_ERROR;
+ case BluetoothGattService::GATT_ERROR_FAILED:
+ RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED);
+ return blink::mojom::WebBluetoothError::GATT_UNKNOWN_FAILURE;
+ case BluetoothGattService::GATT_ERROR_IN_PROGRESS:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::IN_PROGRESS);
+ return blink::mojom::WebBluetoothError::GATT_OPERATION_IN_PROGRESS;
+ case BluetoothGattService::GATT_ERROR_INVALID_LENGTH:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::INVALID_LENGTH);
+ return blink::mojom::WebBluetoothError::GATT_INVALID_ATTRIBUTE_LENGTH;
+ case BluetoothGattService::GATT_ERROR_NOT_PERMITTED:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::NOT_PERMITTED);
+ return blink::mojom::WebBluetoothError::GATT_NOT_PERMITTED;
+ case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::NOT_AUTHORIZED);
+ return blink::mojom::WebBluetoothError::GATT_NOT_AUTHORIZED;
+ case BluetoothGattService::GATT_ERROR_NOT_PAIRED:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::NOT_PAIRED);
+ return blink::mojom::WebBluetoothError::GATT_NOT_PAIRED;
+ case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED:
+ RecordGATTOperationOutcome(operation,
+ UMAGATTOperationOutcome::NOT_SUPPORTED);
+ return blink::mojom::WebBluetoothError::GATT_NOT_SUPPORTED;
+ }
+ NOTREACHED();
+ return blink::mojom::WebBluetoothError::GATT_UNTRANSLATED_ERROR_CODE;
+}
+
+} // namespace
+
+using CacheQueryResult = BluetoothDispatcherHost::CacheQueryResult;
+
+WebBluetoothServiceImpl::WebBluetoothServiceImpl(
+ RenderFrameHost* render_frame_host,
+ blink::mojom::WebBluetoothServiceRequest request)
+ : render_frame_host_(render_frame_host),
+ binding_(this, std::move(request)),
+ weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+WebBluetoothServiceImpl::~WebBluetoothServiceImpl() {}
+
+void WebBluetoothServiceImpl::RemoteCharacteristicWriteValue(
+ const mojo::String& characteristic_instance_id,
+ mojo::Array<uint8_t> value,
+ const RemoteCharacteristicWriteValueCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RecordWebBluetoothFunctionCall(
+ UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE);
+
+ // We perform the length check on the renderer side. So if we
+ // get a value with length > 512, we can assume it's a hostile
+ // renderer and kill it.
+ if (value.size() > 512) {
+ CrashRendererAndClosePipe(bad_message::BDH_INVALID_WRITE_VALUE_LENGTH);
+ return;
+ }
+
+ const CacheQueryResult query_result =
+ GetBluetoothDispatcherHost()->QueryCacheForCharacteristic(
+ GetOrigin(), characteristic_instance_id);
+
+ if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) {
+ binding_.Close();
+ return;
+ }
+
+ if (query_result.outcome != CacheQueryOutcome::SUCCESS) {
+ RecordCharacteristicWriteValueOutcome(query_result.outcome);
+ callback.Run(query_result.GetWebError());
+ return;
+ }
+
+ if (BluetoothBlacklist::Get().IsExcludedFromWrites(
+ query_result.characteristic->GetUUID())) {
+ RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::BLACKLISTED);
+ callback.Run(blink::mojom::WebBluetoothError::BLACKLISTED_WRITE);
+ return;
+ }
+
+ query_result.characteristic->WriteRemoteCharacteristic(
+ value.To<std::vector<uint8_t>>(),
+ base::Bind(&WebBluetoothServiceImpl::OnWriteValueSuccess,
+ weak_ptr_factory_.GetWeakPtr(), callback),
+ base::Bind(&WebBluetoothServiceImpl::OnWriteValueFailed,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void WebBluetoothServiceImpl::OnWriteValueSuccess(
+ const RemoteCharacteristicWriteValueCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::SUCCESS);
+ callback.Run(blink::mojom::WebBluetoothError::SUCCESS);
+}
+
+void WebBluetoothServiceImpl::OnWriteValueFailed(
+ const RemoteCharacteristicWriteValueCallback& callback,
+ device::BluetoothGattService::GattErrorCode error_code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ callback.Run(TranslateGATTErrorAndRecord(
+ error_code, UMAGATTOperation::CHARACTERISTIC_WRITE));
+}
+
+RenderProcessHost* WebBluetoothServiceImpl::GetRenderProcessHost() {
+ return render_frame_host_->GetProcess();
+}
+
+BluetoothDispatcherHost* WebBluetoothServiceImpl::GetBluetoothDispatcherHost() {
+ RenderProcessHostImpl* render_process_host_impl =
+ static_cast<RenderProcessHostImpl*>(GetRenderProcessHost());
+ return render_process_host_impl->GetBluetoothDispatcherHost();
+}
+
+void WebBluetoothServiceImpl::CrashRendererAndClosePipe(
+ bad_message::BadMessageReason reason) {
+ bad_message::ReceivedBadMessage(GetRenderProcessHost(), reason);
+ binding_.Close();
+}
+
+url::Origin WebBluetoothServiceImpl::GetOrigin() {
+ return render_frame_host_->GetLastCommittedOrigin();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/bluetooth/web_bluetooth_service_impl.h b/chromium/content/browser/bluetooth/web_bluetooth_service_impl.h
new file mode 100644
index 00000000000..45f9e8c65bd
--- /dev/null
+++ b/chromium/content/browser/bluetooth/web_bluetooth_service_impl.h
@@ -0,0 +1,77 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_SERVICE_IMPL_H_
+
+#include "base/macros.h"
+#include "content/browser/bad_message.h"
+#include "content/common/content_export.h"
+#include "device/bluetooth/bluetooth_gatt_service.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace content {
+
+class BluetoothDispatcherHost;
+class RenderFrameHost;
+class RenderProcessHost;
+
+// Implementation of Mojo WebBluetoothService located in
+// third_party/WebKit/public/platform/modules/bluetooth.
+// It handles Web Bluetooth API requests coming from Blink / renderer
+// process and uses the platform abstraction of device/bluetooth.
+// WebBluetoothServiceImpl is not thread-safe and should be created on the
+// UI thread as required by device/bluetooth.
+// This class is instantiated on-demand via Mojo's ConnectToRemoteService
+// from the renderer when the first Web Bluetooth API request is handled.
+// RenderFrameHostImpl will create an instance of this class and keep
+// ownership of it.
+class WebBluetoothServiceImpl : public blink::mojom::WebBluetoothService {
+ public:
+ // |render_frame_host|: The RFH that owns this instance.
+ // |request|: The instance will be bound to this request's pipe.
+ WebBluetoothServiceImpl(RenderFrameHost* render_frame_host,
+ blink::mojom::WebBluetoothServiceRequest request);
+ ~WebBluetoothServiceImpl() override;
+
+ private:
+ // WebBluetoothService methods:
+ void RemoteCharacteristicWriteValue(
+ const mojo::String& characteristic_instance_id,
+ mojo::Array<uint8_t> value,
+ const RemoteCharacteristicWriteValueCallback& callback) override;
+
+ // Callbacks for BluetoothGattCharacteristic::WriteRemoteCharacteristic.
+ void OnWriteValueSuccess(
+ const RemoteCharacteristicWriteValueCallback& callback);
+ void OnWriteValueFailed(
+ const RemoteCharacteristicWriteValueCallback& callback,
+ device::BluetoothGattService::GattErrorCode error_code);
+
+ RenderProcessHost* GetRenderProcessHost();
+ BluetoothDispatcherHost* GetBluetoothDispatcherHost();
+ void CrashRendererAndClosePipe(bad_message::BadMessageReason reason);
+ url::Origin GetOrigin();
+
+ // The RFH that owns this instance.
+ RenderFrameHost* render_frame_host_;
+
+ // The lifetime of this instance is exclusively managed by the RFH that
+ // owns it so we use a "Binding" as opposed to a "StrongBinding" which deletes
+ // the service on pipe connection errors.
+ mojo::Binding<blink::mojom::WebBluetoothService> binding_;
+
+ base::WeakPtrFactory<WebBluetoothServiceImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebBluetoothServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/browser_child_process_host_impl.cc b/chromium/content/browser/browser_child_process_host_impl.cc
index 9461b624195..64b81eeb361 100644
--- a/chromium/content/browser/browser_child_process_host_impl.cc
+++ b/chromium/content/browser/browser_child_process_host_impl.cc
@@ -8,10 +8,12 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/dump_without_crashing.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -35,18 +37,12 @@
#include "content/public/common/result_codes.h"
#include "ipc/attachment_broker.h"
#include "ipc/attachment_broker_privileged.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/embedder.h"
#if defined(OS_MACOSX)
#include "content/browser/mach_broker_mac.h"
#endif
-
-#if defined(MOJO_SHELL_CLIENT)
-#include "content/browser/mojo/mojo_shell_client_host.h"
-#include "content/common/mojo/mojo_shell_connection_impl.h"
-#endif
-
namespace content {
namespace {
@@ -132,7 +128,8 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
: data_(process_type),
delegate_(delegate),
power_monitor_message_broadcaster_(this),
- is_channel_connected_(false) {
+ is_channel_connected_(false),
+ notify_child_disconnected_(false) {
data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
#if USE_ATTACHMENT_BROKER
@@ -140,12 +137,12 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
// child process. This ensures that when a test is being run in one of the
// single process modes, the global attachment broker is the privileged
// attachment broker, rather than an unprivileged attachment broker.
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded(
MachBroker::GetInstance());
#else
IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded();
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif // defined(OS_MACOSX)
#endif // USE_ATTACHMENT_BROKER
child_process_host_.reset(ChildProcessHost::Create(this));
@@ -162,6 +159,11 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
g_child_process_list.Get().remove(this);
+
+ if (notify_child_disconnected_) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&NotifyProcessHostDisconnected, data_));
+ }
}
// static
@@ -176,6 +178,28 @@ void BrowserChildProcessHostImpl::TerminateAll() {
}
}
+// static
+void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(
+ base::CommandLine* cmd_line) {
+ std::string enabled_features;
+ std::string disabled_features;
+ base::FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
+ &disabled_features);
+ if (!enabled_features.empty())
+ cmd_line->AppendSwitchASCII(switches::kEnableFeatures, enabled_features);
+ if (!disabled_features.empty())
+ cmd_line->AppendSwitchASCII(switches::kDisableFeatures, disabled_features);
+
+ // If we run base::FieldTrials, we want to pass to their state to the
+ // child process so that it can act in accordance with each state.
+ std::string field_trial_states;
+ base::FieldTrialList::AllStatesToString(&field_trial_states);
+ if (!field_trial_states.empty()) {
+ cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
+ field_trial_states);
+ }
+}
+
void BrowserChildProcessHostImpl::Launch(
SandboxedProcessLauncherDelegate* delegate,
base::CommandLine* cmd_line,
@@ -195,11 +219,11 @@ void BrowserChildProcessHostImpl::Launch(
switches::kTraceToConsole,
switches::kV,
switches::kVModule,
- "use-new-edk", // TODO(use_chrome_edk): temporary.
};
cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
arraysize(kForwardSwitches));
+ notify_child_disconnected_ = true;
child_process_.reset(new ChildProcessLauncher(
delegate,
cmd_line,
@@ -256,13 +280,6 @@ void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
child_process_host_->AddFilter(filter->GetFilter());
}
-void BrowserChildProcessHostImpl::NotifyProcessInstanceCreated(
- const ChildProcessData& data) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(),
- BrowserChildProcessInstanceCreated(data));
-}
-
void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
int process_type) {
UMA_HISTOGRAM_ENUMERATION("ChildProcess.BadMessgeTerminated", process_type,
@@ -287,6 +304,7 @@ void BrowserChildProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
is_channel_connected_ = true;
+ notify_child_disconnected_ = true;
#if defined(OS_WIN)
// From this point onward, the exit of the child process is detected by an
@@ -394,8 +412,6 @@ void BrowserChildProcessHostImpl::OnChildDisconnected() {
}
#endif
}
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&NotifyProcessHostDisconnected, data_));
delete delegate_; // Will delete us
}
@@ -405,6 +421,7 @@ bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
void BrowserChildProcessHostImpl::OnProcessLaunchFailed() {
delegate_->OnProcessLaunchFailed();
+ notify_child_disconnected_ = false;
delete delegate_; // Will delete us
}
@@ -414,25 +431,10 @@ void BrowserChildProcessHostImpl::OnProcessLaunched() {
const base::Process& process = child_process_->GetProcess();
DCHECK(process.IsValid());
- if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
- mojo::embedder::ScopedPlatformHandle client_pipe;
-#if defined(MOJO_SHELL_CLIENT)
- if (IsRunningInMojoShell()) {
- client_pipe = RegisterProcessWithBroker(process.Pid());
- } else
-#endif
- {
- client_pipe = mojo::embedder::ChildProcessLaunched(process.Handle());
- }
- Send(new ChildProcessMsg_SetMojoParentPipeHandle(
- IPC::GetFileHandleForProcess(
-#if defined(OS_WIN)
- client_pipe.release().handle,
-#else
- client_pipe.release().fd,
-#endif
- process.Handle(), true)));
- }
+ mojo::edk::ScopedPlatformHandle client_pipe =
+ mojo::edk::ChildProcessLaunched(process.Handle());
+ Send(new ChildProcessMsg_SetMojoParentPipeHandle(
+ IPC::GetPlatformFileForTransit(client_pipe.release().handle, true)));
#if defined(OS_WIN)
// Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
diff --git a/chromium/content/browser/browser_child_process_host_impl.h b/chromium/content/browser/browser_child_process_host_impl.h
index a5f3b6d528b..ce551a5da86 100644
--- a/chromium/content/browser/browser_child_process_host_impl.h
+++ b/chromium/content/browser/browser_child_process_host_impl.h
@@ -54,6 +54,11 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// instance.
static void TerminateAll();
+ // Copies kEnableFeatures and kDisableFeatures to the command line. Generates
+ // them from the FeatureList override state, to take into account overrides
+ // from FieldTrials.
+ static void CopyFeatureAndFieldTrialFlags(base::CommandLine* cmd_line);
+
// BrowserChildProcessHost implementation:
bool Send(IPC::Message* message) override;
void Launch(SandboxedProcessLauncherDelegate* delegate,
@@ -89,9 +94,6 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// Adds an IPC message filter.
void AddFilter(BrowserMessageFilter* filter);
- // Called when an instance of a particular child is created in a page.
- static void NotifyProcessInstanceCreated(const ChildProcessData& data);
-
static void HistogramBadMessageTerminated(int process_type);
BrowserChildProcessHostDelegate* delegate() const { return delegate_; }
@@ -135,6 +137,7 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
#endif
bool is_channel_connected_;
+ bool notify_child_disconnected_;
};
} // namespace content
diff --git a/chromium/content/browser/browser_context.cc b/chromium/content/browser/browser_context.cc
index fc3f644fba2..4b8396ed03e 100644
--- a/chromium/content/browser/browser_context.cc
+++ b/chromium/content/browser/browser_context.cc
@@ -6,11 +6,15 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
+#include <limits>
#include <utility>
+#include "base/guid.h"
+#include "base/lazy_instance.h"
+#include "base/rand_util.h"
#include "build/build_config.h"
-
-#if !defined(OS_IOS)
+#include "components/profile_service/user_id_map.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
@@ -22,7 +26,6 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/site_instance.h"
-#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/ssl/channel_id_service.h"
#include "net/ssl/channel_id_store.h"
@@ -30,20 +33,24 @@
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/database/database_tracker.h"
#include "storage/browser/fileapi/external_mount_points.h"
-#endif // !OS_IOS
using base::UserDataAdapter;
namespace content {
-// Only ~BrowserContext() is needed on iOS.
-#if !defined(OS_IOS)
namespace {
+base::LazyInstance<std::set<std::string>> g_used_user_ids =
+ LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::vector<std::pair<BrowserContext*, std::string>>>
+g_context_to_user_id = LAZY_INSTANCE_INITIALIZER;
+
// Key names on BrowserContext.
const char kDownloadManagerKeyName[] = "download_manager";
const char kStoragePartitionMapKeyName[] = "content_storage_partition_map";
+const char kMojoWasInitialized[] = "mojo-was-initialized";
+
#if defined(OS_CHROMEOS)
const char kMountPointsKey[] = "mount_points";
#endif // defined(OS_CHROMEOS)
@@ -78,8 +85,7 @@ void SaveSessionStateOnIOThread(
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
AppCacheServiceImpl* appcache_service) {
net::URLRequestContext* context = context_getter->GetURLRequestContext();
- context->cookie_store()->GetCookieMonster()->
- SetForceKeepSessionState();
+ context->cookie_store()->SetForceKeepSessionState();
context->channel_id_service()->GetChannelIDStore()->
SetForceKeepSessionState();
appcache_service->set_force_keep_session_state();
@@ -255,11 +261,12 @@ void BrowserContext::DeliverPushMessage(
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const std::string& data,
+ const PushEventPayload& payload,
const base::Callback<void(PushDeliveryStatus)>& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- PushMessagingRouter::DeliverMessage(
- browser_context, origin, service_worker_registration_id, data, callback);
+ PushMessagingRouter::DeliverMessage(browser_context, origin,
+ service_worker_registration_id, payload,
+ callback);
}
// static
@@ -322,13 +329,44 @@ void BrowserContext::SetDownloadManagerForTesting(
SetDownloadManager(browser_context, download_manager);
}
-#endif // !OS_IOS
+void BrowserContext::Initialize(
+ BrowserContext* browser_context,
+ const base::FilePath& path) {
+ // Generate a GUID for |browser_context| to use as the Mojo user id.
+ std::string new_id = base::GenerateGUID();
+ while (g_used_user_ids.Get().find(new_id) != g_used_user_ids.Get().end())
+ new_id = base::GenerateGUID();
+
+ g_used_user_ids.Get().insert(new_id);
+ g_context_to_user_id.Get().push_back(std::make_pair(browser_context, new_id));
+
+ profile::AssociateMojoUserIDWithProfileDir(new_id, path);
+ browser_context->SetUserData(kMojoWasInitialized,
+ new base::SupportsUserData::Data);
+}
+
+const std::string& BrowserContext::GetMojoUserIdFor(
+ BrowserContext* browser_context) {
+ CHECK(browser_context->GetUserData(kMojoWasInitialized))
+ << "Attempting to get the mojo user id for a BrowserContext that was "
+ << "never Initialize()ed.";
+
+ auto it = std::find_if(
+ g_context_to_user_id.Get().begin(),
+ g_context_to_user_id.Get().end(),
+ [&browser_context](const std::pair<BrowserContext*, std::string>& p) {
+ return p.first == browser_context; });
+ CHECK(it != g_context_to_user_id.Get().end());
+ return it->second;
+}
BrowserContext::~BrowserContext() {
-#if !defined(OS_IOS)
+ CHECK(GetUserData(kMojoWasInitialized))
+ << "Attempting to destroy a BrowserContext that never called "
+ << "Initialize()";
+
if (GetUserData(kDownloadManagerKeyName))
GetDownloadManager(this)->Shutdown();
-#endif
}
} // namespace content
diff --git a/chromium/content/browser/browser_main.cc b/chromium/content/browser/browser_main.cc
index d0897f1d650..459bde05a4d 100644
--- a/chromium/content/browser/browser_main.cc
+++ b/chromium/content/browser/browser_main.cc
@@ -4,6 +4,7 @@
#include "content/browser/browser_main.h"
+#include "base/memory/scoped_ptr.h"
#include "base/trace_event/trace_event.h"
#include "content/common/content_constants_internal.h"
#include "content/public/browser/browser_main_runner.h"
diff --git a/chromium/content/browser/browser_main_loop.cc b/chromium/content/browser/browser_main_loop.cc
index 63ee2cca5d9..175e9d69f7e 100644
--- a/chromium/content/browser/browser_main_loop.cc
+++ b/chromium/content/browser/browser_main_loop.cc
@@ -32,6 +32,7 @@
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "components/tracing/process_metrics_memory_dump_provider.h"
#include "components/tracing/trace_config_file.h"
#include "components/tracing/trace_to_console.h"
#include "components/tracing/tracing_switches.h"
@@ -52,14 +53,17 @@
#include "content/browser/mojo/mojo_shell_context.h"
#include "content/browser/net/browser_online_state_observer.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/speech/speech_recognition_manager_impl.h"
#include "content/browser/startup_task_runner.h"
#include "content/browser/time_zone_monitor.h"
+#include "content/browser/utility_process_host_impl.h"
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/url_data_manager.h"
#include "content/common/content_switches_internal.h"
#include "content/common/host_discardable_shared_memory_manager.h"
#include "content/common/host_shared_bitmap_manager.h"
+#include "content/common/mojo/mojo_shell_connection_impl.h"
#include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
@@ -73,6 +77,8 @@
#include "media/base/media.h"
#include "media/base/user_input_monitor.h"
#include "media/midi/midi_manager.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/shell/public/cpp/shell.h"
#include "net/base/network_change_notifier.h"
#include "net/socket/client_socket_factory.h"
#include "net/ssl/ssl_config_service.h"
@@ -81,7 +87,7 @@
#include "sql/sql_memory_dump_provider.h"
#include "ui/base/clipboard/clipboard.h"
-#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(USE_AURA) || defined(OS_MACOSX)
#include "content/browser/compositor/image_transport_factory.h"
#endif
@@ -90,10 +96,6 @@
#include "ui/aura/env.h"
#endif
-#if !defined(OS_IOS)
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#endif
-
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#include "components/tracing/graphics_memory_dump_provider_android.h"
@@ -106,18 +108,18 @@
#include "ui/gl/gl_surface.h"
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
#include "base/memory/memory_pressure_monitor_mac.h"
#include "content/browser/bootstrap_sandbox_manager_mac.h"
#include "content/browser/cocoa/system_hotkey_helper_mac.h"
-#include "content/browser/compositor/browser_compositor_view_mac.h"
+#include "content/browser/mach_broker_mac.h"
+#include "content/browser/renderer_host/browser_compositor_view_mac.h"
#include "content/browser/theme_helper_mac.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#endif
#if defined(USE_OZONE)
#include "ui/ozone/public/client_native_pixmap_factory.h"
-#include "ui/ozone/public/ozone_platform.h"
#endif
#if defined(OS_WIN)
@@ -126,7 +128,8 @@
#include <shellapi.h>
#include "base/memory/memory_pressure_monitor_win.h"
-#include "content/browser/system_message_window_win.h"
+#include "base/win/windows_version.h"
+#include "content/browser/screen_orientation/screen_orientation_delegate_win.h"
#include "content/common/sandbox_win.h"
#include "net/base/winsock_init.h"
#include "ui/base/l10n/l10n_util_win.h"
@@ -141,26 +144,29 @@
#include <glib-object.h>
#endif
-#if defined(OS_LINUX) && defined(USE_UDEV)
-#include "content/browser/device_monitor_udev.h"
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-#include "content/browser/device_monitor_mac.h"
+#if defined(OS_WIN)
+#include "media/capture/system_message_window_win.h"
+#elif defined(OS_LINUX) && defined(USE_UDEV)
+#include "media/capture/device_monitor_udev.h"
+#elif defined(OS_MACOSX)
+#include "media/capture/device_monitor_mac.h"
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include "content/browser/renderer_host/render_sandbox_host_linux.h"
#include "content/browser/zygote_host/zygote_host_impl_linux.h"
#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
-#endif
+
+#if !defined(OS_ANDROID)
+#include "content/public/browser/zygote_handle_linux.h"
+#endif // !defined(OS_ANDROID)
+#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
+
#if defined(ENABLE_PLUGINS)
#include "content/browser/plugin_service_impl.h"
#endif
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif
-
#if defined(USE_X11)
#include "ui/base/x/x11_util_internal.h"
#include "ui/gfx/x/x11_connection.h"
@@ -173,11 +179,7 @@
#endif
#if defined(MOJO_SHELL_CLIENT)
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "content/common/mojo/mojo_shell_connection_impl.h"
-#include "mojo/converters/network/network_type_converters.h"
-#include "mojo/shell/public/cpp/application_impl.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "mojo/shell/public/cpp/connector.h"
#include "ui/views/mus/window_manager_connection.h"
#endif
@@ -220,6 +222,8 @@ void SetupSandbox(const base::CommandLine& parsed_command_line) {
// Tickle the sandbox host and zygote host so they fork now.
RenderSandboxHostLinux::GetInstance()->Init();
ZygoteHostImpl::GetInstance()->Init(sandbox_binary.value());
+ *GetGenericZygote() = CreateZygote();
+ RenderProcessHostImpl::EarlyZygoteLaunch();
}
#endif
@@ -332,13 +336,11 @@ NOINLINE void ResetThread_IO(scoped_ptr<BrowserProcessSubThread> thread) {
thread.reset();
}
-#if !defined(OS_IOS)
NOINLINE void ResetThread_IndexedDb(scoped_ptr<base::Thread> thread) {
volatile int inhibit_comdat = __LINE__;
ALLOW_UNUSED_LOCAL(inhibit_comdat);
thread.reset();
}
-#endif
MSVC_POP_WARNING()
MSVC_ENABLE_OPTIMIZE();
@@ -383,13 +385,11 @@ class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver {
void WillProcessTask(const base::PendingTask& pending_task) override {}
void DidProcessTask(const base::PendingTask& pending_task) override {
-#if !defined(OS_IOS) // No ProcessMetrics on IOS.
scoped_ptr<base::ProcessMetrics> process_metrics(
base::ProcessMetrics::CreateCurrentProcessMetrics());
size_t private_bytes;
process_metrics->GetMemoryBytes(&private_bytes, NULL);
LOCAL_HISTOGRAM_MEMORY_KB("Memory.BrowserUsed", private_bytes >> 10);
-#endif
}
private:
DISALLOW_COPY_AND_ASSIGN(MemoryObserver);
@@ -420,9 +420,7 @@ BrowserMainLoop::BrowserMainLoop(const MainFunctionParams& parameters)
BrowserMainLoop::~BrowserMainLoop() {
DCHECK_EQ(this, g_current_browser_main_loop);
-#if !defined(OS_IOS)
ui::Clipboard::DestroyClipboardForCurrentThread();
-#endif // !defined(OS_IOS)
g_current_browser_main_loop = NULL;
}
@@ -497,7 +495,6 @@ void BrowserMainLoop::EarlyInitialization() {
crypto::EnsureNSPRInit();
#endif
-#if !defined(OS_IOS)
if (parsed_command_line_.HasSwitch(switches::kRendererProcessLimit)) {
std::string limit_string = parsed_command_line_.GetSwitchValueASCII(
switches::kRendererProcessLimit);
@@ -506,7 +503,6 @@ void BrowserMainLoop::EarlyInitialization() {
RenderProcessHost::SetMaxRendererProcessCount(process_limit);
}
}
-#endif // !defined(OS_IOS)
if (parts_)
parts_->PostEarlyInitialization();
@@ -563,8 +559,6 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:NetworkChangeNotifier");
network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
}
-
-#if !defined(OS_IOS)
{
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MediaFeatures");
media::InitializeMediaLibrary();
@@ -586,10 +580,10 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
new base::trace_event::TraceEventSystemStatsMonitor(
base::ThreadTaskRunnerHandle::Get()));
}
-#endif // !defined(OS_IOS)
#if defined(OS_WIN)
- system_message_window_.reset(new SystemMessageWindowWin);
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+ screen_orientation_delegate_.reset(new ScreenOrientationDelegateWin());
#endif
// TODO(boliu): kSingleProcess check is a temporary workaround for
@@ -622,7 +616,6 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
tracing::TraceConfigFile::GetInstance()->GetTraceConfig(),
TracingController::StartTracingDoneCallback());
}
-#if !defined(OS_IOS)
// Start tracing to a file for certain duration if needed. Only do this after
// starting the main message loop to avoid calling
// MessagePumpForUI::ScheduleWork() before MessagePumpForUI::Start() as it
@@ -631,20 +624,19 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracingForDuration");
InitStartupTracingForDuration(parsed_command_line_);
}
-#endif // !defined(OS_IOS)
#if defined(OS_ANDROID)
{
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTextureManager");
if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
- SurfaceTextureManager::SetInstance(
+ gpu::SurfaceTextureManager::SetInstance(
InProcessSurfaceTextureManager::GetInstance());
} else {
- SurfaceTextureManager::SetInstance(
+ gpu::SurfaceTextureManager::SetInstance(
BrowserSurfaceTextureManager::GetInstance());
}
}
-#if !defined(USE_AURA)
+
if (!parsed_command_line_.HasSwitch(
switches::kDisableScreenOrientationLock)) {
TRACE_EVENT0("startup",
@@ -654,9 +646,8 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
ScreenOrientationProvider::SetDelegate(screen_orientation_delegate_.get());
}
#endif
-#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
if (BootstrapSandboxManager::ShouldEnable()) {
TRACE_EVENT0("startup",
"BrowserMainLoop::Subsystem:BootstrapSandbox");
@@ -668,8 +659,6 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
client_native_pixmap_factory_ = ui::ClientNativePixmapFactory::Create();
ui::ClientNativePixmapFactory::SetInstance(
client_native_pixmap_factory_.get());
- ui::ClientNativePixmapFactory::GetInstance()->Initialize(
- ui::OzonePlatform::GetInstance()->OpenClientNativePixmapDevice());
#endif
if (parsed_command_line_.HasSwitch(switches::kMemoryMetrics)) {
@@ -687,6 +676,8 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
// Enable memory-infra dump providers.
InitSkiaEventTracer();
+ tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
+ base::kNullProcessId);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
HostSharedBitmapManager::current(), "HostSharedBitmapManager", nullptr);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
@@ -704,9 +695,13 @@ int BrowserMainLoop::PreCreateThreads() {
result_code_ = parts_->PreCreateThreads();
}
- // Initialize an instance of FeatureList. This will be a no-op if an instance
- // was already set up by the embedder.
- base::FeatureList::InitializeInstance();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ // Note that we do not initialize a new FeatureList when calling this for
+ // the second time.
+ base::FeatureList::InitializeInstance(
+ command_line->GetSwitchValueASCII(switches::kEnableFeatures),
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures));
// TODO(chrisha): Abstract away this construction mess to a helper function,
// once MemoryPressureMonitor is made a concrete class.
@@ -715,7 +710,7 @@ int BrowserMainLoop::PreCreateThreads() {
memory_pressure_monitor_.reset(new base::chromeos::MemoryPressureMonitor(
chromeos::switches::GetMemoryPressureThresholds()));
}
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#elif defined(OS_MACOSX)
memory_pressure_monitor_.reset(new base::mac::MemoryPressureMonitor());
#elif defined(OS_WIN)
memory_pressure_monitor_.reset(CreateWinMemoryPressureMonitor(
@@ -733,7 +728,7 @@ int BrowserMainLoop::PreCreateThreads() {
}
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
// The WindowResizeHelper allows the UI thread to wait on specific renderer
// and GPU messages from the IO thread. Initializing it before the IO thread
// starts ensures the affected IO thread messages always have somewhere to go.
@@ -746,7 +741,7 @@ int BrowserMainLoop::PreCreateThreads() {
// 2) Must be after parts_->PreCreateThreads to pick up chrome://flags.
GpuDataManagerImpl::GetInstance()->Initialize();
-#if !defined(OS_IOS) && (!defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID))
+#if !defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID)
// Single-process is an unsupported and not fully tested mode, so
// don't enable it for official Chrome builds (except on Android).
if (parsed_command_line_.HasSwitch(switches::kSingleProcess))
@@ -868,7 +863,9 @@ int BrowserMainLoop::CreateThreads() {
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::CACHE");
thread_to_start = &cache_thread_;
+#if defined(OS_WIN)
options = io_message_loop_options;
+#endif // defined(OS_WIN)
options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::IO:
@@ -877,7 +874,7 @@ int BrowserMainLoop::CreateThreads() {
"Thread", "BrowserThread::IO");
thread_to_start = &io_thread_;
options = io_message_loop_options;
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
// Up the priority of the |io_thread_| as some of its IPCs relate to
// display tasks.
options.priority = base::ThreadPriority::DISPLAY;
@@ -908,17 +905,19 @@ int BrowserMainLoop::CreateThreads() {
}
int BrowserMainLoop::PreMainMessageLoopRun() {
-#if defined(MOJO_SHELL_CLIENT)
if (IsRunningInMojoShell()) {
- mojo::embedder::PreInitializeChildProcess();
- MojoShellConnectionImpl::Create();
- MojoShellConnectionImpl::Get()->BindToCommandLinePlatformChannel();
-#if defined(USE_AURA)
- views::WindowManagerConnection::Create(
- MojoShellConnection::Get()->GetApplication());
+ if (!MojoShellConnectionImpl::CreateUsingFactory()) {
+ mojo::edk::SetParentPipeHandleFromCommandLine();
+ MojoShellConnectionImpl::Create();
+ MojoShellConnectionImpl::Get()->BindToRequestFromCommandLine();
+ }
+#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+ if (MojoShellConnection::Get()) {
+ views::WindowManagerConnection::Create(
+ MojoShellConnection::Get()->GetConnector());
+ }
#endif
}
-#endif
if (parts_) {
TRACE_EVENT0("startup",
@@ -966,16 +965,11 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
true));
-#if defined(MOJO_SHELL_CLIENT)
- MojoShellConnection::Destroy();
-#endif
- mojo_ipc_support_.reset();
- mojo_shell_context_.reset();
+ if (IsRunningInMojoShell())
+ MojoShellConnection::Destroy();
-#if !defined(OS_IOS)
if (RenderProcessHost::run_renderer_in_process())
RenderProcessHostImpl::ShutDownInProcessRenderer();
-#endif
if (parts_) {
TRACE_EVENT0("shutdown",
@@ -989,7 +983,6 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
system_stats_monitor_.reset();
-#if !defined(OS_IOS)
// Destroying the GpuProcessHostUIShims on the UI thread posts a task to
// delete related objects on the GPU thread. This must be done before
// stopping the GPU thread. The GPU thread will close IPC channels to renderer
@@ -1034,7 +1027,10 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
#elif defined(OS_MACOSX)
device_monitor_mac_.reset();
#endif
-#endif // !defined(OS_IOS)
+
+ // Shutdown Mojo shell and IPC.
+ mojo_shell_context_.reset();
+ mojo_ipc_support_.reset();
// Must be size_t so we can subtract from it.
for (size_t thread_id = BrowserThread::ID_COUNT - 1;
@@ -1065,12 +1061,10 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
}
case BrowserThread::FILE: {
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:FileThread");
-#if !defined(OS_IOS)
// Clean up state that lives on or uses the file_thread_ before
// it goes away.
if (resource_dispatcher_host_)
resource_dispatcher_host_.get()->save_file_manager()->Shutdown();
-#endif // !defined(OS_IOS)
ResetThread_FILE(std::move(file_thread_));
break;
}
@@ -1102,13 +1096,10 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
break;
}
}
-
-#if !defined(OS_IOS)
{
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IndexedDBThread");
ResetThread_IndexedDb(std::move(indexed_db_thread_));
}
-#endif
// Close the blocking I/O pool after the other threads. Other threads such
// as the I/O thread may need to schedule work like closing files or flushing
@@ -1120,8 +1111,6 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:ThreadPool");
BrowserThreadImpl::ShutdownThreadPool();
}
-
-#if !defined(OS_IOS)
// Must happen after the IO thread is shutdown since this may be accessed from
// it.
{
@@ -1150,7 +1139,6 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DeleteDataSources");
URLDataManager::DeleteDataSources();
}
-#endif // !defined(OS_IOS)
if (parts_) {
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:PostDestroyThreads");
@@ -1177,21 +1165,28 @@ void BrowserMainLoop::InitializeMainThread() {
int BrowserMainLoop::BrowserThreadsStarted() {
TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted");
-#if !defined(OS_IOS)
+ // Bring up Mojo IPC and shell as early as possible.
+ mojo_ipc_support_.reset(new IPC::ScopedIPCSupport(
+ BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
+ ->task_runner()));
+ mojo_shell_context_.reset(new MojoShellContext(file_thread_->task_runner(),
+ db_thread_->task_runner()));
+#if defined(OS_MACOSX)
+ mojo::edk::SetMachPortProvider(MachBroker::GetInstance());
+#endif // defined(OS_MACOSX)
+
indexed_db_thread_.reset(new base::Thread("IndexedDB"));
indexed_db_thread_->Start();
-#endif
-#if !defined(OS_IOS)
HistogramSynchronizer::GetInstance();
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
// Up the priority of the UI thread.
base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY);
#endif
bool always_uses_gpu = true;
bool established_gpu_channel = false;
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
// TODO(crbug.com/439322): This should be set to |true|.
established_gpu_channel = false;
BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
@@ -1238,10 +1233,13 @@ int BrowserMainLoop::BrowserThreadsStarted() {
midi_manager_.reset(media::midi::MidiManager::Create());
}
-#if defined(OS_LINUX) && defined(USE_UDEV)
- device_monitor_linux_.reset(new DeviceMonitorLinux());
+#if defined(OS_WIN)
+ system_message_window_.reset(new media::SystemMessageWindowWin);
+#elif defined(OS_LINUX) && defined(USE_UDEV)
+ device_monitor_linux_.reset(
+ new media::DeviceMonitorLinux(io_thread_->task_runner()));
#elif defined(OS_MACOSX)
- device_monitor_mac_.reset(new DeviceMonitorMac());
+ device_monitor_mac_.reset(new media::DeviceMonitorMac());
#endif
#if defined(OS_WIN)
@@ -1316,13 +1314,6 @@ int BrowserMainLoop::BrowserThreadsStarted() {
SystemHotkeyHelperMac::GetInstance()->DeferredLoadSystemHotkeys();
#endif // defined(OS_MACOSX)
-#endif // !defined(OS_IOS)
-
- mojo_shell_context_.reset(new MojoShellContext);
- mojo_ipc_support_.reset(new IPC::ScopedIPCSupport(
- BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
- ->task_runner()));
-
return result_code_;
}
@@ -1409,7 +1400,7 @@ base::FilePath BrowserMainLoop::GetStartupTraceFileName(
return trace_file;
if (trace_file.empty()) {
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
TracingControllerAndroid::GenerateTracingFilePath(&trace_file);
#else
// Default to saving the startup trace into the current dir.
@@ -1417,7 +1408,7 @@ base::FilePath BrowserMainLoop::GetStartupTraceFileName(
#endif
}
} else {
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
TracingControllerAndroid::GenerateTracingFilePath(&trace_file);
#else
trace_file = tracing::TraceConfigFile::GetInstance()->GetResultFile();
diff --git a/chromium/content/browser/browser_main_loop.h b/chromium/content/browser/browser_main_loop.h
index ae07f764237..e8a13a03881 100644
--- a/chromium/content/browser/browser_main_loop.h
+++ b/chromium/content/browser/browser_main_loop.h
@@ -33,7 +33,15 @@ class ScopedIPCSupport;
namespace media {
class AudioManager;
+#if defined(OS_WIN)
+class SystemMessageWindowWin;
+#elif defined(OS_LINUX) && defined(USE_UDEV)
+class DeviceMonitorLinux;
+#endif
class UserInputMonitor;
+#if defined(OS_MACOSX)
+class DeviceMonitorMac;
+#endif
namespace midi {
class MidiManager;
} // namespace midi
@@ -63,12 +71,8 @@ struct MainFunctionParams;
#if defined(OS_ANDROID)
class ScreenOrientationDelegate;
-#elif defined(OS_LINUX)
-class DeviceMonitorLinux;
-#elif defined(OS_MACOSX)
-class DeviceMonitorMac;
#elif defined(OS_WIN)
-class SystemMessageWindowWin;
+class ScreenOrientationDelegate;
#endif
// Implements the main browser loop stages called from BrowserMainRunner.
@@ -130,7 +134,7 @@ class CONTENT_EXPORT BrowserMainLoop {
void StopStartupTracingTimer();
#if defined(OS_MACOSX) && !defined(OS_IOS)
- DeviceMonitorMac* device_monitor_mac() const {
+ media::DeviceMonitorMac* device_monitor_mac() const {
return device_monitor_mac_.get();
}
#endif
@@ -198,7 +202,7 @@ class CONTENT_EXPORT BrowserMainLoop {
system_stats_monitor_;
#if defined(OS_WIN)
- scoped_ptr<SystemMessageWindowWin> system_message_window_;
+ scoped_ptr<ScreenOrientationDelegate> screen_orientation_delegate_;
#endif
#if defined(OS_ANDROID)
@@ -249,10 +253,12 @@ class CONTENT_EXPORT BrowserMainLoop {
scoped_ptr<media::midi::MidiManager> midi_manager_;
-#if defined(USE_UDEV)
- scoped_ptr<DeviceMonitorLinux> device_monitor_linux_;
+#if defined(OS_WIN)
+ scoped_ptr<media::SystemMessageWindowWin> system_message_window_;
+#elif defined(OS_LINUX) && defined(USE_UDEV)
+ scoped_ptr<media::DeviceMonitorLinux> device_monitor_linux_;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
- scoped_ptr<DeviceMonitorMac> device_monitor_mac_;
+ scoped_ptr<media::DeviceMonitorMac> device_monitor_mac_;
#endif
#if defined(USE_OZONE)
scoped_ptr<ui::ClientNativePixmapFactory> client_native_pixmap_factory_;
diff --git a/chromium/content/browser/browser_main_runner.cc b/chromium/content/browser/browser_main_runner.cc
index 2585c8dd870..de130940eff 100644
--- a/chromium/content/browser/browser_main_runner.cc
+++ b/chromium/content/browser/browser_main_runner.cc
@@ -15,6 +15,7 @@
#include "base/profiler/scoped_profile.h"
#include "base/profiler/scoped_tracker.h"
#include "base/time/time.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
#include "build/build_config.h"
@@ -34,12 +35,8 @@
#endif
#if defined(OS_WIN)
-#include "base/win/win_util.h"
#include "base/win/windows_version.h"
-#include "net/cert/sha256_legacy_support_win.h"
-#include "sandbox/win/src/sidestep/preamble_patcher.h"
#include "ui/base/win/scoped_ole_initializer.h"
-#include "ui/gfx/switches.h"
#include "ui/gfx/win/direct_write.h"
#endif
@@ -48,86 +45,7 @@ namespace content {
namespace {
bool g_exited_main_message_loop = false;
-
-#if defined(OS_WIN)
-#if !defined(_WIN64)
-// Pointer to the original CryptVerifyCertificateSignatureEx function.
-net::sha256_interception::CryptVerifyCertificateSignatureExFunc
- g_real_crypt_verify_signature_stub = NULL;
-
-// Stub function that is called whenever the Crypt32 function
-// CryptVerifyCertificateSignatureEx is called. It just defers to net to perform
-// the actual verification.
-BOOL WINAPI CryptVerifyCertificateSignatureExStub(
- HCRYPTPROV_LEGACY provider,
- DWORD encoding_type,
- DWORD subject_type,
- void* subject_data,
- DWORD issuer_type,
- void* issuer_data,
- DWORD flags,
- void* extra) {
- return net::sha256_interception::CryptVerifyCertificateSignatureExHook(
- g_real_crypt_verify_signature_stub, provider, encoding_type, subject_type,
- subject_data, issuer_type, issuer_data, flags, extra);
-}
-#endif // !defined(_WIN64)
-
-// If necessary, install an interception
-void InstallSha256LegacyHooks() {
-#if defined(_WIN64)
- // Interception on x64 is not supported.
- return;
-#else
- if (base::win::MaybeHasSHA256Support())
- return;
-
- net::sha256_interception::CryptVerifyCertificateSignatureExFunc
- cert_verify_signature_ptr = reinterpret_cast<
- net::sha256_interception::CryptVerifyCertificateSignatureExFunc>(
- ::GetProcAddress(::GetModuleHandle(L"crypt32.dll"),
- "CryptVerifyCertificateSignatureEx"));
- CHECK(cert_verify_signature_ptr);
-
- DWORD old_protect = 0;
- if (!::VirtualProtect(cert_verify_signature_ptr, 5, PAGE_EXECUTE_READWRITE,
- &old_protect)) {
- return;
- }
-
- g_real_crypt_verify_signature_stub =
- reinterpret_cast<
- net::sha256_interception::CryptVerifyCertificateSignatureExFunc>(
- VirtualAllocEx(::GetCurrentProcess(), NULL,
- sidestep::kMaxPreambleStubSize, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE));
- if (g_real_crypt_verify_signature_stub == NULL) {
- CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect,
- &old_protect));
- return;
- }
-
- sidestep::SideStepError patch_result =
- sidestep::PreamblePatcher::Patch(
- cert_verify_signature_ptr, CryptVerifyCertificateSignatureExStub,
- g_real_crypt_verify_signature_stub, sidestep::kMaxPreambleStubSize);
- if (patch_result != sidestep::SIDESTEP_SUCCESS) {
- CHECK(::VirtualFreeEx(::GetCurrentProcess(),
- g_real_crypt_verify_signature_stub, 0,
- MEM_RELEASE));
- CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect,
- &old_protect));
- return;
- }
-
- DWORD dummy = 0;
- CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect, &dummy));
- CHECK(::VirtualProtect(g_real_crypt_verify_signature_stub,
- sidestep::kMaxPreambleStubSize, old_protect,
- &old_protect));
-#endif // _WIN64
-}
-#endif // OS_WIN
+const char kMainThreadName[] = "CrBrowserMain";
} // namespace
@@ -147,7 +65,9 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// TODO(vadimt, yiyaoliu): Remove all tracked_objects references below once
// crbug.com/453640 is fixed.
- tracked_objects::ThreadData::InitializeThreadContext("CrBrowserMain");
+ tracked_objects::ThreadData::InitializeThreadContext(kMainThreadName);
+ base::trace_event::AllocationContextTracker::SetCurrentThreadName(
+ kMainThreadName);
TRACK_SCOPED_REGION(
"Startup", "BrowserMainRunnerImpl::Initialize");
TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize");
@@ -163,10 +83,8 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
SkGraphics::Init();
-#if !defined(OS_IOS)
if (parameters.command_line.HasSwitch(switches::kWaitForDebugger))
base::debug::WaitForDebugger(60, true);
-#endif
#if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
@@ -180,7 +98,6 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// Win32 API here directly.
ImmDisableTextFrameService(static_cast<DWORD>(-1));
}
- InstallSha256LegacyHooks();
#endif // OS_WIN
base::StatisticsRecorder::Initialize();
@@ -266,7 +183,7 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
} else if (tracing::TraceConfigFile::GetInstance()->IsEnabled() &&
TracingController::GetInstance()->IsTracing()) {
base::FilePath result_file;
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
TracingControllerAndroid::GenerateTracingFilePath(&result_file);
#else
result_file = tracing::TraceConfigFile::GetInstance()->GetResultFile();
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
index 68899faf82a..274315ecd3b 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -105,9 +105,7 @@ void BrowserPluginEmbedder::ClearGuestDragStateIfApplicable() {
// static
bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
WebContents* guest_web_contents) {
- RenderWidgetHostImpl::From(
- guest_web_contents->GetRenderViewHost()->GetWidget())
- ->SendScreenRects();
+ static_cast<WebContentsImpl*>(guest_web_contents)->SendScreenRects();
// Not handled => Iterate over all guests.
return false;
}
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
index 33262a832e5..fd0c173ed0b 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -21,6 +21,7 @@
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/frame_host/render_frame_proxy_host.h"
+#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -119,9 +120,9 @@ int BrowserPluginGuest::GetGuestProxyRoutingID() {
if (guest_proxy_routing_id_ != MSG_ROUTING_NONE)
return guest_proxy_routing_id_;
- // Create a swapped out RenderView for the guest in the embedder renderer
+ // Create a RenderFrameProxyHost for the guest in the embedder renderer
// process, so that the embedder can access the guest's window object.
- // On reattachment, we can reuse the same swapped out RenderView because
+ // On reattachment, we can reuse the same RenderFrameProxyHost because
// the embedder process will always be the same even if the embedder
// WebContents changes.
//
@@ -130,17 +131,12 @@ int BrowserPluginGuest::GetGuestProxyRoutingID() {
// |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
// to enable this.
SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance();
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- int proxy_routing_id =
- GetWebContents()->GetFrameTree()->root()->render_manager()->
- CreateRenderFrameProxy(owner_site_instance);
- guest_proxy_routing_id_ = RenderFrameProxyHost::FromID(
- owner_site_instance->GetProcess()->GetID(), proxy_routing_id)
- ->GetRenderViewHost()->GetRoutingID();
- } else {
- guest_proxy_routing_id_ =
- GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
- }
+ int proxy_routing_id =
+ GetWebContents()->GetFrameTree()->root()->render_manager()->
+ CreateRenderFrameProxy(owner_site_instance);
+ guest_proxy_routing_id_ = RenderFrameProxyHost::FromID(
+ owner_site_instance->GetProcess()->GetID(), proxy_routing_id)
+ ->GetRenderViewHost()->GetRoutingID();
return guest_proxy_routing_id_;
}
@@ -250,8 +246,6 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
- OnCompositorFrameSwappedACK)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
OnDragStatusUpdate)
@@ -264,8 +258,6 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
OnImeSetComposition)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
- OnReclaimCompositorResources)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
OnSetEditCommandsForNextKeyEvent)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
@@ -397,24 +389,6 @@ void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
}
-// TODO(wjmaclean): Remove this once any remaining users of this pathway
-// are gone.
-void BrowserPluginGuest::SwapCompositorFrame(
- uint32_t output_surface_id,
- int host_process_id,
- int host_routing_id,
- scoped_ptr<cc::CompositorFrame> frame) {
- last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
- frame->AssignTo(&last_pending_frame_->frame);
- last_pending_frame_->output_surface_id = output_surface_id;
- last_pending_frame_->producing_route_id = host_routing_id;
- last_pending_frame_->producing_host_id = host_process_id;
-
- SendMessageToEmbedder(
- new BrowserPluginMsg_CompositorFrameSwapped(
- browser_plugin_instance_id(), *last_pending_frame_));
-}
-
void BrowserPluginGuest::SetChildFrameSurface(
const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
@@ -752,21 +726,6 @@ void BrowserPluginGuest::Attach(
WebContentsImpl* embedder_web_contents,
const BrowserPluginHostMsg_Attach_Params& params) {
browser_plugin_instance_id_ = browser_plugin_instance_id;
- // If a guest is detaching from one container and attaching to another
- // container, then late arriving ACKs may be lost if the mapping from
- // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
- // ensure that we always get new frames on attachment by ACKing the pending
- // frame if it's still waiting on the ACK.
- if (last_pending_frame_) {
- cc::CompositorFrameAck ack;
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(
- last_pending_frame_->producing_route_id,
- last_pending_frame_->output_surface_id,
- last_pending_frame_->producing_host_id,
- ack);
- last_pending_frame_.reset();
- }
-
// The guest is owned by the embedder. Attach is queued up so we cannot
// change embedders before attach completes. If the embedder goes away,
// so does the guest and so we will never call WillAttachComplete because
@@ -781,16 +740,15 @@ void BrowserPluginGuest::Attach(
void BrowserPluginGuest::OnWillAttachComplete(
WebContentsImpl* embedder_web_contents,
const BrowserPluginHostMsg_Attach_Params& params) {
- bool use_cross_process_frames =
- BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
// If a RenderView has already been created for this new window, then we need
// to initialize the browser-side state now so that the RenderFrameHostManager
// does not create a new RenderView on navigation.
- if (!use_cross_process_frames && has_render_view_) {
+ if (has_render_view_) {
// This will trigger a callback to RenderViewReady after a round-trip IPC.
static_cast<RenderViewHostImpl*>(GetWebContents()->GetRenderViewHost())
->GetWidget()
->Init();
+ GetWebContents()->GetMainFrame()->Init();
WebContentsViewGuest* web_contents_view =
static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
if (!web_contents()->GetRenderViewHost()->GetWidget()->GetView()) {
@@ -809,23 +767,11 @@ void BrowserPluginGuest::OnWillAttachComplete(
RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
web_contents()->GetRenderWidgetHostView());
rwhv->RegisterSurfaceNamespaceId();
-
- if (!use_cross_process_frames)
- has_render_view_ = true;
+ has_render_view_ = true;
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
}
-void BrowserPluginGuest::OnCompositorFrameSwappedACK(
- int browser_plugin_instance_id,
- const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
- params.output_surface_id,
- params.producing_host_id,
- params.ack);
- last_pending_frame_.reset();
-}
-
void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
if (!attached())
return;
@@ -834,8 +780,9 @@ void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
// it's attached again.
attached_ = false;
- RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
- web_contents()->GetRenderWidgetHostView());
+ RenderWidgetHostViewChildFrame* rwhv =
+ static_cast<RenderWidgetHostViewChildFrame*>(
+ web_contents()->GetRenderWidgetHostView());
// If the guest is terminated, our host may already be gone.
if (rwhv)
rwhv->UnregisterSurfaceNamespaceId();
@@ -897,6 +844,7 @@ void BrowserPluginGuest::OnImeSetComposition(
int selection_end) {
Send(new InputMsg_ImeSetComposition(routing_id(),
base::UTF8ToUTF16(text), underlines,
+ gfx::Range::InvalidRange(),
selection_start, selection_end));
}
@@ -920,15 +868,6 @@ void BrowserPluginGuest::OnExtendSelectionAndDelete(
rfh->ExtendSelectionAndDelete(before, after);
}
-void BrowserPluginGuest::OnReclaimCompositorResources(
- int browser_plugin_instance_id,
- const FrameHostMsg_ReclaimCompositorResources_Params& params) {
- RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
- params.output_surface_id,
- params.renderer_host_id,
- params.ack);
-}
-
void BrowserPluginGuest::OnLockMouse(bool user_gesture,
bool last_unlocked_by_target,
bool privileged) {
@@ -973,6 +912,10 @@ void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
bool visible) {
+ // For OOPIF-<webivew>, the remote frame will handle visibility state.
+ if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests())
+ return;
+
guest_visible_ = visible;
if (embedder_visible_ && guest_visible_)
GetWebContents()->WasShown();
@@ -999,10 +942,7 @@ void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
// The plugin has moved within the embedder without resizing or the
// embedder/container's view rect changing.
guest_window_rect_ = view_rect;
- RenderWidgetHostImpl* rwh = RenderWidgetHostImpl::From(
- GetWebContents()->GetRenderViewHost()->GetWidget());
- if (rwh)
- rwh->SendScreenRects();
+ GetWebContents()->SendScreenRects();
}
void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.h b/chromium/content/browser/browser_plugin/browser_plugin_guest.h
index 9cdc85e96d2..e6676f74d6d 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.h
@@ -45,9 +45,6 @@
#include "ui/gfx/geometry/rect.h"
struct BrowserPluginHostMsg_Attach_Params;
-struct FrameHostMsg_CompositorFrameSwappedACK_Params;
-struct FrameHostMsg_ReclaimCompositorResources_Params;
-struct FrameMsg_CompositorFrameSwapped_Params;
struct ViewHostMsg_TextInputState_Params;
#if defined(OS_MACOSX)
@@ -241,11 +238,7 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestHost,
void PointerLockPermissionResponse(bool allow);
- // The next two functions are virtual for test purposes.
- virtual void SwapCompositorFrame(uint32_t output_surface_id,
- int host_process_id,
- int host_routing_id,
- scoped_ptr<cc::CompositorFrame> frame);
+ // The next function is virtual for test purposes.
virtual void SetChildFrameSurface(const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
float scale_factor,
@@ -289,9 +282,6 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestHost,
const cc::SurfaceId& id,
const cc::SurfaceSequence& sequence);
// Message handlers for messages from embedder.
- void OnCompositorFrameSwappedACK(
- int instance_id,
- const FrameHostMsg_CompositorFrameSwappedACK_Params& params);
void OnDetach(int instance_id);
// Handles drag events from the embedder.
// When dragging, the drag events go to the embedder first, and if the drag
@@ -307,11 +297,6 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestHost,
void OnExecuteEditCommand(int instance_id,
const std::string& command);
- // Returns compositor resources reclaimed in the embedder to the guest.
- void OnReclaimCompositorResources(
- int instance_id,
- const FrameHostMsg_ReclaimCompositorResources_Params& params);
-
void OnLockMouse(bool user_gesture,
bool last_unlocked_by_target,
bool privileged);
@@ -456,15 +441,6 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestHost,
// Indicates the URL dragged into the guest if any.
GURL dragged_url_;
- // Guests generate frames and send a CompositorFrameSwapped (CFS) message
- // indicating the next frame is ready to be positioned and composited.
- // Subsequent frames are not generated until the IPC is ACKed. We would like
- // to ensure that the guest generates frames on attachment so we directly ACK
- // an unACKed CFS. ACKs could get lost between the time a guest is detached
- // from a container and the time it is attached elsewhere. This mitigates this
- // race by ensuring the guest is ACKed on attachment.
- scoped_ptr<FrameMsg_CompositorFrameSwapped_Params> last_pending_frame_;
-
// This is a queue of messages that are destined to be sent to the embedder
// once the guest is attached to a particular embedder.
std::deque<linked_ptr<IPC::Message> > pending_messages_;
diff --git a/chromium/content/browser/browser_process_sub_thread.cc b/chromium/content/browser/browser_process_sub_thread.cc
index b1904e10971..5aadda5ad1e 100644
--- a/chromium/content/browser/browser_process_sub_thread.cc
+++ b/chromium/content/browser/browser_process_sub_thread.cc
@@ -66,12 +66,10 @@ void BrowserProcessSubThread::IOThreadPreCleanUp() {
// Destroy all URLRequests started by URLFetchers.
net::URLFetcher::CancelAll();
-#if !defined(OS_IOS)
// If any child processes are still running, terminate them and
// and delete the BrowserChildProcessHost instances to release whatever
// IO thread only resources they are referencing.
BrowserChildProcessHostImpl::TerminateAll();
-#endif // !defined(OS_IOS)
// Unregister GpuMemoryBuffer dump provider before IO thread is shut down.
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
diff --git a/chromium/content/browser/browser_process_sub_thread.h b/chromium/content/browser/browser_process_sub_thread.h
index 2276d6dca46..aded0cb883f 100644
--- a/chromium/content/browser/browser_process_sub_thread.h
+++ b/chromium/content/browser/browser_process_sub_thread.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_BROWSER_PROCESS_SUB_THREAD_H_
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "content/browser/browser_thread_impl.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/browser_side_navigation_browsertest.cc b/chromium/content/browser/browser_side_navigation_browsertest.cc
index 3ffef7d88d2..599f3cc5b71 100644
--- a/chromium/content/browser/browser_side_navigation_browsertest.cc
+++ b/chromium/content/browser/browser_side_navigation_browsertest.cc
@@ -6,7 +6,9 @@
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/site_isolation_policy.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -156,9 +158,21 @@ IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
EXPECT_TRUE(observer.last_navigation_succeeded());
}
- // The RenderFrameHost should not have changed.
- EXPECT_EQ(initial_rfh, static_cast<WebContentsImpl*>(shell()->web_contents())
- ->GetFrameTree()->root()->current_frame_host());
+ // The RenderFrameHost should not have changed unless site-per-process is
+ // enabled.
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_NE(initial_rfh,
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root()
+ ->current_frame_host());
+ } else {
+ EXPECT_EQ(initial_rfh,
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root()
+ ->current_frame_host());
+ }
}
// Ensure that browser side navigation handles navigation failures.
@@ -188,4 +202,30 @@ IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, FailedNavigation) {
}
}
+// Ensure that browser side navigation handles POST navigations correctly.
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, POSTNavigation) {
+ GURL url(embedded_test_server()->GetURL("/session_history/form.html"));
+ GURL post_url = embedded_test_server()->GetURL("/echotitle");
+
+ // Navigate to a page with a form.
+ TestNavigationObserver observer(shell()->web_contents());
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+
+ // Submit the form.
+ GURL submit_url("javascript:submitForm('isubmit')");
+ NavigateToURL(shell(), submit_url);
+
+ // Check that a proper POST navigation was done.
+ EXPECT_EQ("text=&select=a",
+ base::UTF16ToASCII(shell()->web_contents()->GetTitle()));
+ EXPECT_EQ(post_url, shell()->web_contents()->GetLastCommittedURL());
+ EXPECT_TRUE(shell()
+ ->web_contents()
+ ->GetController()
+ .GetActiveEntry()
+ ->GetHasPostData());
+}
+
} // namespace content
diff --git a/chromium/content/browser/browser_thread_impl.cc b/chromium/content/browser/browser_thread_impl.cc
index b86643970e5..dd77c8dac04 100644
--- a/chromium/content/browser/browser_thread_impl.cc
+++ b/chromium/content/browser/browser_thread_impl.cc
@@ -13,9 +13,9 @@
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread_delegate.h"
#include "content/public/browser/content_browser_client.h"
@@ -230,10 +230,11 @@ void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
#endif
BrowserThread::ID thread_id = ID_COUNT;
- if (!GetCurrentThreadIdentifier(&thread_id))
- return Thread::Run(message_loop);
+ CHECK(GetCurrentThreadIdentifier(&thread_id));
+ CHECK_EQ(identifier_, thread_id);
+ CHECK_EQ(Thread::message_loop(), message_loop);
- switch (thread_id) {
+ switch (identifier_) {
case BrowserThread::UI:
return UIThreadRun(message_loop);
case BrowserThread::DB:
@@ -252,7 +253,10 @@ void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
CHECK(false); // This shouldn't actually be reached!
break;
}
- Thread::Run(message_loop);
+
+ // |identifier_| must be set to a valid enum value in the constructor, so it
+ // should be impossible to reach here.
+ CHECK(false);
}
void BrowserThreadImpl::CleanUp() {
@@ -267,6 +271,13 @@ void BrowserThreadImpl::CleanUp() {
if (delegate)
delegate->CleanUp();
+
+ // PostTaskHelper() accesses the message loop while holding this lock.
+ // However, the message loop will soon be destructed without any locking. So
+ // to prevent a race with accessing the message loop in PostTaskHelper(),
+ // remove this thread from the global array now.
+ base::AutoLock lock(globals.lock);
+ globals.threads[identifier_] = NULL;
}
void BrowserThreadImpl::Initialize() {
@@ -398,11 +409,6 @@ bool BrowserThread::IsThreadInitialized(ID identifier) {
// static
bool BrowserThread::CurrentlyOn(ID identifier) {
- // We shouldn't use MessageLoop::current() since it uses LazyInstance which
- // may be deleted by ~AtExitManager when a WorkerPool thread calls this
- // function.
- // http://crbug.com/63678
- base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
@@ -501,13 +507,13 @@ bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
if (g_globals == NULL)
return false;
- // We shouldn't use MessageLoop::current() since it uses LazyInstance which
- // may be deleted by ~AtExitManager when a WorkerPool thread calls this
- // function.
- // http://crbug.com/63678
- base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
base::MessageLoop* cur_message_loop = base::MessageLoop::current();
BrowserThreadGlobals& globals = g_globals.Get();
+ // Profiler to track potential contention on |globals.lock|. This only does
+ // real work on canary and local dev builds, so the cost of having this here
+ // should be minimal.
+ tracked_objects::ScopedTracker tracking_profile(FROM_HERE);
+ base::AutoLock lock(globals.lock);
for (int i = 0; i < ID_COUNT; ++i) {
if (globals.threads[i] &&
globals.threads[i]->message_loop() == cur_message_loop) {
diff --git a/chromium/content/browser/browsing_instance.cc b/chromium/content/browser/browsing_instance.cc
index 1d5f8953769..5dd0ca4191f 100644
--- a/chromium/content/browser/browsing_instance.cc
+++ b/chromium/content/browser/browsing_instance.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "content/browser/site_instance_impl.h"
+#include "content/common/site_isolation_policy.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_switches.h"
@@ -27,29 +28,49 @@ bool BrowsingInstance::HasSiteInstance(const GURL& url) {
return site_instance_map_.find(site) != site_instance_map_.end();
}
-SiteInstance* BrowsingInstance::GetSiteInstanceForURL(const GURL& url) {
- std::string site =
- SiteInstanceImpl::GetSiteForURL(browser_context_, url)
- .possibly_invalid_spec();
+scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURL(
+ const GURL& url) {
+ std::string site = SiteInstanceImpl::GetSiteForURL(browser_context_, url)
+ .possibly_invalid_spec();
SiteInstanceMap::iterator i = site_instance_map_.find(site);
if (i != site_instance_map_.end())
return i->second;
-
// No current SiteInstance for this site, so let's create one.
- SiteInstanceImpl* instance = new SiteInstanceImpl(this);
+ scoped_refptr<SiteInstanceImpl> instance = new SiteInstanceImpl(this);
// Set the site of this new SiteInstance, which will register it with us.
instance->SetSite(url);
return instance;
}
-void BrowsingInstance::RegisterSiteInstance(SiteInstance* site_instance) {
- DCHECK(static_cast<SiteInstanceImpl*>(site_instance)
- ->browsing_instance_.get() ==
- this);
- DCHECK(static_cast<SiteInstanceImpl*>(site_instance)->HasSite());
+scoped_refptr<SiteInstanceImpl>
+BrowsingInstance::GetDefaultSubframeSiteInstance() {
+ // This should only be used for --top-document-isolation mode.
+ CHECK(SiteIsolationPolicy::IsTopDocumentIsolationEnabled());
+ if (!default_subframe_site_instance_) {
+ SiteInstanceImpl* instance = new SiteInstanceImpl(this);
+ instance->set_is_default_subframe_site_instance();
+
+ // TODO(nick): This is a hack for now.
+ instance->SetSite(GURL("http://web-subframes.invalid"));
+
+ default_subframe_site_instance_ = instance;
+ }
+
+ return make_scoped_refptr(default_subframe_site_instance_);
+}
+
+void BrowsingInstance::RegisterSiteInstance(SiteInstanceImpl* site_instance) {
+ DCHECK(site_instance->browsing_instance_.get() == this);
+ DCHECK(site_instance->HasSite());
+
+ // Don't register the default subframe SiteInstance, to prevent it from being
+ // returned by GetSiteInstanceForURL.
+ if (default_subframe_site_instance_ == site_instance)
+ return;
+
std::string site = site_instance->GetSiteURL().possibly_invalid_spec();
// Only register if we don't have a SiteInstance for this site already.
@@ -64,11 +85,9 @@ void BrowsingInstance::RegisterSiteInstance(SiteInstance* site_instance) {
}
}
-void BrowsingInstance::UnregisterSiteInstance(SiteInstance* site_instance) {
- DCHECK(static_cast<SiteInstanceImpl*>(site_instance)
- ->browsing_instance_.get() ==
- this);
- DCHECK(static_cast<SiteInstanceImpl*>(site_instance)->HasSite());
+void BrowsingInstance::UnregisterSiteInstance(SiteInstanceImpl* site_instance) {
+ DCHECK(site_instance->browsing_instance_.get() == this);
+ DCHECK(site_instance->HasSite());
std::string site = site_instance->GetSiteURL().possibly_invalid_spec();
// Only unregister the SiteInstance if it is the same one that is registered
@@ -79,6 +98,8 @@ void BrowsingInstance::UnregisterSiteInstance(SiteInstance* site_instance) {
// Matches, so erase it.
site_instance_map_.erase(i);
}
+ if (default_subframe_site_instance_ == site_instance)
+ default_subframe_site_instance_ = nullptr;
}
BrowsingInstance::~BrowsingInstance() {
diff --git a/chromium/content/browser/browsing_instance.h b/chromium/content/browser/browsing_instance.h
index 0cb80ac80a9..34c1f073bbd 100644
--- a/chromium/content/browser/browsing_instance.h
+++ b/chromium/content/browser/browsing_instance.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -18,7 +19,6 @@
class GURL;
namespace content {
-class SiteInstance;
class SiteInstanceImpl;
///////////////////////////////////////////////////////////////////////////////
@@ -55,12 +55,20 @@ class SiteInstanceImpl;
// site_instance_unittest.cc.
//
///////////////////////////////////////////////////////////////////////////////
-class CONTENT_EXPORT BrowsingInstance
+class CONTENT_EXPORT BrowsingInstance final
: public base::RefCounted<BrowsingInstance> {
- protected:
+ private:
+ friend class base::RefCounted<BrowsingInstance>;
+ friend class SiteInstanceImpl;
+ FRIEND_TEST_ALL_PREFIXES(SiteInstanceTest, OneSiteInstancePerSite);
+ FRIEND_TEST_ALL_PREFIXES(SiteInstanceTest,
+ OneSiteInstancePerSiteInBrowserContext);
+
// Create a new BrowsingInstance.
explicit BrowsingInstance(BrowserContext* context);
+ ~BrowsingInstance();
+
// Get the browser context to which this BrowsingInstance belongs.
BrowserContext* browser_context() const { return browser_context_; }
@@ -71,17 +79,23 @@ class CONTENT_EXPORT BrowsingInstance
// Get the SiteInstance responsible for rendering the given URL. Should
// create a new one if necessary, but should not create more than one
// SiteInstance per site.
- SiteInstance* GetSiteInstanceForURL(const GURL& url);
+ scoped_refptr<SiteInstanceImpl> GetSiteInstanceForURL(const GURL& url);
+
+ // Returns a SiteInstance that should be used for subframes when an oopif is
+ // required, but a dedicated process is not. This SiteInstance will be created
+ // if it doesn't already exist. There is at most one of these per
+ // BrowsingInstance.
+ scoped_refptr<SiteInstanceImpl> GetDefaultSubframeSiteInstance();
// Adds the given SiteInstance to our map, to ensure that we do not create
// another SiteInstance for the same site.
- void RegisterSiteInstance(SiteInstance* site_instance);
+ void RegisterSiteInstance(SiteInstanceImpl* site_instance);
// Removes the given SiteInstance from our map, after all references to it
// have been deleted. This means it is safe to create a new SiteInstance
// if the user later visits a page from this site, within this
// BrowsingInstance.
- void UnregisterSiteInstance(SiteInstance* site_instance);
+ void UnregisterSiteInstance(SiteInstanceImpl* site_instance);
// Tracks the number of WebContents currently in this BrowsingInstance.
size_t active_contents_count() const { return active_contents_count_; }
@@ -91,18 +105,9 @@ class CONTENT_EXPORT BrowsingInstance
active_contents_count_--;
}
- friend class SiteInstanceImpl;
- friend class SiteInstance;
-
- friend class base::RefCounted<BrowsingInstance>;
-
- // Virtual to allow tests to extend it.
- virtual ~BrowsingInstance();
-
- private:
// Map of site to SiteInstance, to ensure we only have one SiteInstance per
// site.
- typedef base::hash_map<std::string, SiteInstance*> SiteInstanceMap;
+ typedef base::hash_map<std::string, SiteInstanceImpl*> SiteInstanceMap;
// Common browser context to which all SiteInstances in this BrowsingInstance
// must belong.
@@ -120,6 +125,8 @@ class CONTENT_EXPORT BrowsingInstance
// Number of WebContentses currently using this BrowsingInstance.
size_t active_contents_count_;
+ SiteInstanceImpl* default_subframe_site_instance_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(BrowsingInstance);
};
diff --git a/chromium/content/browser/cache_storage/cache_storage.cc b/chromium/content/browser/cache_storage/cache_storage.cc
index 362af37e58c..c5a7b1eff63 100644
--- a/chromium/content/browser/cache_storage/cache_storage.cc
+++ b/chromium/content/browser/cache_storage/cache_storage.cc
@@ -46,28 +46,45 @@ std::string HexedHash(const std::string& value) {
return valued_hexed_hash;
}
-void CloseAllCachesDidCloseCache(const scoped_refptr<CacheStorageCache>& cache,
- const base::Closure& barrier_closure) {
- barrier_closure.Run();
+void SizeRetrievedFromCache(const scoped_refptr<CacheStorageCache>& cache,
+ const base::Closure& closure,
+ int64_t* accumulator,
+ int64_t size) {
+ *accumulator += size;
+ closure.Run();
+}
+
+void SizeRetrievedFromAllCaches(scoped_ptr<int64_t> accumulator,
+ const CacheStorage::SizeCallback& callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, *accumulator));
}
} // namespace
const char CacheStorage::kIndexFileName[] = "index.txt";
+struct CacheStorage::CacheMatchResponse {
+ CacheMatchResponse() = default;
+ ~CacheMatchResponse() = default;
+
+ CacheStorageError error;
+ scoped_ptr<ServiceWorkerResponse> service_worker_response;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+};
+
// Handles the loading and clean up of CacheStorageCache objects.
class CacheStorage::CacheLoader {
public:
- typedef base::Callback<void(const scoped_refptr<CacheStorageCache>&)>
- CacheCallback;
+ typedef base::Callback<void(scoped_refptr<CacheStorageCache>)> CacheCallback;
typedef base::Callback<void(bool)> BoolCallback;
typedef base::Callback<void(scoped_ptr<std::vector<std::string>>)>
StringVectorCallback;
CacheLoader(
base::SequencedTaskRunner* cache_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ storage::QuotaManagerProxy* quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context,
const GURL& origin)
: cache_task_runner_(cache_task_runner),
@@ -105,7 +122,10 @@ class CacheStorage::CacheLoader {
protected:
scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
- scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+
+ // Owned by CacheStorage which owns this.
+ storage::QuotaManagerProxy* quota_manager_proxy_;
+
base::WeakPtr<storage::BlobStorageContext> blob_context_;
GURL origin_;
};
@@ -116,12 +136,11 @@ class CacheStorage::CacheLoader {
// cache is deleted.
class CacheStorage::MemoryLoader : public CacheStorage::CacheLoader {
public:
- MemoryLoader(
- base::SequencedTaskRunner* cache_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
- base::WeakPtr<storage::BlobStorageContext> blob_context,
- const GURL& origin)
+ MemoryLoader(base::SequencedTaskRunner* cache_task_runner,
+ scoped_refptr<net::URLRequestContextGetter> request_context,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
: CacheLoader(cache_task_runner,
request_context,
quota_manager_proxy,
@@ -131,14 +150,15 @@ class CacheStorage::MemoryLoader : public CacheStorage::CacheLoader {
scoped_refptr<CacheStorageCache> CreateCache(
const std::string& cache_name) override {
return CacheStorageCache::CreateMemoryCache(
- origin_, request_context_getter_, quota_manager_proxy_, blob_context_);
+ origin_, cache_name, request_context_getter_, quota_manager_proxy_,
+ blob_context_);
}
void PrepareNewCacheDestination(const std::string& cache_name,
const CacheCallback& callback) override {
scoped_refptr<CacheStorageCache> cache = CreateCache(cache_name);
cache_refs_.insert(std::make_pair(cache_name, cache));
- callback.Run(cache);
+ callback.Run(std::move(cache));
}
void CleanUpDeletedCache(const std::string& cache_name,
@@ -171,13 +191,12 @@ class CacheStorage::MemoryLoader : public CacheStorage::CacheLoader {
class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader {
public:
- SimpleCacheLoader(
- const base::FilePath& origin_path,
- base::SequencedTaskRunner* cache_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
- base::WeakPtr<storage::BlobStorageContext> blob_context,
- const GURL& origin)
+ SimpleCacheLoader(const base::FilePath& origin_path,
+ base::SequencedTaskRunner* cache_task_runner,
+ scoped_refptr<net::URLRequestContextGetter> request_context,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
: CacheLoader(cache_task_runner,
request_context,
quota_manager_proxy,
@@ -194,8 +213,8 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader {
std::string cache_dir = cache_name_to_cache_dir_[cache_name];
base::FilePath cache_path = origin_path_.AppendASCII(cache_dir);
return CacheStorageCache::CreatePersistentCache(
- origin_, cache_path, request_context_getter_, quota_manager_proxy_,
- blob_context_);
+ origin_, cache_name, cache_path, request_context_getter_,
+ quota_manager_proxy_, blob_context_);
}
void PrepareNewCacheDestination(const std::string& cache_name,
@@ -253,7 +272,7 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader {
static void CleanUpDeleteCacheDirInPool(
const base::FilePath& cache_path,
const BoolCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> original_task_runner) {
bool rv = base::DeleteFile(cache_path, true);
original_task_runner->PostTask(FROM_HERE, base::Bind(callback, rv));
}
@@ -284,27 +303,24 @@ class CacheStorage::SimpleCacheLoader : public CacheStorage::CacheLoader {
base::FilePath index_path =
origin_path_.AppendASCII(CacheStorage::kIndexFileName);
- cache_task_runner_->PostTask(
- FROM_HERE, base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
- tmp_path, index_path, serialized, callback,
- base::ThreadTaskRunnerHandle::Get()));
+ PostTaskAndReplyWithResult(
+ cache_task_runner_.get(), FROM_HERE,
+ base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool, tmp_path,
+ index_path, serialized),
+ callback);
}
- static void WriteIndexWriteToFileInPool(
- const base::FilePath& tmp_path,
- const base::FilePath& index_path,
- const std::string& data,
- const BoolCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) {
+ static bool WriteIndexWriteToFileInPool(const base::FilePath& tmp_path,
+ const base::FilePath& index_path,
+ const std::string& data) {
int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
if (bytes_written != base::checked_cast<int>(data.size())) {
base::DeleteFile(tmp_path, /* recursive */ false);
- original_task_runner->PostTask(FROM_HERE, base::Bind(callback, false));
+ return false;
}
// Atomically rename the temporary index file to become the real one.
- bool rv = base::ReplaceFile(tmp_path, index_path, NULL);
- original_task_runner->PostTask(FROM_HERE, base::Bind(callback, rv));
+ return base::ReplaceFile(tmp_path, index_path, NULL);
}
void LoadIndex(scoped_ptr<std::vector<std::string>> names,
@@ -442,8 +458,8 @@ CacheStorage::CacheStorage(
const base::FilePath& path,
bool memory_only,
base::SequencedTaskRunner* cache_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>& request_context,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context,
const GURL& origin)
: initialized_(false),
@@ -452,15 +468,17 @@ CacheStorage::CacheStorage(
origin_path_(path),
cache_task_runner_(cache_task_runner),
memory_only_(memory_only),
+ quota_manager_proxy_(quota_manager_proxy),
+ origin_(origin),
weak_factory_(this) {
if (memory_only)
- cache_loader_.reset(new MemoryLoader(cache_task_runner_.get(),
- request_context, quota_manager_proxy,
- blob_context, origin));
+ cache_loader_.reset(
+ new MemoryLoader(cache_task_runner_.get(), std::move(request_context),
+ quota_manager_proxy.get(), blob_context, origin));
else
cache_loader_.reset(new SimpleCacheLoader(
- origin_path_, cache_task_runner_.get(), request_context,
- quota_manager_proxy, blob_context, origin));
+ origin_path_, cache_task_runner_.get(), std::move(request_context),
+ quota_manager_proxy.get(), blob_context, origin));
}
CacheStorage::~CacheStorage() {
@@ -473,6 +491,10 @@ void CacheStorage::OpenCache(const std::string& cache_name,
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
CacheAndErrorCallback pending_callback =
base::Bind(&CacheStorage::PendingCacheAndErrorCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -488,6 +510,10 @@ void CacheStorage::HasCache(const std::string& cache_name,
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
BoolAndErrorCallback pending_callback =
base::Bind(&CacheStorage::PendingBoolAndErrorCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -503,6 +529,10 @@ void CacheStorage::DeleteCache(const std::string& cache_name,
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
BoolAndErrorCallback pending_callback =
base::Bind(&CacheStorage::PendingBoolAndErrorCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -517,6 +547,10 @@ void CacheStorage::EnumerateCaches(const StringsAndErrorCallback& callback) {
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
StringsAndErrorCallback pending_callback =
base::Bind(&CacheStorage::PendingStringsAndErrorCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -534,6 +568,10 @@ void CacheStorage::MatchCache(
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
CacheStorageCache::ResponseCallback pending_callback =
base::Bind(&CacheStorage::PendingResponseCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -550,6 +588,10 @@ void CacheStorage::MatchAllCaches(
if (!initialized_)
LazyInit();
+ quota_manager_proxy_->NotifyStorageAccessed(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary);
+
CacheStorageCache::ResponseCallback pending_callback =
base::Bind(&CacheStorage::PendingResponseCallback,
weak_factory_.GetWeakPtr(), callback);
@@ -558,33 +600,31 @@ void CacheStorage::MatchAllCaches(
base::Passed(std::move(request)), pending_callback));
}
-void CacheStorage::CloseAllCaches(const base::Closure& callback) {
+void CacheStorage::GetSizeThenCloseAllCaches(const SizeCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!initialized_) {
- callback.Run();
- return;
- }
+ if (!initialized_)
+ LazyInit();
- base::Closure pending_callback = base::Bind(
- &CacheStorage::PendingClosure, weak_factory_.GetWeakPtr(), callback);
- scheduler_->ScheduleOperation(base::Bind(&CacheStorage::CloseAllCachesImpl,
- weak_factory_.GetWeakPtr(),
- pending_callback));
+ CacheStorageCache::SizeCallback pending_callback = base::Bind(
+ &CacheStorage::PendingSizeCallback, weak_factory_.GetWeakPtr(), callback);
+
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorage::GetSizeThenCloseAllCachesImpl,
+ weak_factory_.GetWeakPtr(), pending_callback));
}
-int64_t CacheStorage::MemoryBackedSize() const {
+void CacheStorage::Size(const CacheStorage::SizeCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!initialized_ || !memory_only_)
- return 0;
+ if (!initialized_)
+ LazyInit();
+
+ CacheStorageCache::SizeCallback pending_callback = base::Bind(
+ &CacheStorage::PendingSizeCallback, weak_factory_.GetWeakPtr(), callback);
- int64_t sum = 0;
- for (auto& key_value : cache_map_) {
- if (key_value.second)
- sum += key_value.second->MemoryBackedSize();
- }
- return sum;
+ scheduler_->ScheduleOperation(base::Bind(
+ &CacheStorage::SizeImpl, weak_factory_.GetWeakPtr(), pending_callback));
}
void CacheStorage::StartAsyncOperationForTesting() {
@@ -648,7 +688,7 @@ void CacheStorage::OpenCacheImpl(const std::string& cache_name,
const CacheAndErrorCallback& callback) {
scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
if (cache.get()) {
- callback.Run(cache, CACHE_STORAGE_OK);
+ callback.Run(std::move(cache), CACHE_STORAGE_OK);
return;
}
@@ -660,7 +700,7 @@ void CacheStorage::OpenCacheImpl(const std::string& cache_name,
void CacheStorage::CreateCacheDidCreateCache(
const std::string& cache_name,
const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache) {
+ scoped_refptr<CacheStorageCache> cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult",
@@ -680,19 +720,19 @@ void CacheStorage::CreateCacheDidCreateCache(
cache_loader_->WriteIndex(
ordered_cache_names_,
base::Bind(&CacheStorage::CreateCacheDidWriteIndex,
- weak_factory_.GetWeakPtr(), callback, cache));
+ weak_factory_.GetWeakPtr(), callback, std::move(cache)));
}
void CacheStorage::CreateCacheDidWriteIndex(
const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(cache.get());
// TODO(jkarlin): Handle !success.
- callback.Run(cache, CACHE_STORAGE_OK);
+ callback.Run(std::move(cache), CACHE_STORAGE_OK);
}
void CacheStorage::HasCacheImpl(const std::string& cache_name,
@@ -703,14 +743,15 @@ void CacheStorage::HasCacheImpl(const std::string& cache_name,
void CacheStorage::DeleteCacheImpl(const std::string& cache_name,
const BoolAndErrorCallback& callback) {
- CacheMap::iterator it = cache_map_.find(cache_name);
- if (it == cache_map_.end()) {
- callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND);
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ if (!cache.get()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, false, CACHE_STORAGE_ERROR_NOT_FOUND));
return;
}
- base::WeakPtr<CacheStorageCache> cache = it->second;
- cache_map_.erase(it);
+ CacheMap::iterator map_iter = cache_map_.find(cache_name);
+ cache_map_.erase(map_iter);
// Delete the name from ordered_cache_names_.
StringVector::iterator iter = std::find(
@@ -718,36 +759,33 @@ void CacheStorage::DeleteCacheImpl(const std::string& cache_name,
DCHECK(iter != ordered_cache_names_.end());
ordered_cache_names_.erase(iter);
- base::Closure closure =
- base::Bind(&CacheStorage::DeleteCacheDidClose, weak_factory_.GetWeakPtr(),
- cache_name, callback, ordered_cache_names_,
- make_scoped_refptr(cache.get()));
-
- if (cache) {
- cache->Close(closure);
- return;
- }
-
- closure.Run();
+ cache->GetSizeThenClose(base::Bind(&CacheStorage::DeleteCacheDidClose,
+ weak_factory_.GetWeakPtr(), cache_name,
+ callback, ordered_cache_names_, cache));
}
-void CacheStorage::DeleteCacheDidClose(
- const std::string& cache_name,
- const BoolAndErrorCallback& callback,
- const StringVector& ordered_cache_names,
- const scoped_refptr<CacheStorageCache>& cache /* might be null */) {
+void CacheStorage::DeleteCacheDidClose(const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ const StringVector& ordered_cache_names,
+ scoped_refptr<CacheStorageCache> cache,
+ int64_t cache_size) {
cache_loader_->WriteIndex(
ordered_cache_names,
base::Bind(&CacheStorage::DeleteCacheDidWriteIndex,
- weak_factory_.GetWeakPtr(), cache_name, callback));
+ weak_factory_.GetWeakPtr(), cache_name, callback, cache_size));
}
void CacheStorage::DeleteCacheDidWriteIndex(
const std::string& cache_name,
const BoolAndErrorCallback& callback,
+ int cache_size,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ quota_manager_proxy_->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary, -1 * cache_size);
+
cache_loader_->CleanUpDeletedCache(
cache_name, base::Bind(&CacheStorage::DeleteCacheDidCleanUp,
weak_factory_.GetWeakPtr(), callback));
@@ -772,7 +810,7 @@ void CacheStorage::MatchCacheImpl(
scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
if (!cache.get()) {
- callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ callback.Run(CACHE_STORAGE_ERROR_CACHE_NAME_NOT_FOUND,
scoped_ptr<ServiceWorkerResponse>(),
scoped_ptr<storage::BlobDataHandle>());
return;
@@ -786,7 +824,7 @@ void CacheStorage::MatchCacheImpl(
}
void CacheStorage::MatchCacheDidMatch(
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
const CacheStorageCache::ResponseCallback& callback,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
@@ -797,51 +835,55 @@ void CacheStorage::MatchCacheDidMatch(
void CacheStorage::MatchAllCachesImpl(
scoped_ptr<ServiceWorkerFetchRequest> request,
const CacheStorageCache::ResponseCallback& callback) {
- scoped_ptr<CacheStorageCache::ResponseCallback> callback_copy(
- new CacheStorageCache::ResponseCallback(callback));
-
- CacheStorageCache::ResponseCallback* callback_ptr = callback_copy.get();
- base::Closure barrier_closure =
- base::BarrierClosure(ordered_cache_names_.size(),
- base::Bind(&CacheStorage::MatchAllCachesDidMatchAll,
- weak_factory_.GetWeakPtr(),
- base::Passed(std::move(callback_copy))));
-
- for (const std::string& cache_name : ordered_cache_names_) {
- scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ std::vector<CacheMatchResponse>* match_responses =
+ new std::vector<CacheMatchResponse>(ordered_cache_names_.size());
+
+ base::Closure barrier_closure = base::BarrierClosure(
+ ordered_cache_names_.size(),
+ base::Bind(&CacheStorage::MatchAllCachesDidMatchAll,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(make_scoped_ptr(match_responses)), callback));
+
+ for (size_t i = 0, max = ordered_cache_names_.size(); i < max; ++i) {
+ scoped_refptr<CacheStorageCache> cache =
+ GetLoadedCache(ordered_cache_names_[i]);
DCHECK(cache.get());
cache->Match(make_scoped_ptr(new ServiceWorkerFetchRequest(*request)),
base::Bind(&CacheStorage::MatchAllCachesDidMatch,
- weak_factory_.GetWeakPtr(), cache, barrier_closure,
- callback_ptr));
+ weak_factory_.GetWeakPtr(), cache,
+ &match_responses->at(i), barrier_closure));
}
}
void CacheStorage::MatchAllCachesDidMatch(
scoped_refptr<CacheStorageCache> cache,
+ CacheMatchResponse* out_match_response,
const base::Closure& barrier_closure,
- CacheStorageCache::ResponseCallback* callback,
CacheStorageError error,
- scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<ServiceWorkerResponse> service_worker_response,
scoped_ptr<storage::BlobDataHandle> handle) {
- if (callback->is_null() || error == CACHE_STORAGE_ERROR_NOT_FOUND) {
- barrier_closure.Run();
- return;
- }
- callback->Run(error, std::move(response), std::move(handle));
- callback->Reset(); // Only call the callback once.
-
+ out_match_response->error = error;
+ out_match_response->service_worker_response =
+ std::move(service_worker_response);
+ out_match_response->blob_data_handle = std::move(handle);
barrier_closure.Run();
}
void CacheStorage::MatchAllCachesDidMatchAll(
- scoped_ptr<CacheStorageCache::ResponseCallback> callback) {
- if (!callback->is_null()) {
- callback->Run(CACHE_STORAGE_ERROR_NOT_FOUND,
- scoped_ptr<ServiceWorkerResponse>(),
- scoped_ptr<storage::BlobDataHandle>());
+ scoped_ptr<std::vector<CacheMatchResponse>> match_responses,
+ const CacheStorageCache::ResponseCallback& callback) {
+ for (CacheMatchResponse& match_response : *match_responses) {
+ if (match_response.error == CACHE_STORAGE_ERROR_NOT_FOUND)
+ continue;
+ callback.Run(match_response.error,
+ std::move(match_response.service_worker_response),
+ std::move(match_response.blob_data_handle));
+ return;
}
+ callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
}
scoped_refptr<CacheStorageCache> CacheStorage::GetLoadedCache(
@@ -868,7 +910,7 @@ scoped_refptr<CacheStorageCache> CacheStorage::GetLoadedCache(
}
void CacheStorage::TemporarilyPreserveCache(
- const scoped_refptr<CacheStorageCache>& cache) {
+ scoped_refptr<CacheStorageCache> cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!ContainsKey(preserved_caches_, cache.get()));
@@ -894,32 +936,42 @@ void CacheStorage::RemovePreservedCache(const CacheStorageCache* cache) {
preserved_caches_.erase(cache);
}
-void CacheStorage::CloseAllCachesImpl(const base::Closure& callback) {
- int live_cache_count = 0;
- for (const auto& key_value : cache_map_) {
- if (key_value.second)
- live_cache_count += 1;
- }
+void CacheStorage::GetSizeThenCloseAllCachesImpl(const SizeCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(initialized_);
- if (live_cache_count == 0) {
- callback.Run();
- return;
- }
+ scoped_ptr<int64_t> accumulator(new int64_t(0));
+ int64_t* accumulator_ptr = accumulator.get();
- // The closure might modify this object so delay calling it until after
- // iterating through cache_map_ by adding one to the barrier.
- base::Closure barrier_closure =
- base::BarrierClosure(live_cache_count + 1, base::Bind(callback));
+ base::Closure barrier_closure = base::BarrierClosure(
+ ordered_cache_names_.size(),
+ base::Bind(&SizeRetrievedFromAllCaches,
+ base::Passed(std::move(accumulator)), callback));
- for (auto& key_value : cache_map_) {
- if (key_value.second) {
- key_value.second->Close(base::Bind(
- CloseAllCachesDidCloseCache,
- make_scoped_refptr(key_value.second.get()), barrier_closure));
- }
+ for (const std::string& cache_name : ordered_cache_names_) {
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ cache->GetSizeThenClose(base::Bind(&SizeRetrievedFromCache, cache,
+ barrier_closure, accumulator_ptr));
}
+}
- barrier_closure.Run();
+void CacheStorage::SizeImpl(const SizeCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(initialized_);
+
+ scoped_ptr<int64_t> accumulator(new int64_t(0));
+ int64_t* accumulator_ptr = accumulator.get();
+
+ base::Closure barrier_closure = base::BarrierClosure(
+ ordered_cache_names_.size(),
+ base::Bind(&SizeRetrievedFromAllCaches,
+ base::Passed(std::move(accumulator)), callback));
+
+ for (const std::string& cache_name : ordered_cache_names_) {
+ scoped_refptr<CacheStorageCache> cache = GetLoadedCache(cache_name);
+ cache->Size(base::Bind(&SizeRetrievedFromCache, cache, barrier_closure,
+ accumulator_ptr));
+ }
}
void CacheStorage::PendingClosure(const base::Closure& callback) {
@@ -943,11 +995,11 @@ void CacheStorage::PendingBoolAndErrorCallback(
void CacheStorage::PendingCacheAndErrorCallback(
const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error) {
base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
- callback.Run(cache, error);
+ callback.Run(std::move(cache), error);
if (cache_storage)
scheduler_->CompleteOperationAndRunNext();
}
@@ -975,4 +1027,13 @@ void CacheStorage::PendingResponseCallback(
scheduler_->CompleteOperationAndRunNext();
}
+void CacheStorage::PendingSizeCallback(const SizeCallback& callback,
+ int64_t size) {
+ base::WeakPtr<CacheStorage> cache_storage = weak_factory_.GetWeakPtr();
+
+ callback.Run(size);
+ if (cache_storage)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
} // namespace content
diff --git a/chromium/content/browser/cache_storage/cache_storage.h b/chromium/content/browser/cache_storage/cache_storage.h
index b1bf67e75d6..e81dd2f1441 100644
--- a/chromium/content/browser/cache_storage/cache_storage.h
+++ b/chromium/content/browser/cache_storage/cache_storage.h
@@ -41,10 +41,12 @@ class CONTENT_EXPORT CacheStorage {
public:
typedef std::vector<std::string> StringVector;
typedef base::Callback<void(bool, CacheStorageError)> BoolAndErrorCallback;
- typedef base::Callback<void(const scoped_refptr<CacheStorageCache>&,
- CacheStorageError)> CacheAndErrorCallback;
+ typedef base::Callback<void(scoped_refptr<CacheStorageCache>,
+ CacheStorageError)>
+ CacheAndErrorCallback;
typedef base::Callback<void(const StringVector&, CacheStorageError)>
StringsAndErrorCallback;
+ using SizeCallback = base::Callback<void(int64_t)>;
static const char kIndexFileName[];
@@ -52,8 +54,8 @@ class CONTENT_EXPORT CacheStorage {
const base::FilePath& origin_path,
bool memory_only,
base::SequencedTaskRunner* cache_task_runner,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context,
const GURL& origin);
@@ -84,20 +86,19 @@ class CONTENT_EXPORT CacheStorage {
const CacheStorageCache::ResponseCallback& callback);
// Calls match on all of the caches in parallel, calling |callback| with the
- // first response found. Note that if multiple caches have the same
- // request/response then it is not defined which cache's response will be
- // returned. If no response is found then |callback| is called with
+ // response from the first cache (in order of cache creation) to have the
+ // entry. If no response is found then |callback| is called with
// CACHE_STORAGE_ERROR_NOT_FOUND.
void MatchAllCaches(scoped_ptr<ServiceWorkerFetchRequest> request,
const CacheStorageCache::ResponseCallback& callback);
- // Calls close on each cache and runs the callback after all of them have
- // closed.
- void CloseAllCaches(const base::Closure& callback);
+ // Sums the sizes of each cache and closes them. Runs |callback| with the
+ // size.
+ void GetSizeThenCloseAllCaches(const SizeCallback& callback);
- // The size of all of the origin's contents in memory. Returns 0 if the cache
- // backend is not a memory backend. Runs synchronously.
- int64_t MemoryBackedSize() const;
+ // The size of all of the origin's contents. This value should be used as an
+ // estimate only since the cache may be modified at any time.
+ void Size(const SizeCallback& callback);
// The functions below are for tests to verify that the operations run
// serially.
@@ -106,10 +107,10 @@ class CONTENT_EXPORT CacheStorage {
private:
friend class TestCacheStorage;
-
+ class CacheLoader;
class MemoryLoader;
class SimpleCacheLoader;
- class CacheLoader;
+ struct CacheMatchResponse;
typedef std::map<std::string, base::WeakPtr<CacheStorageCache>> CacheMap;
@@ -119,7 +120,7 @@ class CONTENT_EXPORT CacheStorage {
const std::string& cache_name);
// Holds a reference to a cache for thirty seconds.
- void TemporarilyPreserveCache(const scoped_refptr<CacheStorageCache>& cache);
+ void TemporarilyPreserveCache(scoped_refptr<CacheStorageCache> cache);
virtual void SchedulePreservedCacheRemoval(
const base::Closure& callback); // Virtual for testing.
void RemovePreservedCache(const CacheStorageCache* cache);
@@ -135,9 +136,9 @@ class CONTENT_EXPORT CacheStorage {
const CacheAndErrorCallback& callback);
void CreateCacheDidCreateCache(const std::string& cache_name,
const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache);
+ scoped_refptr<CacheStorageCache> cache);
void CreateCacheDidWriteIndex(const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
bool success);
// The HasCache callbacks are below.
@@ -151,9 +152,11 @@ class CONTENT_EXPORT CacheStorage {
void DeleteCacheDidClose(const std::string& cache_name,
const BoolAndErrorCallback& callback,
const StringVector& ordered_cache_names,
- const scoped_refptr<CacheStorageCache>& cache);
+ scoped_refptr<CacheStorageCache> cache,
+ int64_t cache_size);
void DeleteCacheDidWriteIndex(const std::string& cache_name,
const BoolAndErrorCallback& callback,
+ int cache_size,
bool success);
void DeleteCacheDidCleanUp(const BoolAndErrorCallback& callback,
bool success);
@@ -165,7 +168,7 @@ class CONTENT_EXPORT CacheStorage {
void MatchCacheImpl(const std::string& cache_name,
scoped_ptr<ServiceWorkerFetchRequest> request,
const CacheStorageCache::ResponseCallback& callback);
- void MatchCacheDidMatch(const scoped_refptr<CacheStorageCache>& cache,
+ void MatchCacheDidMatch(scoped_refptr<CacheStorageCache> cache,
const CacheStorageCache::ResponseCallback& callback,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
@@ -174,26 +177,28 @@ class CONTENT_EXPORT CacheStorage {
// The MatchAllCaches callbacks are below.
void MatchAllCachesImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
const CacheStorageCache::ResponseCallback& callback);
- void MatchAllCachesDidMatch(scoped_refptr<CacheStorageCache> cache,
- const base::Closure& barrier_closure,
- CacheStorageCache::ResponseCallback* callback,
- CacheStorageError error,
- scoped_ptr<ServiceWorkerResponse> response,
- scoped_ptr<storage::BlobDataHandle> handle);
+ void MatchAllCachesDidMatch(
+ scoped_refptr<CacheStorageCache> cache,
+ CacheMatchResponse* out_match_response,
+ const base::Closure& barrier_closure,
+ CacheStorageError error,
+ scoped_ptr<ServiceWorkerResponse> service_worker_response,
+ scoped_ptr<storage::BlobDataHandle> handle);
void MatchAllCachesDidMatchAll(
- scoped_ptr<CacheStorageCache::ResponseCallback> callback);
+ scoped_ptr<std::vector<CacheMatchResponse>> match_responses,
+ const CacheStorageCache::ResponseCallback& callback);
- // The CloseAllCaches callbacks are below.
- void CloseAllCachesImpl(const base::Closure& callback);
+ void GetSizeThenCloseAllCachesImpl(const SizeCallback& callback);
+
+ void SizeImpl(const SizeCallback& callback);
void PendingClosure(const base::Closure& callback);
void PendingBoolAndErrorCallback(const BoolAndErrorCallback& callback,
bool found,
CacheStorageError error);
- void PendingCacheAndErrorCallback(
- const CacheAndErrorCallback& callback,
- const scoped_refptr<CacheStorageCache>& cache,
- CacheStorageError error);
+ void PendingCacheAndErrorCallback(const CacheAndErrorCallback& callback,
+ scoped_refptr<CacheStorageCache> cache,
+ CacheStorageError error);
void PendingStringsAndErrorCallback(const StringsAndErrorCallback& callback,
const StringVector& strings,
CacheStorageError error);
@@ -203,6 +208,8 @@ class CONTENT_EXPORT CacheStorage {
scoped_ptr<ServiceWorkerResponse> response,
scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void PendingSizeCallback(const SizeCallback& callback, int64_t size);
+
// Whether or not we've loaded the list of cache names into memory.
bool initialized_;
bool initializing_;
@@ -233,6 +240,12 @@ class CONTENT_EXPORT CacheStorage {
std::map<const CacheStorageCache*, scoped_refptr<CacheStorageCache>>
preserved_caches_;
+ // The quota manager.
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+
+ // The origin that this CacheStorage is associated with.
+ GURL origin_;
+
base::WeakPtrFactory<CacheStorage> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CacheStorage);
diff --git a/chromium/content/browser/cache_storage/cache_storage.proto b/chromium/content/browser/cache_storage/cache_storage.proto
index 807c1e548c4..07a61700cff 100644
--- a/chromium/content/browser/cache_storage/cache_storage.proto
+++ b/chromium/content/browser/cache_storage/cache_storage.proto
@@ -42,6 +42,7 @@ message CacheResponse {
required ResponseType response_type = 3;
repeated CacheHeaderMap headers = 4;
optional string url = 5;
+ optional int64 response_time = 6;
}
message CacheMetadata {
diff --git a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
index 08dffc32323..bc58008ae29 100644
--- a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
@@ -32,13 +32,14 @@ CacheStorageBlobToDiskCache::~CacheStorageBlobToDiskCache() {
void CacheStorageBlobToDiskCache::StreamBlobToCache(
disk_cache::ScopedEntryPtr entry,
int disk_cache_body_index,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
+ net::URLRequestContextGetter* request_context_getter,
scoped_ptr<storage::BlobDataHandle> blob_data_handle,
const EntryAndBoolCallback& callback) {
DCHECK(entry);
DCHECK_LE(0, disk_cache_body_index);
DCHECK(blob_data_handle);
DCHECK(!blob_request_);
+ DCHECK(request_context_getter);
if (!request_context_getter->GetURLRequestContext()) {
callback.Run(std::move(entry), false /* success */);
diff --git a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
index 18e6fd9730f..3f73f255a6b 100644
--- a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
+++ b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
@@ -43,12 +43,11 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
// Writes the body of |blob_data_handle| to |entry| with index
// |disk_cache_body_index|. |entry| is passed to the callback once complete.
// Only call this once per instantiation of CacheStorageBlobToDiskCache.
- void StreamBlobToCache(
- disk_cache::ScopedEntryPtr entry,
- int disk_cache_body_index,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- scoped_ptr<storage::BlobDataHandle> blob_data_handle,
- const EntryAndBoolCallback& callback);
+ void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
+ int disk_cache_body_index,
+ net::URLRequestContextGetter* request_context_getter,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+ const EntryAndBoolCallback& callback);
// net::URLRequest::Delegate overrides for reading blobs.
void OnResponseStarted(net::URLRequest* request) override;
@@ -80,7 +79,10 @@ class CONTENT_EXPORT CacheStorageBlobToDiskCache
int cache_entry_offset_;
disk_cache::ScopedEntryPtr entry_;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+
+ // Owned by CacheStorageCache which owns this.
+ net::URLRequestContextGetter* request_context_getter_;
+
int disk_cache_body_index_;
scoped_ptr<net::URLRequest> blob_request_;
EntryAndBoolCallback callback_;
diff --git a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
index 28e6c0c18b4..5734e0d8a31 100644
--- a/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
@@ -172,7 +172,7 @@ class CacheStorageBlobToDiskCacheTest : public testing::Test {
cache_storage_blob_to_disk_cache_->StreamBlobToCache(
std::move(disk_cache_entry_), kCacheEntryIndex,
- url_request_context_getter_, std::move(new_data_handle),
+ url_request_context_getter_.get(), std::move(new_data_handle),
base::Bind(&CacheStorageBlobToDiskCacheTest::StreamCallback,
base::Unretained(this)));
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.cc b/chromium/content/browser/cache_storage/cache_storage_cache.cc
index 2fc74110e7e..cbe1889d4e6 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.cc
@@ -15,6 +15,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/cache_storage/cache_storage.pb.h"
#include "content/browser/cache_storage/cache_storage_blob_to_disk_cache.h"
#include "content/browser/cache_storage/cache_storage_scheduler.h"
@@ -41,7 +42,7 @@ namespace {
class CacheStorageCacheDataHandle
: public storage::BlobDataBuilder::DataHandle {
public:
- CacheStorageCacheDataHandle(const scoped_refptr<CacheStorageCache>& cache,
+ CacheStorageCacheDataHandle(scoped_refptr<CacheStorageCache> cache,
disk_cache::ScopedEntryPtr entry)
: cache_(cache), entry_(std::move(entry)) {}
@@ -58,13 +59,9 @@ typedef base::Callback<void(scoped_ptr<CacheMetadata>)> MetadataCallback;
enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
-// The maximum size of an individual cache. Ultimately cache size is controlled
-// per-origin.
-const int kMaxCacheBytes = 512 * 1024 * 1024;
-
-void NotReachedCompletionCallback(int rv) {
- NOTREACHED();
-}
+// The maximum size of each cache. Ultimately, cache size
+// is controlled per-origin by the QuotaManager.
+const int kMaxCacheBytes = std::numeric_limits<int>::max();
blink::WebServiceWorkerResponseType ProtoResponseTypeToWebResponseType(
CacheResponse::ResponseType response_type) {
@@ -109,11 +106,10 @@ CacheResponse::ResponseType WebResponseTypeToProtoResponseType(
// Copy headers out of a cache entry and into a protobuf. The callback is
// guaranteed to be run.
void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback);
-void ReadMetadataDidReadMetadata(
- disk_cache::Entry* entry,
- const MetadataCallback& callback,
- const scoped_refptr<net::IOBufferWithSize>& buffer,
- int rv);
+void ReadMetadataDidReadMetadata(disk_cache::Entry* entry,
+ const MetadataCallback& callback,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ int rv);
bool VaryMatches(const ServiceWorkerHeaderMap& request,
const ServiceWorkerHeaderMap& cached_request,
@@ -147,6 +143,12 @@ bool VaryMatches(const ServiceWorkerHeaderMap& request,
return true;
}
+GURL RemoveQueryParam(const GURL& url) {
+ url::Replacements<char> replacements;
+ replacements.ClearQuery();
+ return url.ReplaceComponents(replacements);
+}
+
void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
DCHECK(entry);
@@ -163,11 +165,10 @@ void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
read_header_callback.Run(read_rv);
}
-void ReadMetadataDidReadMetadata(
- disk_cache::Entry* entry,
- const MetadataCallback& callback,
- const scoped_refptr<net::IOBufferWithSize>& buffer,
- int rv) {
+void ReadMetadataDidReadMetadata(disk_cache::Entry* entry,
+ const MetadataCallback& callback,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ int rv) {
if (rv != buffer->size()) {
callback.Run(scoped_ptr<CacheMetadata>());
return;
@@ -210,12 +211,20 @@ struct CacheStorageCache::OpenAllEntriesContext {
// The state needed to pass between CacheStorageCache::MatchAll callbacks.
struct CacheStorageCache::MatchAllContext {
- explicit MatchAllContext(const CacheStorageCache::ResponsesCallback& callback)
- : original_callback(callback),
+ MatchAllContext(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCacheQueryParams& match_params,
+ const ResponsesCallback& callback)
+ : request(std::move(request)),
+ options(match_params),
+ original_callback(callback),
out_responses(new Responses),
out_blob_data_handles(new BlobDataHandles) {}
~MatchAllContext() {}
+ scoped_ptr<ServiceWorkerFetchRequest> request;
+
+ CacheStorageCacheQueryParams options;
+
// The callback passed to the MatchAll() function.
ResponsesCallback original_callback;
@@ -251,31 +260,22 @@ struct CacheStorageCache::KeysContext {
// The state needed to pass between CacheStorageCache::Put callbacks.
struct CacheStorageCache::PutContext {
- PutContext(
- const GURL& origin,
- scoped_ptr<ServiceWorkerFetchRequest> request,
- scoped_ptr<ServiceWorkerResponse> response,
- scoped_ptr<storage::BlobDataHandle> blob_data_handle,
- const CacheStorageCache::ErrorCallback& callback,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
- : origin(origin),
- request(std::move(request)),
+ PutContext(scoped_ptr<ServiceWorkerFetchRequest> request,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+ const CacheStorageCache::ErrorCallback& callback)
+ : request(std::move(request)),
response(std::move(response)),
blob_data_handle(std::move(blob_data_handle)),
- callback(callback),
- request_context_getter(request_context_getter),
- quota_manager_proxy(quota_manager_proxy) {}
+ callback(callback) {}
// Input parameters to the Put function.
- GURL origin;
scoped_ptr<ServiceWorkerFetchRequest> request;
scoped_ptr<ServiceWorkerResponse> response;
scoped_ptr<storage::BlobDataHandle> blob_data_handle;
CacheStorageCache::ErrorCallback callback;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter;
- scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
disk_cache::ScopedEntryPtr cache_entry;
+ int64_t available_bytes = 0;
private:
DISALLOW_COPY_AND_ASSIGN(PutContext);
@@ -284,26 +284,30 @@ struct CacheStorageCache::PutContext {
// static
scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache(
const GURL& origin,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ const std::string& cache_name,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context) {
- return make_scoped_refptr(
- new CacheStorageCache(origin, base::FilePath(), request_context_getter,
- quota_manager_proxy, blob_context));
+ return make_scoped_refptr(new CacheStorageCache(
+ origin, cache_name, base::FilePath(), std::move(request_context_getter),
+ std::move(quota_manager_proxy), blob_context));
}
// static
scoped_refptr<CacheStorageCache> CacheStorageCache::CreatePersistentCache(
const GURL& origin,
+ const std::string& cache_name,
const base::FilePath& path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context) {
return make_scoped_refptr(new CacheStorageCache(
- origin, path, request_context_getter, quota_manager_proxy, blob_context));
+ origin, cache_name, path, std::move(request_context_getter),
+ std::move(quota_manager_proxy), blob_context));
}
CacheStorageCache::~CacheStorageCache() {
+ quota_manager_proxy_->NotifyOriginNoLongerInUse(origin_);
}
base::WeakPtr<CacheStorageCache> CacheStorageCache::AsWeakPtr() {
@@ -327,7 +331,10 @@ void CacheStorageCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
base::Passed(std::move(request)), pending_callback));
}
-void CacheStorageCache::MatchAll(const ResponsesCallback& callback) {
+void CacheStorageCache::MatchAll(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCacheQueryParams& match_params,
+ const ResponsesCallback& callback) {
if (!LazyInitialize()) {
callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Responses>(),
scoped_ptr<BlobDataHandles>());
@@ -337,9 +344,12 @@ void CacheStorageCache::MatchAll(const ResponsesCallback& callback) {
ResponsesCallback pending_callback =
base::Bind(&CacheStorageCache::PendingResponsesCallback,
weak_ptr_factory_.GetWeakPtr(), callback);
+
+ scoped_ptr<MatchAllContext> context(
+ new MatchAllContext(std::move(request), match_params, pending_callback));
scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::MatchAllImpl,
weak_ptr_factory_.GetWeakPtr(),
- pending_callback));
+ base::Passed(std::move(context))));
}
void CacheStorageCache::BatchOperation(
@@ -427,50 +437,63 @@ void CacheStorageCache::Close(const base::Closure& callback) {
pending_callback));
}
-int64_t CacheStorageCache::MemoryBackedSize() const {
- if (backend_state_ != BACKEND_OPEN || !memory_only_)
- return 0;
+void CacheStorageCache::Size(const SizeCallback& callback) {
+ if (!LazyInitialize()) {
+ // TODO(jkarlin): Delete caches that can't be initialized.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, 0));
+ return;
+ }
- scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
- backend_->CreateIterator();
- disk_cache::Entry* entry = nullptr;
+ if (initializing_) {
+ // Note that Size doesn't use the scheduler, see header comments for why.
+ pending_size_callbacks_.push_back(callback);
+ return;
+ }
- int64_t sum = 0;
+ // Run immediately so that we don't deadlock on
+ // CacheStorageCache::PutDidDelete's call to
+ // quota_manager_proxy_->GetUsageAndQuota.
+ SizeImpl(callback);
+}
- std::vector<disk_cache::Entry*> entries;
- int rv = net::OK;
- while ((rv = backend_iter->OpenNextEntry(
- &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
- entries.push_back(entry); // Open the entries without mutating them.
+void CacheStorageCache::GetSizeThenClose(const SizeCallback& callback) {
+ if (!LazyInitialize()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, 0));
+ return;
}
- DCHECK_NE(net::ERR_IO_PENDING, rv)
- << "Memory cache operations should be synchronous.";
- for (disk_cache::Entry* entry : entries) {
- sum += entry->GetDataSize(INDEX_HEADERS) +
- entry->GetDataSize(INDEX_RESPONSE_BODY);
- entry->Close();
- }
+ SizeCallback pending_callback =
+ base::Bind(&CacheStorageCache::PendingSizeCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
- return sum;
+ scheduler_->ScheduleOperation(
+ base::Bind(&CacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(),
+ base::Bind(&CacheStorageCache::GetSizeThenCloseDidGetSize,
+ weak_ptr_factory_.GetWeakPtr(), pending_callback)));
}
CacheStorageCache::CacheStorageCache(
const GURL& origin,
+ const std::string& cache_name,
const base::FilePath& path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context)
: origin_(origin),
+ cache_name_(cache_name),
path_(path),
- request_context_getter_(request_context_getter),
- quota_manager_proxy_(quota_manager_proxy),
+ request_context_getter_(std::move(request_context_getter)),
+ quota_manager_proxy_(std::move(quota_manager_proxy)),
blob_storage_context_(blob_context),
- backend_state_(BACKEND_UNINITIALIZED),
scheduler_(new CacheStorageScheduler()),
- initializing_(false),
memory_only_(path.empty()),
weak_ptr_factory_(this) {
+ DCHECK(!origin_.is_empty());
+ DCHECK(quota_manager_proxy_.get());
+
+ quota_manager_proxy_->NotifyOriginInUse(origin_);
}
bool CacheStorageCache::LazyInitialize() {
@@ -638,28 +661,30 @@ void CacheStorageCache::MatchDidReadMetadata(
std::move(blob_data_handle));
}
-void CacheStorageCache::MatchAllImpl(const ResponsesCallback& callback) {
+void CacheStorageCache::MatchAllImpl(scoped_ptr<MatchAllContext> context) {
DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
if (backend_state_ != BACKEND_OPEN) {
- callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Responses>(),
- scoped_ptr<BlobDataHandles>());
+ context->original_callback.Run(CACHE_STORAGE_ERROR_STORAGE,
+ scoped_ptr<Responses>(),
+ scoped_ptr<BlobDataHandles>());
return;
}
OpenAllEntries(base::Bind(&CacheStorageCache::MatchAllDidOpenAllEntries,
- weak_ptr_factory_.GetWeakPtr(), callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(context))));
}
void CacheStorageCache::MatchAllDidOpenAllEntries(
- const ResponsesCallback& callback,
+ scoped_ptr<MatchAllContext> context,
scoped_ptr<OpenAllEntriesContext> entries_context,
CacheStorageError error) {
if (error != CACHE_STORAGE_OK) {
- callback.Run(error, scoped_ptr<Responses>(), scoped_ptr<BlobDataHandles>());
+ context->original_callback.Run(error, scoped_ptr<Responses>(),
+ scoped_ptr<BlobDataHandles>());
return;
}
- scoped_ptr<MatchAllContext> context(new MatchAllContext(callback));
context->entries_context.swap(entries_context);
Entries::iterator iter = context->entries_context->entries.begin();
MatchAllProcessNextEntry(std::move(context), iter);
@@ -676,6 +701,17 @@ void CacheStorageCache::MatchAllProcessNextEntry(
return;
}
+ if (context->options.ignore_search) {
+ DCHECK(context->request);
+ disk_cache::Entry* entry(*iter);
+ if (RemoveQueryParam(context->request->url) !=
+ RemoveQueryParam(GURL(entry->GetKey()))) {
+ // In this case, we don't need to read data.
+ MatchAllProcessNextEntry(std::move(context), iter + 1);
+ return;
+ }
+ }
+
ReadMetadata(*iter, base::Bind(&CacheStorageCache::MatchAllDidReadMetadata,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(std::move(context)), iter));
@@ -740,7 +776,9 @@ void CacheStorageCache::Put(const CacheStorageBatchOperation& operation,
operation.response.status_text, operation.response.response_type,
operation.response.headers, operation.response.blob_uuid,
operation.response.blob_size, operation.response.stream_url,
- operation.response.error));
+ operation.response.error, operation.response.response_time,
+ false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */));
scoped_ptr<storage::BlobDataHandle> blob_data_handle;
@@ -762,9 +800,8 @@ void CacheStorageCache::Put(const CacheStorageBatchOperation& operation,
weak_ptr_factory_.GetWeakPtr(), callback);
scoped_ptr<PutContext> put_context(
- new PutContext(origin_, std::move(request), std::move(response),
- std::move(blob_data_handle), pending_callback,
- request_context_getter_, quota_manager_proxy_));
+ new PutContext(std::move(request), std::move(response),
+ std::move(blob_data_handle), pending_callback));
scheduler_->ScheduleOperation(
base::Bind(&CacheStorageCache::PutImpl, weak_ptr_factory_.GetWeakPtr(),
@@ -781,7 +818,7 @@ void CacheStorageCache::PutImpl(scoped_ptr<PutContext> put_context) {
scoped_ptr<ServiceWorkerFetchRequest> request_copy(
new ServiceWorkerFetchRequest(*put_context->request));
- DeleteImpl(std::move(request_copy),
+ DeleteImpl(std::move(request_copy), CacheStorageCacheQueryParams(),
base::Bind(&CacheStorageCache::PutDidDelete,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(std::move(put_context))));
@@ -794,6 +831,31 @@ void CacheStorageCache::PutDidDelete(scoped_ptr<PutContext> put_context,
return;
}
+ quota_manager_proxy_->GetUsageAndQuota(
+ base::ThreadTaskRunnerHandle::Get().get(), origin_,
+ storage::kStorageTypeTemporary,
+ base::Bind(&CacheStorageCache::PutDidGetUsageAndQuota,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(put_context))));
+}
+
+void CacheStorageCache::PutDidGetUsageAndQuota(
+ scoped_ptr<PutContext> put_context,
+ storage::QuotaStatusCode status_code,
+ int64_t usage,
+ int64_t quota) {
+ if (backend_state_ != BACKEND_OPEN) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
+ return;
+ }
+
+ if (status_code != storage::kQuotaStatusOk) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
+ return;
+ }
+
+ put_context->available_bytes = quota - usage;
+
scoped_ptr<disk_cache::Entry*> scoped_entry_ptr(new disk_cache::Entry*());
disk_cache::Entry** entry_ptr = scoped_entry_ptr.get();
ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
@@ -841,6 +903,8 @@ void CacheStorageCache::PutDidCreateEntry(
response_metadata->set_response_type(
WebResponseTypeToProtoResponseType(put_context->response->response_type));
response_metadata->set_url(put_context->response->url.spec());
+ response_metadata->set_response_time(
+ put_context->response->response_time.ToInternalValue());
for (ServiceWorkerHeaderMap::const_iterator it =
put_context->response->headers.begin();
it != put_context->response->headers.end(); ++it) {
@@ -860,6 +924,12 @@ void CacheStorageCache::PutDidCreateEntry(
scoped_refptr<net::StringIOBuffer> buffer(
new net::StringIOBuffer(std::move(serialized)));
+ int64_t bytes_to_write = buffer->size() + put_context->response->blob_size;
+ if (put_context->available_bytes < bytes_to_write) {
+ put_context->callback.Run(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED);
+ return;
+ }
+
// Get a temporary copy of the entry pointer before passing it in base::Bind.
disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get();
@@ -888,13 +958,7 @@ void CacheStorageCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
// from the blob into the cache entry.
if (put_context->response->blob_uuid.empty()) {
- if (put_context->quota_manager_proxy.get()) {
- put_context->quota_manager_proxy->NotifyStorageModified(
- storage::QuotaClient::kServiceWorkerCache, put_context->origin,
- storage::kStorageTypeTemporary,
- put_context->cache_entry->GetDataSize(INDEX_HEADERS));
- }
-
+ UpdateCacheSize();
put_context->callback.Run(CACHE_STORAGE_OK);
return;
}
@@ -909,14 +973,11 @@ void CacheStorageCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
BlobToDiskCacheIDMap::KeyType blob_to_cache_key =
active_blob_to_disk_cache_writers_.Add(blob_to_cache);
- // Grab some pointers before passing put_context in Bind.
- scoped_refptr<net::URLRequestContextGetter> request_context_getter =
- put_context->request_context_getter;
scoped_ptr<storage::BlobDataHandle> blob_data_handle =
std::move(put_context->blob_data_handle);
blob_to_cache->StreamBlobToCache(
- std::move(entry), INDEX_RESPONSE_BODY, request_context_getter,
+ std::move(entry), INDEX_RESPONSE_BODY, request_context_getter_.get(),
std::move(blob_data_handle),
base::Bind(&CacheStorageCache::PutDidWriteBlobToCache,
weak_ptr_factory_.GetWeakPtr(),
@@ -939,17 +1000,32 @@ void CacheStorageCache::PutDidWriteBlobToCache(
return;
}
- if (put_context->quota_manager_proxy.get()) {
- put_context->quota_manager_proxy->NotifyStorageModified(
- storage::QuotaClient::kServiceWorkerCache, put_context->origin,
- storage::kStorageTypeTemporary,
- put_context->cache_entry->GetDataSize(INDEX_HEADERS) +
- put_context->cache_entry->GetDataSize(INDEX_RESPONSE_BODY));
- }
-
+ UpdateCacheSize();
put_context->callback.Run(CACHE_STORAGE_OK);
}
+void CacheStorageCache::UpdateCacheSize() {
+ if (backend_state_ != BACKEND_OPEN)
+ return;
+
+ // Note that the callback holds a refptr to |this| since UpdateCacheSize is
+ // often called after an operation completes and the cache might be freed.
+ int rv = backend_->CalculateSizeOfAllEntries(
+ base::Bind(&CacheStorageCache::UpdateCacheSizeGotSize, this));
+
+ if (rv != net::ERR_IO_PENDING)
+ UpdateCacheSizeGotSize(rv);
+}
+
+void CacheStorageCache::UpdateCacheSizeGotSize(int current_cache_size) {
+ int64_t old_cache_size = cache_size_;
+ cache_size_ = current_cache_size;
+
+ quota_manager_proxy_->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorkerCache, origin_,
+ storage::kStorageTypeTemporary, current_cache_size - old_cache_size);
+}
+
void CacheStorageCache::Delete(const CacheStorageBatchOperation& operation,
const ErrorCallback& callback) {
DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
@@ -966,17 +1042,27 @@ void CacheStorageCache::Delete(const CacheStorageBatchOperation& operation,
weak_ptr_factory_.GetWeakPtr(), callback);
scheduler_->ScheduleOperation(
base::Bind(&CacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(),
- base::Passed(std::move(request)), pending_callback));
+ base::Passed(std::move(request)), operation.match_params,
+ pending_callback));
}
void CacheStorageCache::DeleteImpl(
scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCacheQueryParams& match_params,
const ErrorCallback& callback) {
DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
if (backend_state_ != BACKEND_OPEN) {
callback.Run(CACHE_STORAGE_ERROR_STORAGE);
return;
}
+
+ if (match_params.ignore_search) {
+ OpenAllEntries(base::Bind(&CacheStorageCache::DeleteDidOpenAllEntries,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(request)), callback));
+ return;
+ }
+
scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
disk_cache::Entry** entry_ptr = entry.get();
@@ -986,7 +1072,7 @@ void CacheStorageCache::DeleteImpl(
net::CompletionCallback open_entry_callback = base::Bind(
&CacheStorageCache::DeleteDidOpenEntry, weak_ptr_factory_.GetWeakPtr(),
origin_, base::Passed(std::move(request)), callback,
- base::Passed(std::move(entry)), quota_manager_proxy_);
+ base::Passed(std::move(entry)));
int rv = backend_->OpenEntry(request_ptr->url.spec(), entry_ptr,
open_entry_callback);
@@ -994,12 +1080,35 @@ void CacheStorageCache::DeleteImpl(
open_entry_callback.Run(rv);
}
+void CacheStorageCache::DeleteDidOpenAllEntries(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ErrorCallback& callback,
+ scoped_ptr<OpenAllEntriesContext> entries_context,
+ CacheStorageError error) {
+ if (error != CACHE_STORAGE_OK) {
+ callback.Run(error);
+ return;
+ }
+
+ GURL request_url_without_query = RemoveQueryParam(request->url);
+ for (Entries::iterator iter = entries_context->entries.begin();
+ iter != entries_context->entries.end(); iter++) {
+ disk_cache::Entry* entry(*iter);
+ if (request_url_without_query == RemoveQueryParam(GURL(entry->GetKey())))
+ entry->Doom();
+ }
+
+ entries_context.reset();
+
+ UpdateCacheSize();
+ callback.Run(CACHE_STORAGE_OK);
+}
+
void CacheStorageCache::DeleteDidOpenEntry(
const GURL& origin,
scoped_ptr<ServiceWorkerFetchRequest> request,
const CacheStorageCache::ErrorCallback& callback,
scoped_ptr<disk_cache::Entry*> entry_ptr,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
int rv) {
if (rv != net::OK) {
callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND);
@@ -1009,15 +1118,10 @@ void CacheStorageCache::DeleteDidOpenEntry(
DCHECK(entry_ptr);
disk_cache::ScopedEntryPtr entry(*entry_ptr);
- if (quota_manager_proxy.get()) {
- quota_manager_proxy->NotifyStorageModified(
- storage::QuotaClient::kServiceWorkerCache, origin,
- storage::kStorageTypeTemporary,
- -1 * (entry->GetDataSize(INDEX_HEADERS) +
- entry->GetDataSize(INDEX_RESPONSE_BODY)));
- }
-
entry->Doom();
+ entry.reset();
+
+ UpdateCacheSize();
callback.Run(CACHE_STORAGE_OK);
}
@@ -1107,6 +1211,19 @@ void CacheStorageCache::CloseImpl(const base::Closure& callback) {
callback.Run();
}
+void CacheStorageCache::SizeImpl(const SizeCallback& callback) {
+ DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
+
+ int64_t size = backend_state_ == BACKEND_OPEN ? cache_size_ : 0;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, size));
+}
+
+void CacheStorageCache::GetSizeThenCloseDidGetSize(const SizeCallback& callback,
+ int64_t cache_size) {
+ CloseImpl(base::Bind(callback, cache_size));
+}
+
void CacheStorageCache::CreateBackend(const ErrorCallback& callback) {
DCHECK(!backend_);
@@ -1158,19 +1275,40 @@ void CacheStorageCache::InitBackend() {
scheduler_->ScheduleOperation(base::Bind(
&CacheStorageCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(),
- base::Bind(&CacheStorageCache::InitDone,
+ base::Bind(&CacheStorageCache::InitDidCreateBackend,
weak_ptr_factory_.GetWeakPtr())));
}
-void CacheStorageCache::InitDone(CacheStorageError error) {
+void CacheStorageCache::InitDidCreateBackend(
+ CacheStorageError cache_create_error) {
+ if (cache_create_error != CACHE_STORAGE_OK) {
+ InitGotCacheSize(cache_create_error, 0);
+ return;
+ }
+
+ int rv = backend_->CalculateSizeOfAllEntries(
+ base::Bind(&CacheStorageCache::InitGotCacheSize,
+ weak_ptr_factory_.GetWeakPtr(), cache_create_error));
+
+ if (rv != net::ERR_IO_PENDING)
+ InitGotCacheSize(cache_create_error, rv);
+}
+
+void CacheStorageCache::InitGotCacheSize(CacheStorageError cache_create_error,
+ int cache_size) {
+ cache_size_ = cache_size;
initializing_ = false;
- backend_state_ = (error == CACHE_STORAGE_OK && backend_ &&
+ backend_state_ = (cache_create_error == CACHE_STORAGE_OK && backend_ &&
backend_state_ == BACKEND_UNINITIALIZED)
? BACKEND_OPEN
: BACKEND_CLOSED;
- UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult", error,
- CACHE_STORAGE_ERROR_LAST + 1);
+ for (const SizeCallback& callback : pending_size_callbacks_)
+ SizeImpl(callback);
+ pending_size_callbacks_.clear();
+
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.InitBackendResult",
+ cache_create_error, CACHE_STORAGE_ERROR_LAST + 1);
scheduler_->CompleteOperationAndRunNext();
}
@@ -1227,6 +1365,15 @@ void CacheStorageCache::PendingRequestsCallback(
scheduler_->CompleteOperationAndRunNext();
}
+void CacheStorageCache::PendingSizeCallback(const SizeCallback& callback,
+ int64_t size) {
+ base::WeakPtr<CacheStorageCache> cache = weak_ptr_factory_.GetWeakPtr();
+
+ callback.Run(size);
+ if (cache)
+ scheduler_->CompleteOperationAndRunNext();
+}
+
void CacheStorageCache::PopulateResponseMetadata(
const CacheMetadata& metadata,
ServiceWorkerResponse* response) {
@@ -1235,7 +1382,9 @@ void CacheStorageCache::PopulateResponseMetadata(
metadata.response().status_text(),
ProtoResponseTypeToWebResponseType(metadata.response().response_type()),
ServiceWorkerHeaderMap(), "", 0, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown);
+ blink::WebServiceWorkerResponseErrorUnknown,
+ base::Time::FromInternalValue(metadata.response().response_time()),
+ true /* is_in_cache_storage */, cache_name_);
for (int i = 0; i < metadata.response().headers_size(); ++i) {
const CacheHeaderMap header = metadata.response().headers(i);
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.h b/chromium/content/browser/cache_storage/cache_storage_cache.h
index a9dcd4cccaf..4cb77ddb70a 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache.h
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.h
@@ -18,6 +18,7 @@
#include "content/common/cache_storage/cache_storage_types.h"
#include "content/common/service_worker/service_worker_types.h"
#include "net/disk_cache/disk_cache.h"
+#include "storage/common/quota/quota_status_code.h"
namespace net {
class URLRequestContextGetter;
@@ -38,9 +39,9 @@ class CacheStorageScheduler;
class TestCacheStorageCache;
// Represents a ServiceWorker Cache as seen in
-// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
-// The asynchronous methods are executed serially. Callbacks to the
-// public functions will be called so long as the cache object lives.
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ The
+// asynchronous methods are executed serially (except for Size). Callbacks to
+// the public functions will be called so long as the cache object lives.
class CONTENT_EXPORT CacheStorageCache
: public base::RefCounted<CacheStorageCache> {
public:
@@ -57,26 +58,31 @@ class CONTENT_EXPORT CacheStorageCache
using Requests = std::vector<ServiceWorkerFetchRequest>;
using RequestsCallback =
base::Callback<void(CacheStorageError, scoped_ptr<Requests>)>;
+ using SizeCallback = base::Callback<void(int64_t)>;
static scoped_refptr<CacheStorageCache> CreateMemoryCache(
const GURL& origin,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ const std::string& cache_name,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context);
static scoped_refptr<CacheStorageCache> CreatePersistentCache(
const GURL& origin,
+ const std::string& cache_name,
const base::FilePath& path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context);
// Returns ERROR_TYPE_NOT_FOUND if not found.
void Match(scoped_ptr<ServiceWorkerFetchRequest> request,
const ResponseCallback& callback);
- // Returns CACHE_STORAGE_OK and all responses in this cache. If there are no
- // responses, returns CACHE_STORAGE_OK and an empty vector.
- void MatchAll(const ResponsesCallback& callback);
+ // Returns CACHE_STORAGE_OK and matched responses in this cache. If there are
+ // no responses, returns CACHE_STORAGE_OK and an empty vector.
+ void MatchAll(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCacheQueryParams& match_params,
+ const ResponsesCallback& callback);
// Runs given batch operations. This corresponds to the Batch Cache Operations
// algorithm in the spec.
@@ -106,9 +112,16 @@ class CONTENT_EXPORT CacheStorageCache
// will exit early. Close should only be called once per CacheStorageCache.
void Close(const base::Closure& callback);
- // The size of the cache contents in memory. Returns 0 if the cache backend is
- // not a memory cache backend.
- int64_t MemoryBackedSize() const;
+ // The size of the cache's contents. This runs in parallel with other Cache
+ // operations. This is because QuotaManager is a dependency of the Put
+ // operation and QuotaManager calls Size. If the cache isn't yet initialized,
+ // runs immediately after initialization, before any pending operations in the
+ // scheduler are run.
+ void Size(const SizeCallback& callback);
+
+ // Gets the cache's size, closes the backend, and then runs |callback| with
+ // the cache's size.
+ void GetSizeThenClose(const SizeCallback& callback);
base::FilePath path() const { return path_; }
@@ -141,9 +154,10 @@ class CONTENT_EXPORT CacheStorageCache
CacheStorageCache(
const GURL& origin,
+ const std::string& cache_name,
const base::FilePath& path,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context);
// Async operations in progress will cancel and not run their callbacks.
@@ -171,9 +185,9 @@ class CONTENT_EXPORT CacheStorageCache
scoped_ptr<CacheMetadata> headers);
// MatchAll callbacks
- void MatchAllImpl(const ResponsesCallback& callback);
+ void MatchAllImpl(scoped_ptr<MatchAllContext> context);
void MatchAllDidOpenAllEntries(
- const ResponsesCallback& callback,
+ scoped_ptr<MatchAllContext> context,
scoped_ptr<OpenAllEntriesContext> entries_context,
CacheStorageError error);
void MatchAllProcessNextEntry(scoped_ptr<MatchAllContext> context,
@@ -190,6 +204,10 @@ class CONTENT_EXPORT CacheStorageCache
void PutImpl(scoped_ptr<PutContext> put_context);
void PutDidDelete(scoped_ptr<PutContext> put_context,
CacheStorageError delete_error);
+ void PutDidGetUsageAndQuota(scoped_ptr<PutContext> put_context,
+ storage::QuotaStatusCode status_code,
+ int64_t usage,
+ int64_t quota);
void PutDidCreateEntry(scoped_ptr<disk_cache::Entry*> entry_ptr,
scoped_ptr<PutContext> put_context,
int rv);
@@ -201,18 +219,28 @@ class CONTENT_EXPORT CacheStorageCache
disk_cache::ScopedEntryPtr entry,
bool success);
+ // Asynchronously calculates the current cache size, notifies the quota
+ // manager of any change from the last report, and sets cache_size_ to the new
+ // size. Runs |callback| once complete.
+ void UpdateCacheSize();
+ void UpdateCacheSizeGotSize(int current_cache_size);
+
// Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK.
void Delete(const CacheStorageBatchOperation& operation,
const ErrorCallback& callback);
void DeleteImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCacheQueryParams& match_params,
const ErrorCallback& callback);
- void DeleteDidOpenEntry(
- const GURL& origin,
+ void DeleteDidOpenAllEntries(
scoped_ptr<ServiceWorkerFetchRequest> request,
- const CacheStorageCache::ErrorCallback& callback,
- scoped_ptr<disk_cache::Entry*> entryptr,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
- int rv);
+ const ErrorCallback& callback,
+ scoped_ptr<OpenAllEntriesContext> entries_context,
+ CacheStorageError error);
+ void DeleteDidOpenEntry(const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const CacheStorageCache::ErrorCallback& callback,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ int rv);
// Keys callbacks.
void KeysImpl(const RequestsCallback& callback);
@@ -227,6 +255,11 @@ class CONTENT_EXPORT CacheStorageCache
void CloseImpl(const base::Closure& callback);
+ void SizeImpl(const SizeCallback& callback);
+
+ void GetSizeThenCloseDidGetSize(const SizeCallback& callback,
+ int64_t cache_size);
+
// Loads the backend and calls the callback with the result (true for
// success). The callback will always be called. Virtual for tests.
virtual void CreateBackend(const ErrorCallback& callback);
@@ -235,7 +268,8 @@ class CONTENT_EXPORT CacheStorageCache
int rv);
void InitBackend();
- void InitDone(CacheStorageError error);
+ void InitDidCreateBackend(CacheStorageError cache_create_error);
+ void InitGotCacheSize(CacheStorageError cache_create_error, int cache_size);
void PendingClosure(const base::Closure& callback);
void PendingErrorCallback(const ErrorCallback& callback,
@@ -252,6 +286,7 @@ class CONTENT_EXPORT CacheStorageCache
void PendingRequestsCallback(const RequestsCallback& callback,
CacheStorageError error,
scoped_ptr<Requests> requests);
+ void PendingSizeCallback(const SizeCallback& callback, int64_t size);
void PopulateResponseMetadata(const CacheMetadata& metadata,
ServiceWorkerResponse* response);
@@ -263,13 +298,16 @@ class CONTENT_EXPORT CacheStorageCache
scoped_ptr<disk_cache::Backend> backend_;
GURL origin_;
+ const std::string cache_name_;
base::FilePath path_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
- BackendState backend_state_;
+ BackendState backend_state_ = BACKEND_UNINITIALIZED;
scoped_ptr<CacheStorageScheduler> scheduler_;
- bool initializing_;
+ std::vector<SizeCallback> pending_size_callbacks_;
+ bool initializing_ = false;
+ int64_t cache_size_ = 0;
// Owns the elements of the list
BlobToDiskCacheIDMap active_blob_to_disk_cache_writers_;
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
index b440758990e..a8200769fb2 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -23,6 +23,7 @@
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/referrer.h"
+#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/test_completion_callback.h"
@@ -41,6 +42,8 @@ namespace content {
namespace {
const char kTestData[] = "Hello World";
+const char kOrigin[] = "http://example.com";
+const char kCacheName[] = "test_cache";
// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
// the memory.
@@ -188,6 +191,14 @@ bool ResponseMetadataEqual(const ServiceWorkerResponse& expected,
return false;
}
+ EXPECT_EQ(expected.response_time, actual.response_time);
+ if (expected.response_time != actual.response_time)
+ return false;
+
+ EXPECT_EQ(expected.cache_storage_cache_name, actual.cache_storage_cache_name);
+ if (expected.cache_storage_cache_name != actual.cache_storage_cache_name)
+ return false;
+
return true;
}
@@ -198,6 +209,14 @@ bool ResponseBodiesEqual(const std::string& expected_body,
return expected_body == actual_body;
}
+ServiceWorkerResponse SetCacheName(const ServiceWorkerResponse& original) {
+ return ServiceWorkerResponse(
+ original.url, original.status_code, original.status_text,
+ original.response_type, original.headers, original.blob_uuid,
+ original.blob_size, original.stream_url, original.error,
+ original.response_time, true, kCacheName);
+}
+
} // namespace
// A CacheStorageCache that can optionally delay during backend creation.
@@ -205,11 +224,13 @@ class TestCacheStorageCache : public CacheStorageCache {
public:
TestCacheStorageCache(
const GURL& origin,
+ const std::string& cache_name,
const base::FilePath& path,
const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext> blob_context)
: CacheStorageCache(origin,
+ cache_name,
path,
request_context_getter,
quota_manager_proxy,
@@ -253,9 +274,7 @@ class TestCacheStorageCache : public CacheStorageCache {
class CacheStorageCacheTest : public testing::Test {
public:
CacheStorageCacheTest()
- : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- callback_error_(CACHE_STORAGE_OK),
- callback_closed_(false) {}
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
ChromeBlobStorageContext* blob_storage_context =
@@ -264,8 +283,19 @@ class CacheStorageCacheTest : public testing::Test {
base::RunLoop().RunUntilIdle();
blob_storage_context_ = blob_storage_context->context();
+ if (!MemoryOnly())
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ quota_policy_ = new MockSpecialStoragePolicy;
+ mock_quota_manager_ = new MockQuotaManager(
+ MemoryOnly() /* is incognito */, temp_dir_.path(),
+ base::ThreadTaskRunnerHandle::Get().get(),
+ base::ThreadTaskRunnerHandle::Get().get(), quota_policy_.get());
+ mock_quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypeTemporary,
+ 1024 * 1024 * 100);
+
quota_manager_proxy_ = new MockQuotaManagerProxy(
- nullptr, base::ThreadTaskRunnerHandle::Get().get());
+ mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
url_request_job_factory_->SetProtocolHandler(
@@ -278,13 +308,10 @@ class CacheStorageCacheTest : public testing::Test {
CreateRequests(blob_storage_context);
- if (!MemoryOnly())
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = MemoryOnly() ? base::FilePath() : temp_dir_.path();
-
cache_ = make_scoped_refptr(new TestCacheStorageCache(
- GURL("http://example.com"), path, browser_context_.GetRequestContext(),
- quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr()));
+ GURL(kOrigin), kCacheName, temp_dir_.path(),
+ browser_context_.GetRequestContext(), quota_manager_proxy_,
+ blob_storage_context->context()->AsWeakPtr()));
}
void TearDown() override {
@@ -299,6 +326,9 @@ class CacheStorageCacheTest : public testing::Test {
body_request_ =
ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
headers, Referrer(), false);
+ body_request_with_query_ = ServiceWorkerFetchRequest(
+ GURL("http://example.com/body.html?query=test"), "GET", headers,
+ Referrer(), false);
no_body_request_ =
ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
"GET", headers, Referrer(), false);
@@ -318,12 +348,24 @@ class CacheStorageCacheTest : public testing::Test {
GURL("http://example.com/body.html"), 200, "OK",
blink::WebServiceWorkerResponseTypeDefault, headers,
blob_handle_->uuid(), expected_blob_data_.size(), GURL(),
- blink::WebServiceWorkerResponseErrorUnknown);
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time::Now(),
+ false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */);
+
+ body_response_with_query_ = ServiceWorkerResponse(
+ GURL("http://example.com/body.html?query=test"), 200, "OK",
+ blink::WebServiceWorkerResponseTypeDefault, headers,
+ blob_handle_->uuid(), expected_blob_data_.size(), GURL(),
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time::Now(),
+ false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */);
no_body_response_ = ServiceWorkerResponse(
GURL("http://example.com/no_body.html"), 200, "OK",
blink::WebServiceWorkerResponseTypeDefault, headers, "", 0, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown);
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time::Now(),
+ false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */);
}
scoped_ptr<ServiceWorkerFetchRequest> CopyFetchRequest(
@@ -372,20 +414,33 @@ class CacheStorageCacheTest : public testing::Test {
return callback_error_ == CACHE_STORAGE_OK;
}
- bool MatchAll(scoped_ptr<CacheStorageCache::Responses>* responses,
+ bool MatchAll(const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params,
+ scoped_ptr<CacheStorageCache::Responses>* responses,
scoped_ptr<CacheStorageCache::BlobDataHandles>* body_handles) {
base::RunLoop loop;
- cache_->MatchAll(base::Bind(
- &CacheStorageCacheTest::ResponsesAndErrorCallback,
- base::Unretained(this), loop.QuitClosure(), responses, body_handles));
+ cache_->MatchAll(
+ CopyFetchRequest(request), match_params,
+ base::Bind(&CacheStorageCacheTest::ResponsesAndErrorCallback,
+ base::Unretained(this), loop.QuitClosure(), responses,
+ body_handles));
loop.Run();
return callback_error_ == CACHE_STORAGE_OK;
}
- bool Delete(const ServiceWorkerFetchRequest& request) {
+ bool MatchAll(scoped_ptr<CacheStorageCache::Responses>* responses,
+ scoped_ptr<CacheStorageCache::BlobDataHandles>* body_handles) {
+ return MatchAll(ServiceWorkerFetchRequest(), CacheStorageCacheQueryParams(),
+ responses, body_handles);
+ }
+
+ bool Delete(const ServiceWorkerFetchRequest& request,
+ const CacheStorageCacheQueryParams& match_params =
+ CacheStorageCacheQueryParams()) {
CacheStorageBatchOperation operation;
operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE;
operation.request = request;
+ operation.match_params = match_params;
CacheStorageError error =
BatchOperation(std::vector<CacheStorageBatchOperation>(1, operation));
@@ -413,6 +468,32 @@ class CacheStorageCacheTest : public testing::Test {
return callback_closed_;
}
+ int64_t Size() {
+ // Storage notification happens after an operation completes. Let the any
+ // notifications complete before calling Size.
+ base::RunLoop().RunUntilIdle();
+
+ base::RunLoop run_loop;
+ bool callback_called = false;
+ cache_->Size(base::Bind(&CacheStorageCacheTest::SizeCallback,
+ base::Unretained(this), &run_loop,
+ &callback_called));
+ run_loop.Run();
+ EXPECT_TRUE(callback_called);
+ return callback_size_;
+ }
+
+ int64_t GetSizeThenClose() {
+ base::RunLoop run_loop;
+ bool callback_called = false;
+ cache_->GetSizeThenClose(base::Bind(&CacheStorageCacheTest::SizeCallback,
+ base::Unretained(this), &run_loop,
+ &callback_called));
+ run_loop.Run();
+ EXPECT_TRUE(callback_called);
+ return callback_size_;
+ }
+
void RequestsCallback(base::RunLoop* run_loop,
CacheStorageError error,
scoped_ptr<CacheStorageCache::Requests> requests) {
@@ -477,6 +558,15 @@ class CacheStorageCacheTest : public testing::Test {
run_loop->Quit();
}
+ void SizeCallback(base::RunLoop* run_loop,
+ bool* callback_called,
+ int64_t size) {
+ *callback_called = true;
+ callback_size_ = size;
+ if (run_loop)
+ run_loop->Quit();
+ }
+
bool VerifyKeys(const std::vector<std::string>& expected_keys) {
if (expected_keys.size() != callback_strings_.size())
return false;
@@ -514,6 +604,8 @@ class CacheStorageCacheTest : public testing::Test {
TestBrowserContext browser_context_;
TestBrowserThreadBundle browser_thread_bundle_;
scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
+ scoped_refptr<MockSpecialStoragePolicy> quota_policy_;
+ scoped_refptr<MockQuotaManager> mock_quota_manager_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
storage::BlobStorageContext* blob_storage_context_;
@@ -521,16 +613,19 @@ class CacheStorageCacheTest : public testing::Test {
ServiceWorkerFetchRequest body_request_;
ServiceWorkerResponse body_response_;
+ ServiceWorkerFetchRequest body_request_with_query_;
+ ServiceWorkerResponse body_response_with_query_;
ServiceWorkerFetchRequest no_body_request_;
ServiceWorkerResponse no_body_response_;
scoped_ptr<storage::BlobDataHandle> blob_handle_;
std::string expected_blob_data_;
- CacheStorageError callback_error_;
+ CacheStorageError callback_error_ = CACHE_STORAGE_OK;
scoped_ptr<ServiceWorkerResponse> callback_response_;
scoped_ptr<storage::BlobDataHandle> callback_response_data_;
std::vector<std::string> callback_strings_;
- bool callback_closed_;
+ bool callback_closed_ = false;
+ int64_t callback_size_ = 0;
};
class CacheStorageCacheTestP : public CacheStorageCacheTest,
@@ -538,12 +633,6 @@ class CacheStorageCacheTestP : public CacheStorageCacheTest,
bool MemoryOnly() override { return !GetParam(); }
};
-class CacheStorageCacheMemoryOnlyTest
- : public CacheStorageCacheTest,
- public testing::WithParamInterface<bool> {
- bool MemoryOnly() override { return true; }
-};
-
TEST_P(CacheStorageCacheTestP, PutNoBody) {
EXPECT_TRUE(Put(no_body_request_, no_body_response_));
}
@@ -666,14 +755,16 @@ TEST_P(CacheStorageCacheTestP, PutReplcaceInBatch) {
TEST_P(CacheStorageCacheTestP, MatchNoBody) {
EXPECT_TRUE(Put(no_body_request_, no_body_response_));
EXPECT_TRUE(Match(no_body_request_));
- EXPECT_TRUE(ResponseMetadataEqual(no_body_response_, *callback_response_));
+ EXPECT_TRUE(ResponseMetadataEqual(SetCacheName(no_body_response_),
+ *callback_response_));
EXPECT_FALSE(callback_response_data_);
}
TEST_P(CacheStorageCacheTestP, MatchBody) {
EXPECT_TRUE(Put(body_request_, body_response_));
EXPECT_TRUE(Match(body_request_));
- EXPECT_TRUE(ResponseMetadataEqual(body_response_, *callback_response_));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(body_response_), *callback_response_));
EXPECT_TRUE(
ResponseBodiesEqual(expected_blob_data_, *callback_response_data_));
}
@@ -694,7 +785,8 @@ TEST_P(CacheStorageCacheTestP, MatchAll_NoBody) {
EXPECT_TRUE(MatchAll(&responses, &body_handles));
ASSERT_EQ(1u, responses->size());
- EXPECT_TRUE(ResponseMetadataEqual(no_body_response_, responses->at(0)));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(no_body_response_), responses->at(0)));
EXPECT_TRUE(body_handles->empty());
}
@@ -707,7 +799,8 @@ TEST_P(CacheStorageCacheTestP, MatchAll_Body) {
ASSERT_EQ(1u, responses->size());
ASSERT_EQ(1u, body_handles->size());
- EXPECT_TRUE(ResponseMetadataEqual(body_response_, responses->at(0)));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(body_response_), responses->at(0)));
EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, body_handles->at(0)));
}
@@ -725,10 +818,12 @@ TEST_P(CacheStorageCacheTestP, MatchAll_TwoResponsesThenOne) {
std::set<std::string> matched_set;
for (const ServiceWorkerResponse& response : *responses) {
if (response.url.spec() == "http://example.com/no_body.html") {
- EXPECT_TRUE(ResponseMetadataEqual(no_body_response_, response));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(no_body_response_), response));
matched_set.insert(response.url.spec());
} else if (response.url.spec() == "http://example.com/body.html") {
- EXPECT_TRUE(ResponseMetadataEqual(body_response_, response));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(body_response_), response));
EXPECT_TRUE(
ResponseBodiesEqual(expected_blob_data_, body_handles->at(0)));
matched_set.insert(response.url.spec());
@@ -743,10 +838,41 @@ TEST_P(CacheStorageCacheTestP, MatchAll_TwoResponsesThenOne) {
EXPECT_TRUE(MatchAll(&responses, &body_handles));
ASSERT_EQ(1u, responses->size());
- EXPECT_TRUE(ResponseMetadataEqual(no_body_response_, responses->at(0)));
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(no_body_response_), responses->at(0)));
EXPECT_TRUE(body_handles->empty());
}
+TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreSearch) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+
+ scoped_ptr<CacheStorageCache::Responses> responses;
+ scoped_ptr<CacheStorageCache::BlobDataHandles> body_handles;
+ CacheStorageCacheQueryParams match_params;
+ match_params.ignore_search = true;
+ EXPECT_TRUE(MatchAll(body_request_, match_params, &responses, &body_handles));
+
+ ASSERT_EQ(2u, responses->size());
+ ASSERT_EQ(2u, body_handles->size());
+
+ // Order of returned responses is not guaranteed.
+ std::set<std::string> matched_set;
+ for (const ServiceWorkerResponse& response : *responses) {
+ if (response.url.spec() == "http://example.com/body.html?query=test") {
+ EXPECT_TRUE(ResponseMetadataEqual(SetCacheName(body_response_with_query_),
+ response));
+ matched_set.insert(response.url.spec());
+ } else if (response.url.spec() == "http://example.com/body.html") {
+ EXPECT_TRUE(
+ ResponseMetadataEqual(SetCacheName(body_response_), response));
+ matched_set.insert(response.url.spec());
+ }
+ }
+ EXPECT_EQ(2u, matched_set.size());
+}
+
TEST_P(CacheStorageCacheTestP, Vary) {
body_request_.headers["vary_foo"] = "foo";
body_response_.headers["vary"] = "vary_foo";
@@ -863,6 +989,61 @@ TEST_P(CacheStorageCacheTestP, DeleteBody) {
EXPECT_TRUE(Delete(body_request_));
}
+TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchTrue) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(3u, callback_strings_.size());
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back(no_body_request_.url.spec());
+ expected_keys.push_back(body_request_.url.spec());
+ expected_keys.push_back(body_request_with_query_.url.spec());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+
+ // The following delete operation will remove both of body_request_ and
+ // body_request_with_query_ from cache storage.
+ CacheStorageCacheQueryParams match_params;
+ match_params.ignore_search = true;
+ EXPECT_TRUE(Delete(body_request_with_query_, match_params));
+
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(1u, callback_strings_.size());
+ expected_keys.clear();
+ expected_keys.push_back(no_body_request_.url.spec());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+}
+
+TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchFalse) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(3u, callback_strings_.size());
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back(no_body_request_.url.spec());
+ expected_keys.push_back(body_request_.url.spec());
+ expected_keys.push_back(body_request_with_query_.url.spec());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+
+ // Default value of ignore_search is false.
+ CacheStorageCacheQueryParams match_params;
+ match_params.ignore_search = false;
+ EXPECT_EQ(match_params.ignore_search,
+ CacheStorageCacheQueryParams().ignore_search);
+
+ EXPECT_TRUE(Delete(body_request_with_query_, match_params));
+
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(2u, callback_strings_.size());
+ expected_keys.clear();
+ expected_keys.push_back(no_body_request_.url.spec());
+ expected_keys.push_back(body_request_.url.spec());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+}
+
TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
for (int i = 0; i < 100; ++i) {
EXPECT_FALSE(Match(no_body_request_));
@@ -895,7 +1076,9 @@ TEST_F(CacheStorageCacheTest, CaselessServiceWorkerResponseHeaders) {
ServiceWorkerResponse response(GURL("http://www.example.com"), 200, "OK",
blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(), "", 0, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown);
+ blink::WebServiceWorkerResponseErrorUnknown,
+ base::Time(), false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */);
response.headers["content-type"] = "foo";
response.headers["Content-Type"] = "bar";
EXPECT_EQ("bar", response.headers["content-type"]);
@@ -916,46 +1099,95 @@ TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ // Storage notification happens after the operation returns, so continue the
+ // event loop.
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count());
EXPECT_LT(0, quota_manager_proxy_->last_notified_delta());
int64_t sum_delta = quota_manager_proxy_->last_notified_delta();
EXPECT_TRUE(Put(body_request_, body_response_));
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count());
EXPECT_LT(sum_delta, quota_manager_proxy_->last_notified_delta());
sum_delta += quota_manager_proxy_->last_notified_delta();
EXPECT_TRUE(Delete(body_request_));
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, quota_manager_proxy_->notify_storage_modified_count());
sum_delta += quota_manager_proxy_->last_notified_delta();
EXPECT_TRUE(Delete(no_body_request_));
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(4, quota_manager_proxy_->notify_storage_modified_count());
sum_delta += quota_manager_proxy_->last_notified_delta();
EXPECT_EQ(0, sum_delta);
}
-TEST_F(CacheStorageCacheMemoryOnlyTest, MemoryBackedSize) {
- EXPECT_EQ(0, cache_->MemoryBackedSize());
+TEST_P(CacheStorageCacheTestP, PutObeysQuotaLimits) {
+ mock_quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypeTemporary,
+ 0);
+ EXPECT_FALSE(Put(no_body_request_, no_body_response_));
+ EXPECT_EQ(CACHE_STORAGE_ERROR_QUOTA_EXCEEDED, callback_error_);
+}
+
+TEST_P(CacheStorageCacheTestP, Size) {
+ EXPECT_EQ(0, Size());
EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_LT(0, cache_->MemoryBackedSize());
- int64_t no_body_size = cache_->MemoryBackedSize();
+ EXPECT_LT(0, Size());
+ int64_t no_body_size = Size();
EXPECT_TRUE(Delete(no_body_request_));
- EXPECT_EQ(0, cache_->MemoryBackedSize());
+ EXPECT_EQ(0, Size());
EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_LT(no_body_size, cache_->MemoryBackedSize());
+ EXPECT_LT(no_body_size, Size());
EXPECT_TRUE(Delete(body_request_));
- EXPECT_EQ(0, cache_->MemoryBackedSize());
+ EXPECT_EQ(0, Size());
}
-TEST_F(CacheStorageCacheTest, MemoryBackedSizePersistent) {
- EXPECT_EQ(0, cache_->MemoryBackedSize());
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_EQ(0, cache_->MemoryBackedSize());
+TEST_P(CacheStorageCacheTestP, SizeOperationsArePrioritized) {
+ // Test that pending size operations (those waiting for initialization) run
+ // before other scheduler operations.
+ cache_->set_delay_backend_creation(true); // Delay cache initialization
+
+ CacheStorageBatchOperation operation;
+ operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
+ operation.request = body_request_;
+ operation.response = body_response_;
+
+ callback_error_ = CACHE_STORAGE_ERROR_NOT_FOUND;
+ base::RunLoop run_loop;
+ // Start a put operation that blocks on initialization.
+ cache_->BatchOperation(std::vector<CacheStorageBatchOperation>(1, operation),
+ base::Bind(&CacheStorageCacheTest::ErrorTypeCallback,
+ base::Unretained(this), &run_loop));
+
+ // Next start a size operation that also blocks on initialization.
+ bool size_callback_called = false;
+ cache_->Size(base::Bind(&CacheStorageCacheTest::SizeCallback,
+ base::Unretained(this), nullptr,
+ &size_callback_called));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(size_callback_called);
+ EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+
+ // Finish initialization. The Size operation should complete before Put gets
+ // to run as Size has priority. See crbug.com/605663.
+ cache_->ContinueCreateBackend();
+ run_loop.Run();
+ EXPECT_TRUE(size_callback_called);
+ EXPECT_EQ(CACHE_STORAGE_OK, callback_error_);
+}
+
+TEST_P(CacheStorageCacheTestP, GetSizeThenClose) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ int64_t cache_size = Size();
+ EXPECT_EQ(cache_size, GetSizeThenClose());
+ VerifyAllOpsFail();
}
TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackendNeverCreated) {
diff --git a/chromium/content/browser/cache_storage/cache_storage_context_impl.cc b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
index 83aa12d6cdc..e58d790939c 100644
--- a/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -28,8 +28,7 @@ CacheStorageContextImpl::~CacheStorageContextImpl() {
void CacheStorageContextImpl::Init(
const base::FilePath& user_data_directory,
- storage::QuotaManagerProxy* quota_manager_proxy,
- storage::SpecialStoragePolicy* special_storage_policy) {
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
is_incognito_ = user_data_directory.empty();
@@ -45,7 +44,7 @@ void CacheStorageContextImpl::Init(
// TODO: Fix the tests to let the quota manager initialize normally.
if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
CreateCacheStorageManager(user_data_directory, cache_task_runner,
- quota_manager_proxy, special_storage_policy);
+ std::move(quota_manager_proxy));
return;
}
@@ -53,8 +52,7 @@ void CacheStorageContextImpl::Init(
BrowserThread::IO, FROM_HERE,
base::Bind(&CacheStorageContextImpl::CreateCacheStorageManager, this,
user_data_directory, cache_task_runner,
- make_scoped_refptr(quota_manager_proxy),
- make_scoped_refptr(special_storage_policy)));
+ std::move(quota_manager_proxy)));
}
void CacheStorageContextImpl::Shutdown() {
@@ -103,15 +101,13 @@ void CacheStorageContextImpl::DeleteForOrigin(const GURL& origin) {
void CacheStorageContextImpl::CreateCacheStorageManager(
const base::FilePath& user_data_directory,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- storage::QuotaManagerProxy* quota_manager_proxy,
- storage::SpecialStoragePolicy* special_storage_policy) {
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!cache_manager_);
- cache_manager_ =
- CacheStorageManager::Create(user_data_directory, cache_task_runner.get(),
- make_scoped_refptr(quota_manager_proxy));
+ cache_manager_ = CacheStorageManager::Create(
+ user_data_directory, cache_task_runner, std::move(quota_manager_proxy));
}
void CacheStorageContextImpl::ShutdownOnIO() {
diff --git a/chromium/content/browser/cache_storage/cache_storage_context_impl.h b/chromium/content/browser/cache_storage/cache_storage_context_impl.h
index d72babf1d37..f404fa86d31 100644
--- a/chromium/content/browser/cache_storage/cache_storage_context_impl.h
+++ b/chromium/content/browser/cache_storage/cache_storage_context_impl.h
@@ -44,8 +44,7 @@ class CONTENT_EXPORT CacheStorageContextImpl
// Init and Shutdown are for use on the UI thread when the profile,
// storagepartition is being setup and torn down.
void Init(const base::FilePath& user_data_directory,
- storage::QuotaManagerProxy* quota_manager_proxy,
- storage::SpecialStoragePolicy* special_storage_policy);
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
void Shutdown();
// Only callable on the IO thread.
@@ -73,9 +72,8 @@ class CONTENT_EXPORT CacheStorageContextImpl
private:
void CreateCacheStorageManager(
const base::FilePath& user_data_directory,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- storage::QuotaManagerProxy* quota_manager_proxy,
- storage::SpecialStoragePolicy* special_storage_policy);
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
void ShutdownOnIO();
diff --git a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 073f57d8027..f371be943dc 100644
--- a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -22,6 +22,8 @@
#include "content/public/common/origin_util.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCacheError.h"
+#include "url/gurl.h"
+#include "url/origin.h"
namespace content {
@@ -43,13 +45,17 @@ blink::WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
return blink::WebServiceWorkerCacheErrorNotFound;
case CACHE_STORAGE_ERROR_NOT_FOUND:
return blink::WebServiceWorkerCacheErrorNotFound;
+ case CACHE_STORAGE_ERROR_QUOTA_EXCEEDED:
+ return blink::WebServiceWorkerCacheErrorQuotaExceeded;
+ case CACHE_STORAGE_ERROR_CACHE_NAME_NOT_FOUND:
+ return blink::WebServiceWorkerCacheErrorCacheNameNotFound;
}
NOTREACHED();
return blink::WebServiceWorkerCacheErrorNotImplemented;
}
-bool OriginCanAccessCacheStorage(const GURL& url) {
- return IsOriginSecure(url);
+bool OriginCanAccessCacheStorage(const url::Origin& origin) {
+ return !origin.unique() && IsOriginSecure(GURL(origin.Serialize()));
}
} // namespace
@@ -67,7 +73,7 @@ void CacheStorageDispatcherHost::Init(CacheStorageContextImpl* context) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&CacheStorageDispatcherHost::CreateCacheListener, this,
- make_scoped_refptr(context)));
+ base::RetainedRef(context)));
}
void CacheStorageDispatcherHost::OnDestruct() const {
@@ -110,7 +116,7 @@ void CacheStorageDispatcherHost::CreateCacheListener(
void CacheStorageDispatcherHost::OnCacheStorageHas(
int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name) {
TRACE_EVENT0("CacheStorage", "CacheStorageDispatcherHost::OnCacheStorageHas");
if (!OriginCanAccessCacheStorage(origin)) {
@@ -118,7 +124,7 @@ void CacheStorageDispatcherHost::OnCacheStorageHas(
return;
}
context_->cache_manager()->HasCache(
- origin, base::UTF16ToUTF8(cache_name),
+ GURL(origin.Serialize()), base::UTF16ToUTF8(cache_name),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageHasCallback, this,
thread_id, request_id));
}
@@ -126,7 +132,7 @@ void CacheStorageDispatcherHost::OnCacheStorageHas(
void CacheStorageDispatcherHost::OnCacheStorageOpen(
int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name) {
TRACE_EVENT0("CacheStorage",
"CacheStorageDispatcherHost::OnCacheStorageOpen");
@@ -135,7 +141,7 @@ void CacheStorageDispatcherHost::OnCacheStorageOpen(
return;
}
context_->cache_manager()->OpenCache(
- origin, base::UTF16ToUTF8(cache_name),
+ GURL(origin.Serialize()), base::UTF16ToUTF8(cache_name),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageOpenCallback, this,
thread_id, request_id));
}
@@ -143,7 +149,7 @@ void CacheStorageDispatcherHost::OnCacheStorageOpen(
void CacheStorageDispatcherHost::OnCacheStorageDelete(
int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name) {
TRACE_EVENT0("CacheStorage",
"CacheStorageDispatcherHost::OnCacheStorageDelete");
@@ -152,14 +158,14 @@ void CacheStorageDispatcherHost::OnCacheStorageDelete(
return;
}
context_->cache_manager()->DeleteCache(
- origin, base::UTF16ToUTF8(cache_name),
+ GURL(origin.Serialize()), base::UTF16ToUTF8(cache_name),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageDeleteCallback,
this, thread_id, request_id));
}
void CacheStorageDispatcherHost::OnCacheStorageKeys(int thread_id,
int request_id,
- const GURL& origin) {
+ const url::Origin& origin) {
TRACE_EVENT0("CacheStorage",
"CacheStorageDispatcherHost::OnCacheStorageKeys");
if (!OriginCanAccessCacheStorage(origin)) {
@@ -167,7 +173,7 @@ void CacheStorageDispatcherHost::OnCacheStorageKeys(int thread_id,
return;
}
context_->cache_manager()->EnumerateCaches(
- origin,
+ GURL(origin.Serialize()),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageKeysCallback, this,
thread_id, request_id));
}
@@ -175,7 +181,7 @@ void CacheStorageDispatcherHost::OnCacheStorageKeys(int thread_id,
void CacheStorageDispatcherHost::OnCacheStorageMatch(
int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const ServiceWorkerFetchRequest& request,
const CacheStorageCacheQueryParams& match_params) {
TRACE_EVENT0("CacheStorage",
@@ -191,13 +197,13 @@ void CacheStorageDispatcherHost::OnCacheStorageMatch(
if (match_params.cache_name.empty()) {
context_->cache_manager()->MatchAllCaches(
- origin, std::move(scoped_request),
+ GURL(origin.Serialize()), std::move(scoped_request),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageMatchCallback,
this, thread_id, request_id));
return;
}
context_->cache_manager()->MatchCache(
- origin, base::UTF16ToUTF8(match_params.cache_name),
+ GURL(origin.Serialize()), base::UTF16ToUTF8(match_params.cache_name),
std::move(scoped_request),
base::Bind(&CacheStorageDispatcherHost::OnCacheStorageMatchCallback, this,
thread_id, request_id));
@@ -242,6 +248,7 @@ void CacheStorageDispatcherHost::OnCacheMatchAll(
scoped_refptr<CacheStorageCache> cache = it->second;
if (request.url.is_empty()) {
cache->MatchAll(
+ scoped_ptr<ServiceWorkerFetchRequest>(), match_params,
base::Bind(&CacheStorageDispatcherHost::OnCacheMatchAllCallback, this,
thread_id, request_id, cache));
return;
@@ -251,6 +258,13 @@ void CacheStorageDispatcherHost::OnCacheMatchAll(
new ServiceWorkerFetchRequest(request.url, request.method,
request.headers, request.referrer,
request.is_reload));
+ if (match_params.ignore_search) {
+ cache->MatchAll(
+ std::move(scoped_request), match_params,
+ base::Bind(&CacheStorageDispatcherHost::OnCacheMatchAllCallback, this,
+ thread_id, request_id, cache));
+ return;
+ }
cache->Match(
std::move(scoped_request),
base::Bind(&CacheStorageDispatcherHost::OnCacheMatchAllCallbackAdapter,
@@ -322,14 +336,14 @@ void CacheStorageDispatcherHost::OnCacheStorageHasCallback(
void CacheStorageDispatcherHost::OnCacheStorageOpenCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error) {
if (error != CACHE_STORAGE_OK) {
Send(new CacheStorageMsg_CacheStorageOpenError(
thread_id, request_id, ToWebServiceWorkerCacheError(error)));
return;
}
- CacheID cache_id = StoreCacheReference(cache);
+ CacheID cache_id = StoreCacheReference(std::move(cache));
Send(new CacheStorageMsg_CacheStorageOpenSuccess(thread_id, request_id,
cache_id));
}
@@ -388,7 +402,7 @@ void CacheStorageDispatcherHost::OnCacheStorageMatchCallback(
void CacheStorageDispatcherHost::OnCacheMatchCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
@@ -407,7 +421,7 @@ void CacheStorageDispatcherHost::OnCacheMatchCallback(
void CacheStorageDispatcherHost::OnCacheMatchAllCallbackAdapter(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
@@ -421,14 +435,14 @@ void CacheStorageDispatcherHost::OnCacheMatchAllCallbackAdapter(
if (blob_data_handle)
blob_data_handles->push_back(*blob_data_handle);
}
- OnCacheMatchAllCallback(thread_id, request_id, cache, error,
+ OnCacheMatchAllCallback(thread_id, request_id, std::move(cache), error,
std::move(responses), std::move(blob_data_handles));
}
void CacheStorageDispatcherHost::OnCacheMatchAllCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<CacheStorageCache::Responses> responses,
scoped_ptr<CacheStorageCache::BlobDataHandles> blob_data_handles) {
@@ -448,7 +462,7 @@ void CacheStorageDispatcherHost::OnCacheMatchAllCallback(
void CacheStorageDispatcherHost::OnCacheKeysCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<CacheStorageCache::Requests> requests) {
if (error != CACHE_STORAGE_OK) {
@@ -472,7 +486,7 @@ void CacheStorageDispatcherHost::OnCacheKeysCallback(
void CacheStorageDispatcherHost::OnCacheBatchCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error) {
if (error != CACHE_STORAGE_OK) {
Send(new CacheStorageMsg_CacheBatchError(
@@ -485,9 +499,9 @@ void CacheStorageDispatcherHost::OnCacheBatchCallback(
CacheStorageDispatcherHost::CacheID
CacheStorageDispatcherHost::StoreCacheReference(
- const scoped_refptr<CacheStorageCache>& cache) {
+ scoped_refptr<CacheStorageCache> cache) {
int cache_id = next_cache_id_++;
- id_to_cache_map_[cache_id] = cache;
+ id_to_cache_map_[cache_id] = std::move(cache);
return cache_id;
}
diff --git a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
index 77435096db2..14cfe301efb 100644
--- a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
@@ -13,6 +13,10 @@
#include "content/browser/cache_storage/cache_storage.h"
#include "content/public/browser/browser_message_filter.h"
+namespace url {
+class Origin;
+}
+
namespace content {
class CacheStorageContextImpl;
@@ -49,20 +53,22 @@ class CONTENT_EXPORT CacheStorageDispatcherHost : public BrowserMessageFilter {
// The message receiver functions for the CacheStorage API:
void OnCacheStorageHas(int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name);
void OnCacheStorageOpen(int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name);
void OnCacheStorageDelete(int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const base::string16& cache_name);
- void OnCacheStorageKeys(int thread_id, int request_id, const GURL& origin);
+ void OnCacheStorageKeys(int thread_id,
+ int request_id,
+ const url::Origin& origin);
void OnCacheStorageMatch(int thread_id,
int request_id,
- const GURL& origin,
+ const url::Origin& origin,
const ServiceWorkerFetchRequest& request,
const CacheStorageCacheQueryParams& match_params);
@@ -91,7 +97,7 @@ class CONTENT_EXPORT CacheStorageDispatcherHost : public BrowserMessageFilter {
CacheStorageError error);
void OnCacheStorageOpenCallback(int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error);
void OnCacheStorageDeleteCallback(int thread_id,
int request_id,
@@ -112,21 +118,21 @@ class CONTENT_EXPORT CacheStorageDispatcherHost : public BrowserMessageFilter {
void OnCacheMatchCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
scoped_ptr<storage::BlobDataHandle> blob_data_handle);
void OnCacheMatchAllCallbackAdapter(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<ServiceWorkerResponse> response,
scoped_ptr<storage::BlobDataHandle> blob_data_handle);
void OnCacheMatchAllCallback(
int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<std::vector<ServiceWorkerResponse>> responses,
scoped_ptr<CacheStorageCache::BlobDataHandles> blob_data_handles);
@@ -137,18 +143,18 @@ class CONTENT_EXPORT CacheStorageDispatcherHost : public BrowserMessageFilter {
const CacheStorageCacheQueryParams& match_params);
void OnCacheKeysCallback(int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error,
scoped_ptr<CacheStorageCache::Requests> requests);
void OnCacheBatchCallback(int thread_id,
int request_id,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error);
// Hangs onto a scoped_refptr for the cache if it isn't already doing so.
// Returns a unique cache_id. Call DropCacheReference when the client is done
// with this cache.
- CacheID StoreCacheReference(const scoped_refptr<CacheStorageCache>& cache);
+ CacheID StoreCacheReference(scoped_refptr<CacheStorageCache> cache);
void DropCacheReference(CacheID cache_id);
// Stores blob handles while waiting for acknowledgement of receipt from the
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.cc b/chromium/content/browser/cache_storage/cache_storage_manager.cc
index cd02deb0a0f..be2c6d7c5b1 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.cc
@@ -9,6 +9,7 @@
#include <string>
#include <utility>
+#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
@@ -23,7 +24,7 @@
#include "content/browser/cache_storage/cache_storage_quota_client.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/public/browser/browser_thread.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/common/database/database_identifier.h"
#include "storage/common/quota/quota_status_code.h"
@@ -42,11 +43,16 @@ void DeleteOriginDidDeleteDir(
bool rv) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- callback.Run(rv ? storage::kQuotaStatusOk : storage::kQuotaErrorAbort);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, rv ? storage::kQuotaStatusOk
+ : storage::kQuotaErrorAbort));
}
-std::set<GURL> ListOriginsOnDisk(base::FilePath root_path) {
- std::set<GURL> origins;
+// Open the various cache directories' index files and extract their origins and
+// last modified times.
+void ListOriginsAndLastModifiedOnTaskRunner(
+ std::vector<CacheStorageUsageInfo>* usages,
+ base::FilePath root_path) {
base::FileEnumerator file_enum(root_path, false /* recursive */,
base::FileEnumerator::DIRECTORIES);
@@ -55,33 +61,28 @@ std::set<GURL> ListOriginsOnDisk(base::FilePath root_path) {
std::string protobuf;
base::ReadFileToString(path.AppendASCII(CacheStorage::kIndexFileName),
&protobuf);
-
CacheStorageIndex index;
if (index.ParseFromString(protobuf)) {
- if (index.has_origin())
- origins.insert(GURL(index.origin()));
+ if (index.has_origin()) {
+ base::File::Info file_info;
+ if (base::GetFileInfo(path, &file_info)) {
+ usages->push_back(CacheStorageUsageInfo(
+ GURL(index.origin()), 0 /* size */, file_info.last_modified));
+ }
+ }
}
}
-
- return origins;
}
-std::vector<CacheStorageUsageInfo> GetAllOriginsUsageOnTaskRunner(
- const base::FilePath root_path) {
- std::vector<CacheStorageUsageInfo> entries;
- const std::set<GURL> origins = ListOriginsOnDisk(root_path);
- entries.reserve(origins.size());
- for (const GURL& origin : origins) {
- base::FilePath path =
- CacheStorageManager::ConstructOriginPath(root_path, origin);
- int64_t size = base::ComputeDirectorySize(path);
- base::File::Info file_info;
- base::Time last_modified;
- if (base::GetFileInfo(path, &file_info))
- last_modified = file_info.last_modified;
- entries.push_back(CacheStorageUsageInfo(origin, size, last_modified));
- }
- return entries;
+std::set<GURL> ListOriginsOnTaskRunner(base::FilePath root_path) {
+ std::vector<CacheStorageUsageInfo> usages;
+ ListOriginsAndLastModifiedOnTaskRunner(&usages, root_path);
+
+ std::set<GURL> out_origins;
+ for (const CacheStorageUsageInfo& usage : usages)
+ out_origins.insert(usage.origin);
+
+ return out_origins;
}
void GetOriginsForHostDidListOrigins(
@@ -93,26 +94,45 @@ void GetOriginsForHostDidListOrigins(
if (host == net::GetHostOrSpecFromURL(origin))
out_origins.insert(origin);
}
- callback.Run(out_origins);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, out_origins));
}
void EmptyQuotaStatusCallback(storage::QuotaStatusCode code) {}
+void AllOriginSizesReported(
+ scoped_ptr<std::vector<CacheStorageUsageInfo>> usages,
+ const CacheStorageContext::GetUsageInfoCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, *usages));
+}
+
+void OneOriginSizeReported(const base::Closure& callback,
+ CacheStorageUsageInfo* usage,
+ int64_t size) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ usage->total_size_bytes = size;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+}
+
} // namespace
// static
scoped_ptr<CacheStorageManager> CacheStorageManager::Create(
const base::FilePath& path,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy) {
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) {
base::FilePath root_path = path;
if (!path.empty()) {
root_path = path.Append(ServiceWorkerContextCore::kServiceWorkerDirectory)
.AppendASCII("CacheStorage");
}
- return make_scoped_ptr(new CacheStorageManager(root_path, cache_task_runner,
- quota_manager_proxy));
+ return make_scoped_ptr(new CacheStorageManager(
+ root_path, std::move(cache_task_runner), std::move(quota_manager_proxy)));
}
// static
@@ -191,14 +211,14 @@ void CacheStorageManager::MatchAllCaches(
}
void CacheStorageManager::SetBlobParametersForCache(
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(cache_storage_map_.empty());
DCHECK(!request_context_getter_ ||
request_context_getter_.get() == request_context_getter.get());
DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get());
- request_context_getter_ = request_context_getter;
+ request_context_getter_ = std::move(request_context_getter);
blob_context_ = blob_storage_context;
}
@@ -206,23 +226,54 @@ void CacheStorageManager::GetAllOriginsUsage(
const CacheStorageContext::GetUsageInfoCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ scoped_ptr<std::vector<CacheStorageUsageInfo>> usages(
+ new std::vector<CacheStorageUsageInfo>());
+
if (IsMemoryBacked()) {
- std::vector<CacheStorageUsageInfo> entries;
- entries.reserve(cache_storage_map_.size());
for (const auto& origin_details : cache_storage_map_) {
- entries.push_back(CacheStorageUsageInfo(
- origin_details.first, origin_details.second->MemoryBackedSize(),
- base::Time()));
+ usages->push_back(
+ CacheStorageUsageInfo(origin_details.first, 0 /* size */,
+ base::Time() /* last modified */));
}
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(callback, entries));
+ GetAllOriginsUsageGetSizes(std::move(usages), callback);
return;
}
- PostTaskAndReplyWithResult(
- cache_task_runner_.get(), FROM_HERE,
- base::Bind(&GetAllOriginsUsageOnTaskRunner, root_path_),
- base::Bind(callback));
+ std::vector<CacheStorageUsageInfo>* usages_ptr = usages.get();
+ cache_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&ListOriginsAndLastModifiedOnTaskRunner, usages_ptr,
+ root_path_),
+ base::Bind(&CacheStorageManager::GetAllOriginsUsageGetSizes,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(usages)), callback));
+}
+
+void CacheStorageManager::GetAllOriginsUsageGetSizes(
+ scoped_ptr<std::vector<CacheStorageUsageInfo>> usages,
+ const CacheStorageContext::GetUsageInfoCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(usages);
+
+ // The origin GURL and last modified times are set in |usages| but not the
+ // size in bytes. Call each CacheStorage's Size() function to fill that out.
+ std::vector<CacheStorageUsageInfo>* usages_ptr = usages.get();
+
+ if (usages->empty()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, *usages));
+ return;
+ }
+
+ base::Closure barrier_closure = base::BarrierClosure(
+ usages_ptr->size(),
+ base::Bind(&AllOriginSizesReported, base::Passed(std::move(usages)),
+ callback));
+
+ for (CacheStorageUsageInfo& usage : *usages_ptr) {
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(usage.origin);
+ cache_storage->Size(
+ base::Bind(&OneOriginSizeReported, barrier_closure, &usage));
+ }
}
void CacheStorageManager::GetOriginUsage(
@@ -230,20 +281,9 @@ void CacheStorageManager::GetOriginUsage(
const storage::QuotaClient::GetUsageCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (IsMemoryBacked()) {
- int64_t usage = 0;
- if (ContainsKey(cache_storage_map_, origin_url))
- usage = cache_storage_map_[origin_url]->MemoryBackedSize();
- callback.Run(usage);
- return;
- }
+ CacheStorage* cache_storage = FindOrCreateCacheStorage(origin_url);
- MigrateOrigin(origin_url);
- PostTaskAndReplyWithResult(
- cache_task_runner_.get(), FROM_HERE,
- base::Bind(base::ComputeDirectorySize,
- ConstructOriginPath(root_path_, origin_url)),
- base::Bind(callback));
+ cache_storage->Size(callback);
}
void CacheStorageManager::GetOrigins(
@@ -255,12 +295,13 @@ void CacheStorageManager::GetOrigins(
for (const auto& key_value : cache_storage_map_)
origins.insert(key_value.first);
- callback.Run(origins);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, origins));
return;
}
PostTaskAndReplyWithResult(cache_task_runner_.get(), FROM_HERE,
- base::Bind(&ListOriginsOnDisk, root_path_),
+ base::Bind(&ListOriginsOnTaskRunner, root_path_),
base::Bind(callback));
}
@@ -275,13 +316,14 @@ void CacheStorageManager::GetOriginsForHost(
if (host == net::GetHostOrSpecFromURL(key_value.first))
origins.insert(key_value.first);
}
- callback.Run(origins);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, origins));
return;
}
PostTaskAndReplyWithResult(
cache_task_runner_.get(), FROM_HERE,
- base::Bind(&ListOriginsOnDisk, root_path_),
+ base::Bind(&ListOriginsOnTaskRunner, root_path_),
base::Bind(&GetOriginsForHostDidListOrigins, host, callback));
}
@@ -290,18 +332,18 @@ void CacheStorageManager::DeleteOriginData(
const storage::QuotaClient::DeletionCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Create the CacheStorage for the origin if it hasn't been loaded yet.
+ FindOrCreateCacheStorage(origin);
+
CacheStorageMap::iterator it = cache_storage_map_.find(origin);
- if (it == cache_storage_map_.end()) {
- callback.Run(storage::kQuotaStatusOk);
- return;
- }
+ DCHECK(it != cache_storage_map_.end());
CacheStorage* cache_storage = it->second.release();
cache_storage_map_.erase(origin);
- cache_storage->CloseAllCaches(
- base::Bind(&CacheStorageManager::DeleteOriginDidClose, origin, callback,
- base::Passed(make_scoped_ptr(cache_storage)),
- weak_ptr_factory_.GetWeakPtr()));
+ cache_storage->GetSizeThenCloseAllCaches(
+ base::Bind(&CacheStorageManager::DeleteOriginDidClose,
+ weak_ptr_factory_.GetWeakPtr(), origin, callback,
+ base::Passed(make_scoped_ptr(cache_storage))));
}
void CacheStorageManager::DeleteOriginData(const GURL& origin) {
@@ -309,42 +351,40 @@ void CacheStorageManager::DeleteOriginData(const GURL& origin) {
DeleteOriginData(origin, base::Bind(&EmptyQuotaStatusCallback));
}
-// static
void CacheStorageManager::DeleteOriginDidClose(
const GURL& origin,
const storage::QuotaClient::DeletionCallback& callback,
scoped_ptr<CacheStorage> cache_storage,
- base::WeakPtr<CacheStorageManager> cache_manager) {
+ int64_t origin_size) {
// TODO(jkarlin): Deleting the storage leaves any unfinished operations
- // hanging, resulting in unresolved promises. Fix this by guaranteeing that
- // callbacks are called in ServiceWorkerStorage.
+ // hanging, resulting in unresolved promises. Fix this by returning early from
+ // CacheStorage operations posted after GetSizeThenCloseAllCaches is called.
cache_storage.reset();
- if (!cache_manager) {
- callback.Run(storage::kQuotaErrorAbort);
- return;
- }
+ quota_manager_proxy_->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorkerCache, origin,
+ storage::kStorageTypeTemporary, -1 * origin_size);
- if (cache_manager->IsMemoryBacked()) {
- callback.Run(storage::kQuotaStatusOk);
+ if (IsMemoryBacked()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, storage::kQuotaStatusOk));
return;
}
- cache_manager->MigrateOrigin(origin);
+ MigrateOrigin(origin);
PostTaskAndReplyWithResult(
- cache_manager->cache_task_runner_.get(), FROM_HERE,
- base::Bind(&DeleteDir,
- ConstructOriginPath(cache_manager->root_path_, origin)),
+ cache_task_runner_.get(), FROM_HERE,
+ base::Bind(&DeleteDir, ConstructOriginPath(root_path_, origin)),
base::Bind(&DeleteOriginDidDeleteDir, callback));
}
CacheStorageManager::CacheStorageManager(
const base::FilePath& path,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
: root_path_(path),
- cache_task_runner_(cache_task_runner),
- quota_manager_proxy_(quota_manager_proxy),
+ cache_task_runner_(std::move(cache_task_runner)),
+ quota_manager_proxy_(std::move(quota_manager_proxy)),
weak_ptr_factory_(this) {
if (quota_manager_proxy_.get()) {
quota_manager_proxy_->RegisterClient(
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.h b/chromium/content/browser/cache_storage/cache_storage_manager.h
index 121a25228d3..ded3703e924 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager.h
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.h
@@ -40,8 +40,8 @@ class CONTENT_EXPORT CacheStorageManager {
public:
static scoped_ptr<CacheStorageManager> Create(
const base::FilePath& path,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
static scoped_ptr<CacheStorageManager> Create(
CacheStorageManager* old_manager);
@@ -76,7 +76,7 @@ class CONTENT_EXPORT CacheStorageManager {
// This must be called before creating any of the public *Cache functions
// above.
void SetBlobParametersForCache(
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
base::WeakPtr<CacheStorageManager> AsWeakPtr() {
@@ -95,8 +95,8 @@ class CONTENT_EXPORT CacheStorageManager {
CacheStorageManager(
const base::FilePath& path,
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
- const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
// The returned CacheStorage* is owned by this manager.
CacheStorage* FindOrCreateCacheStorage(const GURL& origin);
@@ -104,6 +104,10 @@ class CONTENT_EXPORT CacheStorageManager {
// QuotaClient and Browsing Data Deletion support
void GetAllOriginsUsage(
const CacheStorageContext::GetUsageInfoCallback& callback);
+ void GetAllOriginsUsageGetSizes(
+ scoped_ptr<std::vector<CacheStorageUsageInfo>> usage_info,
+ const CacheStorageContext::GetUsageInfoCallback& callback);
+
void GetOriginUsage(const GURL& origin_url,
const storage::QuotaClient::GetUsageCallback& callback);
void GetOrigins(const storage::QuotaClient::GetOriginsCallback& callback);
@@ -113,11 +117,11 @@ class CONTENT_EXPORT CacheStorageManager {
void DeleteOriginData(const GURL& origin,
const storage::QuotaClient::DeletionCallback& callback);
void DeleteOriginData(const GURL& origin);
- static void DeleteOriginDidClose(
+ void DeleteOriginDidClose(
const GURL& origin,
const storage::QuotaClient::DeletionCallback& callback,
scoped_ptr<CacheStorage> cache_storage,
- base::WeakPtr<CacheStorageManager> cache_manager);
+ int64_t origin_size);
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter()
const {
@@ -128,7 +132,7 @@ class CONTENT_EXPORT CacheStorageManager {
return blob_context_;
}
- const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner() const {
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner() const {
return cache_task_runner_;
}
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
index f8d94976e2b..dec8cfa953f 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -24,6 +24,7 @@
#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cache_storage_usage_info.h"
+#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/url_request_context.h"
@@ -75,19 +76,25 @@ class CacheStorageManagerTest : public testing::Test {
url_request_context->set_job_factory(url_request_job_factory_.get());
+ if (!MemoryOnly())
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ quota_policy_ = new MockSpecialStoragePolicy;
+ mock_quota_manager_ = new MockQuotaManager(
+ MemoryOnly() /* is incognito */, temp_dir_.path(),
+ base::ThreadTaskRunnerHandle::Get().get(),
+ base::ThreadTaskRunnerHandle::Get().get(), quota_policy_.get());
+ mock_quota_manager_->SetQuota(
+ GURL(origin1_), storage::kStorageTypeTemporary, 1024 * 1024 * 100);
+ mock_quota_manager_->SetQuota(
+ GURL(origin2_), storage::kStorageTypeTemporary, 1024 * 1024 * 100);
+
quota_manager_proxy_ = new MockQuotaManagerProxy(
- nullptr, base::ThreadTaskRunnerHandle::Get().get());
+ mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
- if (MemoryOnly()) {
- cache_manager_ = CacheStorageManager::Create(
- base::FilePath(), base::ThreadTaskRunnerHandle::Get(),
- quota_manager_proxy_);
- } else {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- cache_manager_ = CacheStorageManager::Create(
- temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
- quota_manager_proxy_);
- }
+ cache_manager_ = CacheStorageManager::Create(
+ temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
+ quota_manager_proxy_);
cache_manager_->SetBlobParametersForCache(
browser_context_.GetRequestContext(),
@@ -110,9 +117,9 @@ class CacheStorageManagerTest : public testing::Test {
}
void CacheAndErrorCallback(base::RunLoop* run_loop,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error) {
- callback_cache_ = cache;
+ callback_cache_ = std::move(cache);
callback_error_ = error;
run_loop->Quit();
}
@@ -219,8 +226,13 @@ class CacheStorageManagerTest : public testing::Test {
return callback_error_ == CACHE_STORAGE_OK;
}
- bool CachePut(const scoped_refptr<CacheStorageCache>& cache,
- const GURL& url) {
+ bool CachePut(CacheStorageCache* cache, const GURL& url) {
+ return CachePutWithStatusCode(cache, url, 200);
+ }
+
+ bool CachePutWithStatusCode(CacheStorageCache* cache,
+ const GURL& url,
+ int status_code) {
ServiceWorkerFetchRequest request;
request.url = url;
@@ -231,9 +243,11 @@ class CacheStorageManagerTest : public testing::Test {
scoped_ptr<storage::BlobDataHandle> blob_handle =
blob_storage_context_->AddFinishedBlob(blob_data.get());
ServiceWorkerResponse response(
- url, 200, "OK", blink::WebServiceWorkerResponseTypeDefault,
+ url, status_code, "OK", blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(), blob_handle->uuid(), url.spec().size(),
- GURL(), blink::WebServiceWorkerResponseErrorUnknown);
+ GURL(), blink::WebServiceWorkerResponseErrorUnknown, base::Time(),
+ false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */);
CacheStorageBatchOperation operation;
operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT;
@@ -250,8 +264,7 @@ class CacheStorageManagerTest : public testing::Test {
return callback_error_ == CACHE_STORAGE_OK;
}
- bool CacheMatch(const scoped_refptr<CacheStorageCache>& cache,
- const GURL& url) {
+ bool CacheMatch(CacheStorageCache* cache, const GURL& url) {
scoped_ptr<ServiceWorkerFetchRequest> request(
new ServiceWorkerFetchRequest());
request->url = url;
@@ -298,6 +311,25 @@ class CacheStorageManagerTest : public testing::Test {
run_loop->Quit();
}
+ int64_t GetSizeThenCloseAllCaches(const GURL& origin) {
+ base::RunLoop loop;
+ CacheStorage* cache_storage = CacheStorageForOrigin(origin);
+ cache_storage->GetSizeThenCloseAllCaches(
+ base::Bind(&CacheStorageManagerTest::UsageCallback,
+ base::Unretained(this), &loop));
+ loop.Run();
+ return callback_usage_;
+ }
+
+ int64_t Size(const GURL& origin) {
+ base::RunLoop loop;
+ CacheStorage* cache_storage = CacheStorageForOrigin(origin);
+ cache_storage->Size(base::Bind(&CacheStorageManagerTest::UsageCallback,
+ base::Unretained(this), &loop));
+ loop.Run();
+ return callback_usage_;
+ }
+
protected:
// Temporary directory must be allocated first so as to be destroyed last.
base::ScopedTempDir temp_dir_;
@@ -307,6 +339,8 @@ class CacheStorageManagerTest : public testing::Test {
scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
storage::BlobStorageContext* blob_storage_context_;
+ scoped_refptr<MockSpecialStoragePolicy> quota_policy_;
+ scoped_refptr<MockQuotaManager> mock_quota_manager_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
scoped_ptr<CacheStorageManager> cache_manager_;
@@ -395,6 +429,18 @@ TEST_P(CacheStorageManagerTestP, DeleteTwice) {
EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
}
+TEST_P(CacheStorageManagerTestP, DeleteCacheReducesOriginSize) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+ // The quota manager gets updated after the put operation runs its callback so
+ // run the event loop.
+ base::RunLoop().RunUntilIdle();
+ int64_t put_delta = quota_manager_proxy_->last_notified_delta();
+ EXPECT_LT(0, put_delta);
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_EQ(put_delta, -1 * quota_manager_proxy_->last_notified_delta());
+}
+
TEST_P(CacheStorageManagerTestP, EmptyKeys) {
EXPECT_TRUE(Keys(origin1_));
EXPECT_TRUE(callback_strings_.empty());
@@ -427,33 +473,33 @@ TEST_P(CacheStorageManagerTestP, DeletedKeysGone) {
TEST_P(CacheStorageManagerTestP, StorageMatchEntryExists) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_TRUE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo")));
}
TEST_P(CacheStorageManagerTestP, StorageMatchNoEntry) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/bar")));
EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
}
TEST_P(CacheStorageManagerTestP, StorageMatchNoCache) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_FALSE(StorageMatch(origin1_, "bar", GURL("http://example.com/foo")));
- EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
+ EXPECT_EQ(CACHE_STORAGE_ERROR_CACHE_NAME_NOT_FOUND, callback_error_);
}
TEST_P(CacheStorageManagerTestP, StorageMatchAllEntryExists) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
}
TEST_P(CacheStorageManagerTestP, StorageMatchAllNoEntry) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_FALSE(StorageMatchAll(origin1_, GURL("http://example.com/bar")));
EXPECT_EQ(CACHE_STORAGE_ERROR_NOT_FOUND, callback_error_);
}
@@ -468,8 +514,8 @@ TEST_F(CacheStorageManagerTest, StorageReuseCacheName) {
// with the same URL should work. (see crbug.com/542668)
const GURL kTestURL = GURL("http://example.com/foo");
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, kTestURL));
- EXPECT_TRUE(CacheMatch(callback_cache_, kTestURL));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), kTestURL));
+ EXPECT_TRUE(CacheMatch(callback_cache_.get(), kTestURL));
scoped_ptr<storage::BlobDataHandle> data_handle =
std::move(callback_data_handle_);
@@ -477,22 +523,28 @@ TEST_F(CacheStorageManagerTest, StorageReuseCacheName) {
// The cache is deleted but the handle to one of its entries is still
// open. Creating a new cache in the same directory would fail on Windows.
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, kTestURL));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), kTestURL));
}
TEST_P(CacheStorageManagerTestP, StorageMatchAllEntryExistsTwice) {
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePutWithStatusCode(callback_cache_.get(),
+ GURL("http://example.com/foo"), 200));
EXPECT_TRUE(Open(origin1_, "bar"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePutWithStatusCode(callback_cache_.get(),
+ GURL("http://example.com/foo"), 201));
EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+
+ // The caches need to be searched in order of creation, so verify that the
+ // response came from the first cache.
+ EXPECT_EQ(200, callback_cache_response_->status_code);
}
TEST_P(CacheStorageManagerTestP, StorageMatchInOneOfMany) {
EXPECT_TRUE(Open(origin1_, "foo"));
EXPECT_TRUE(Open(origin1_, "bar"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_TRUE(Open(origin1_, "baz"));
EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
@@ -595,56 +647,67 @@ TEST_P(CacheStorageManagerTestP, OpenRunsSerially) {
TEST_P(CacheStorageManagerTestP, GetOriginUsage) {
EXPECT_EQ(0, GetOriginUsage(origin1_));
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_EQ(0, GetOriginUsage(origin1_));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+ int64_t foo_size = GetOriginUsage(origin1_);
EXPECT_LT(0, GetOriginUsage(origin1_));
EXPECT_EQ(0, GetOriginUsage(origin2_));
+
+ // Add the same entry into a second cache, the size should double.
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+ EXPECT_EQ(2 * foo_size, GetOriginUsage(origin1_));
}
TEST_P(CacheStorageManagerTestP, GetAllOriginsUsage) {
EXPECT_EQ(0ULL, GetAllOriginsUsage().size());
+ // Put one entry in a cache on origin 1.
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+
+ // Put two entries (of identical size) in a cache on origin 2.
+ EXPECT_TRUE(Open(origin2_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/bar")));
+
std::vector<CacheStorageUsageInfo> usage = GetAllOriginsUsage();
- EXPECT_EQ(1ULL, usage.size());
- const CacheStorageUsageInfo& info = usage[0];
- EXPECT_EQ(origin1_, info.origin);
- EXPECT_LT(0, info.total_size_bytes);
- if (MemoryOnly())
- EXPECT_TRUE(info.last_modified.is_null());
- else
- EXPECT_FALSE(info.last_modified.is_null());
+ EXPECT_EQ(2ULL, usage.size());
+
+ int origin1_index = usage[0].origin == origin1_ ? 0 : 1;
+ int origin2_index = usage[1].origin == origin2_ ? 1 : 0;
+ EXPECT_NE(origin1_index, origin2_index);
+
+ int64_t origin1_size = usage[origin1_index].total_size_bytes;
+ int64_t origin2_size = usage[origin2_index].total_size_bytes;
+ EXPECT_EQ(2 * origin1_size, origin2_size);
+
+ if (MemoryOnly()) {
+ EXPECT_TRUE(usage[origin1_index].last_modified.is_null());
+ EXPECT_TRUE(usage[origin2_index].last_modified.is_null());
+ } else {
+ EXPECT_FALSE(usage[origin1_index].last_modified.is_null());
+ EXPECT_FALSE(usage[origin2_index].last_modified.is_null());
+ }
}
-TEST_F(CacheStorageManagerMemoryOnlyTest, MemoryBackedSize) {
- CacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
- EXPECT_EQ(0, cache_storage->MemoryBackedSize());
-
+TEST_P(CacheStorageManagerTestP, GetSizeThenCloseAllCaches) {
EXPECT_TRUE(Open(origin1_, "foo"));
- scoped_refptr<CacheStorageCache> foo_cache = callback_cache_;
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo2")));
EXPECT_TRUE(Open(origin1_, "bar"));
- scoped_refptr<CacheStorageCache> bar_cache = callback_cache_;
- EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/bar")));
- EXPECT_TRUE(CachePut(foo_cache, GURL("http://example.com/foo")));
- EXPECT_LT(0, cache_storage->MemoryBackedSize());
- int64_t foo_size = cache_storage->MemoryBackedSize();
+ int64_t origin_size = GetOriginUsage(origin1_);
+ EXPECT_LT(0, origin_size);
- EXPECT_TRUE(CachePut(bar_cache, GURL("http://example.com/foo")));
- EXPECT_EQ(foo_size * 2, cache_storage->MemoryBackedSize());
-}
-
-TEST_F(CacheStorageManagerTest, MemoryBackedSizePersistent) {
- CacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
- EXPECT_EQ(0, cache_storage->MemoryBackedSize());
- EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
- EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+ EXPECT_EQ(origin_size, GetSizeThenCloseAllCaches(origin1_));
+ EXPECT_FALSE(CachePut(callback_cache_.get(), GURL("http://example.com/baz")));
}
TEST_F(CacheStorageManagerTest, DeleteUnreferencedCacheDirectories) {
// Create a referenced cache.
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
// Create an unreferenced directory next to the referenced one.
base::FilePath origin_path = CacheStorageManager::ConstructOriginPath(
@@ -660,12 +723,63 @@ TEST_F(CacheStorageManagerTest, DeleteUnreferencedCacheDirectories) {
// Verify that the referenced cache still works.
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CacheMatch(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(
+ CacheMatch(callback_cache_.get(), GURL("http://example.com/foo")));
// Verify that the unreferenced cache is gone.
EXPECT_FALSE(base::DirectoryExists(unreferenced_path));
}
+TEST_P(CacheStorageManagerTestP, OpenCacheStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, HasStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_FALSE(Has(origin1_, "foo"));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, DeleteStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_FALSE(Delete(origin1_, "foo"));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, KeysStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, MatchCacheStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo")));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, MatchAllCachesStorageAccessed) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+ EXPECT_FALSE(StorageMatchAll(origin1_, GURL("http://example.com/foo")));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, SizeStorageAccessed) {
+ EXPECT_EQ(0, Size(origin1_));
+ // Size is not part of the web API and should not notify the quota manager of
+ // an access.
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
+TEST_P(CacheStorageManagerTestP, SizeThenCloseStorageAccessed) {
+ EXPECT_EQ(0, GetSizeThenCloseAllCaches(origin1_));
+ // GetSizeThenCloseAllCaches is not part of the web API and should not notify
+ // the quota manager of an access.
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count());
+}
+
class CacheStorageMigrationTest : public CacheStorageManagerTest {
protected:
CacheStorageMigrationTest() : cache1_("foo"), cache2_("bar") {}
@@ -729,7 +843,7 @@ TEST_F(CacheStorageMigrationTest, DeleteCache) {
}
TEST_F(CacheStorageMigrationTest, GetOriginUsage) {
- EXPECT_GT(GetOriginUsage(origin1_), 0);
+ EXPECT_EQ(0, GetOriginUsage(origin1_));
EXPECT_FALSE(base::DirectoryExists(legacy_path_));
EXPECT_TRUE(base::DirectoryExists(new_path_));
}
@@ -774,7 +888,7 @@ class MigratedLegacyCacheDirectoryNameTest : public CacheStorageManagerTest {
// Populate a legacy cache.
ASSERT_TRUE(Open(origin1_, legacy_cache_name_));
- EXPECT_TRUE(CachePut(callback_cache_, stored_url_));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), stored_url_));
base::FilePath new_path = callback_cache_->path();
// Close the cache's backend so that the files can be moved.
@@ -827,27 +941,29 @@ TEST_F(MigratedLegacyCacheDirectoryNameTest, LegacyCacheMigrated) {
ASSERT_FALSE(base::DirectoryExists(legacy_path_));
// Verify that the existing entry still works.
- EXPECT_TRUE(CacheMatch(callback_cache_, stored_url_));
+ EXPECT_TRUE(CacheMatch(callback_cache_.get(), stored_url_));
// Verify that adding new entries works.
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo2")));
- EXPECT_TRUE(CacheMatch(callback_cache_, GURL("http://example.com/foo2")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo2")));
+ EXPECT_TRUE(
+ CacheMatch(callback_cache_.get(), GURL("http://example.com/foo2")));
}
TEST_F(MigratedLegacyCacheDirectoryNameTest,
RandomDirectoryCacheSideBySideWithLegacy) {
EXPECT_TRUE(Open(origin1_, legacy_cache_name_));
EXPECT_TRUE(Open(origin1_, "bar"));
- EXPECT_TRUE(CachePut(callback_cache_, stored_url_));
- EXPECT_TRUE(CacheMatch(callback_cache_, stored_url_));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), stored_url_));
+ EXPECT_TRUE(CacheMatch(callback_cache_.get(), stored_url_));
}
TEST_F(MigratedLegacyCacheDirectoryNameTest, DeleteLegacyCacheAndRecreateNew) {
EXPECT_TRUE(Delete(origin1_, legacy_cache_name_));
EXPECT_TRUE(Open(origin1_, legacy_cache_name_));
- EXPECT_FALSE(CacheMatch(callback_cache_, stored_url_));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo2")));
- EXPECT_TRUE(CacheMatch(callback_cache_, GURL("http://example.com/foo2")));
+ EXPECT_FALSE(CacheMatch(callback_cache_.get(), stored_url_));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo2")));
+ EXPECT_TRUE(
+ CacheMatch(callback_cache_.get(), GURL("http://example.com/foo2")));
}
class CacheStorageQuotaClientTest : public CacheStorageManagerTest {
@@ -929,6 +1045,11 @@ class CacheStorageQuotaClientTest : public CacheStorageManagerTest {
DISALLOW_COPY_AND_ASSIGN(CacheStorageQuotaClientTest);
};
+class CacheStorageQuotaClientDiskOnlyTest : public CacheStorageQuotaClientTest {
+ public:
+ bool MemoryOnly() override { return false; }
+};
+
class CacheStorageQuotaClientTestP : public CacheStorageQuotaClientTest,
public testing::WithParamInterface<bool> {
bool MemoryOnly() override { return !GetParam(); }
@@ -941,7 +1062,7 @@ TEST_P(CacheStorageQuotaClientTestP, QuotaID) {
TEST_P(CacheStorageQuotaClientTestP, QuotaGetOriginUsage) {
EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
EXPECT_TRUE(Open(origin1_, "foo"));
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_LT(0, QuotaGetOriginUsage(origin1_));
}
@@ -967,14 +1088,20 @@ TEST_P(CacheStorageQuotaClientTestP, QuotaGetOriginsForHost) {
}
TEST_P(CacheStorageQuotaClientTestP, QuotaDeleteOriginData) {
+ EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
EXPECT_TRUE(Open(origin1_, "foo"));
// Call put to test that initialized caches are properly deleted too.
- EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
EXPECT_TRUE(Open(origin1_, "bar"));
EXPECT_TRUE(Open(origin2_, "baz"));
+ int64_t origin1_size = QuotaGetOriginUsage(origin1_);
+ EXPECT_LT(0, origin1_size);
+
EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
+ EXPECT_EQ(-1 * origin1_size, quota_manager_proxy_->last_notified_delta());
+ EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
EXPECT_FALSE(Has(origin1_, "foo"));
EXPECT_FALSE(Has(origin1_, "bar"));
EXPECT_TRUE(Has(origin2_, "baz"));
@@ -985,6 +1112,25 @@ TEST_P(CacheStorageQuotaClientTestP, QuotaDeleteEmptyOrigin) {
EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
}
+TEST_F(CacheStorageQuotaClientDiskOnlyTest, QuotaDeleteUnloadedOriginData) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ // Call put to test that initialized caches are properly deleted too.
+ EXPECT_TRUE(CachePut(callback_cache_.get(), GURL("http://example.com/foo")));
+
+ // Close the cache backend so that it writes out its index to disk.
+ base::RunLoop run_loop;
+ callback_cache_->Close(run_loop.QuitClosure());
+ run_loop.Run();
+
+ // Create a new CacheStorageManager that hasn't yet loaded the origin.
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ cache_manager_ = CacheStorageManager::Create(cache_manager_.get());
+ quota_client_.reset(new CacheStorageQuotaClient(cache_manager_->AsWeakPtr()));
+
+ EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
+ EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
+}
+
TEST_P(CacheStorageQuotaClientTestP, QuotaDoesSupport) {
EXPECT_TRUE(QuotaDoesSupport(storage::kStorageTypeTemporary));
EXPECT_FALSE(QuotaDoesSupport(storage::kStorageTypePersistent));
diff --git a/chromium/content/browser/cache_storage/cache_storage_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_unittest.cc
index faf0eb10635..9c0081ba087 100644
--- a/chromium/content/browser/cache_storage/cache_storage_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_unittest.cc
@@ -7,9 +7,12 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/thread_task_runner_handle.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
+#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/quota/quota_manager_proxy.h"
@@ -23,12 +26,14 @@ const char kOrigin[] = "http://example.com/";
class TestCacheStorage : public CacheStorage {
public:
- explicit TestCacheStorage(const base::FilePath& file_path)
+ TestCacheStorage(
+ const base::FilePath& file_path,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
: CacheStorage(file_path,
false /* memory_only */,
base::ThreadTaskRunnerHandle::Get().get(),
scoped_refptr<net::URLRequestContextGetter>(),
- scoped_refptr<storage::QuotaManagerProxy>(),
+ quota_manager_proxy,
base::WeakPtr<storage::BlobStorageContext>(),
GURL(kOrigin)),
delay_preserved_cache_callback_(false) {}
@@ -67,7 +72,17 @@ class CacheStorageTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- test_cache_storage_.reset(new TestCacheStorage(temp_dir_.path()));
+
+ quota_policy_ = new MockSpecialStoragePolicy;
+ mock_quota_manager_ = new MockQuotaManager(
+ false /* is incognito */, temp_dir_.path(),
+ base::ThreadTaskRunnerHandle::Get().get(),
+ base::ThreadTaskRunnerHandle::Get().get(), quota_policy_.get());
+ quota_manager_proxy_ = new MockQuotaManagerProxy(
+ mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
+
+ test_cache_storage_.reset(
+ new TestCacheStorage(temp_dir_.path(), quota_manager_proxy_));
}
bool OpenCache(const std::string& cache_name) {
@@ -81,7 +96,7 @@ class CacheStorageTest : public testing::Test {
}
void OpenCacheCallback(bool* callback_called,
- const scoped_refptr<CacheStorageCache>& cache,
+ scoped_refptr<CacheStorageCache> cache,
CacheStorageError error) {
*callback_called = true;
callback_cache_ = cache;
@@ -90,6 +105,9 @@ class CacheStorageTest : public testing::Test {
base::ScopedTempDir temp_dir_;
TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_refptr<MockSpecialStoragePolicy> quota_policy_;
+ scoped_refptr<MockQuotaManager> mock_quota_manager_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
scoped_ptr<TestCacheStorage> test_cache_storage_;
scoped_refptr<CacheStorageCache> callback_cache_;
diff --git a/chromium/content/browser/child_process_launcher.cc b/chromium/content/browser/child_process_launcher.cc
index 57a6368cb7d..47205b630c1 100644
--- a/chromium/content/browser/child_process_launcher.cc
+++ b/chromium/content/browser/child_process_launcher.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
+#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
@@ -23,9 +24,13 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
#if defined(OS_WIN)
#include "base/files/file_path.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
#include "content/common/sandbox_win.h"
#include "content/public/common/sandbox_init.h"
#elif defined(OS_MACOSX)
@@ -39,8 +44,10 @@
#elif defined(OS_POSIX)
#include "base/memory/singleton.h"
#include "content/browser/renderer_host/render_sandbox_host_linux.h"
+#include "content/browser/zygote_host/zygote_communication_linux.h"
#include "content/browser/zygote_host/zygote_host_impl_linux.h"
#include "content/common/child_process_sandbox_support_impl_linux.h"
+#include "content/public/browser/zygote_handle_linux.h"
#endif
#if defined(OS_POSIX)
@@ -53,9 +60,10 @@ namespace content {
namespace {
-typedef base::Callback<void(bool,
+typedef base::Callback<void(ZygoteHandle,
#if defined(OS_ANDROID)
base::ScopedFD,
+ base::ScopedFD,
#endif
base::Process)> NotifyCallback;
@@ -79,6 +87,7 @@ void OnChildProcessStartedAndroid(const NotifyCallback& callback,
BrowserThread::ID client_thread_id,
const base::TimeTicks begin_launch_time,
base::ScopedFD ipcfd,
+ base::ScopedFD mojo_fd,
base::ProcessHandle handle) {
// This can be called on the launcher thread or UI thread.
base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
@@ -87,8 +96,8 @@ void OnChildProcessStartedAndroid(const NotifyCallback& callback,
base::Bind(&RecordHistogramsOnLauncherThread, launch_time));
base::Closure callback_on_client_thread(
- base::Bind(callback, false, base::Passed(&ipcfd),
- base::Passed(base::Process(handle))));
+ base::Bind(callback, nullptr, base::Passed(&ipcfd),
+ base::Passed(&mojo_fd), base::Passed(base::Process(handle))));
if (BrowserThread::CurrentlyOn(client_thread_id)) {
callback_on_client_thread.Run();
} else {
@@ -105,18 +114,19 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
#if defined(OS_ANDROID)
base::ScopedFD ipcfd,
#endif
+ mojo::edk::ScopedPlatformHandle client_handle,
base::CommandLine* cmd_line) {
DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
+#if !defined(OS_ANDROID)
+ ZygoteHandle zygote = nullptr;
+#endif
#if defined(OS_WIN)
- bool use_zygote = false;
bool launch_elevated = delegate->ShouldLaunchElevated();
#elif defined(OS_MACOSX)
- bool use_zygote = false;
base::EnvironmentMap env = delegate->GetEnvironment();
base::ScopedFD ipcfd = delegate->TakeIpcFd();
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
- bool use_zygote = delegate->ShouldUseZygote();
base::EnvironmentMap env = delegate->GetEnvironment();
base::ScopedFD ipcfd = delegate->TakeIpcFd();
#endif
@@ -126,11 +136,19 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
base::Process process;
#if defined(OS_WIN)
if (launch_elevated) {
+ // TODO(rockot): We may want to support Mojo IPC to elevated processes as
+ // well, but this isn't currently feasible without sharing a pipe path on
+ // the command line as elevated process launch goes through ShellExecuteEx.
base::LaunchOptions options;
options.start_hidden = true;
process = base::LaunchElevatedProcess(*cmd_line, options);
} else {
- process = StartSandboxedProcess(delegate, cmd_line);
+ base::HandlesToInheritVector handles;
+ handles.push_back(client_handle.get().handle);
+ cmd_line->AppendSwitchASCII(
+ mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch,
+ base::UintToString(base::win::HandleToUint32(handles[0])));
+ process = StartSandboxedProcess(delegate, cmd_line, handles);
}
#elif defined(OS_POSIX)
std::string process_type =
@@ -138,10 +156,17 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
scoped_ptr<FileDescriptorInfo> files_to_register(
FileDescriptorInfoImpl::Create());
+ base::ScopedFD mojo_fd(client_handle.release().handle);
+ DCHECK(mojo_fd.is_valid());
+
#if defined(OS_ANDROID)
- files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
+ if (ipcfd.get() != -1)
+ files_to_register->Share(kPrimaryIPCChannel, ipcfd.get());
+ files_to_register->Share(kMojoIPCChannel, mojo_fd.get());
#else
- files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd));
+ if (ipcfd.get() != -1)
+ files_to_register->Transfer(kPrimaryIPCChannel, std::move(ipcfd));
+ files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd));
#endif
#endif
@@ -154,6 +179,31 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
#endif
);
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+ bool snapshot_loaded = false;
+#if defined(OS_ANDROID)
+ base::MemoryMappedFile::Region region;
+ auto maybe_register = [&region, &regions, &files_to_register](int key,
+ int fd) {
+ if (fd != -1) {
+ files_to_register->Share(key, fd);
+ regions.insert(std::make_pair(key, region));
+ }
+ };
+ maybe_register(
+ kV8NativesDataDescriptor32,
+ gin::V8Initializer::GetOpenNativesFileForChildProcesses(&region, true));
+ maybe_register(
+ kV8NativesDataDescriptor64,
+ gin::V8Initializer::GetOpenNativesFileForChildProcesses(&region, false));
+ maybe_register(
+ kV8SnapshotDataDescriptor32,
+ gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(&region, true));
+ maybe_register(
+ kV8SnapshotDataDescriptor64,
+ gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(&region, false));
+
+ snapshot_loaded = true;
+#else
base::PlatformFile natives_pf =
gin::V8Initializer::GetOpenNativesFileForChildProcesses(
&regions[kV8NativesDataDescriptor]);
@@ -167,13 +217,15 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
// Failure to load the V8 snapshot is not necessarily an error. V8 can start
// up (slower) without the snapshot.
if (snapshot_pf != -1) {
+ snapshot_loaded = true;
files_to_register->Share(kV8SnapshotDataDescriptor, snapshot_pf);
regions.insert(std::make_pair(kV8SnapshotDataDescriptor, snapshot_region));
}
+#endif
if (process_type != switches::kZygoteProcess) {
cmd_line->AppendSwitch(::switches::kV8NativesPassedByFD);
- if (snapshot_pf != -1) {
+ if (snapshot_loaded) {
cmd_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
}
}
@@ -192,15 +244,24 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
StartChildProcess(
cmd_line->argv(), child_process_id, std::move(files_to_register), regions,
base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
- begin_launch_time, base::Passed(&ipcfd)));
+ begin_launch_time, base::Passed(&ipcfd),
+ base::Passed(&mojo_fd)));
#elif defined(OS_POSIX)
// We need to close the client end of the IPC channel to reliably detect
// child termination.
#if !defined(OS_MACOSX)
- if (use_zygote) {
- base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
+ ZygoteHandle* zygote_handle = delegate->GetZygote();
+ // If |zygote_handle| is null, a zygote should not be used.
+ if (zygote_handle) {
+ // This code runs on the PROCESS_LAUNCHER thread so race conditions are not
+ // an issue with the lazy initialization.
+ if (*zygote_handle == nullptr) {
+ *zygote_handle = CreateZygote();
+ }
+ zygote = *zygote_handle;
+ base::ProcessHandle handle = zygote->ForkRequest(
cmd_line->argv(), std::move(files_to_register), process_type);
process = base::Process(handle);
} else
@@ -278,13 +339,11 @@ void LaunchOnLauncherThread(const NotifyCallback& callback,
begin_launch_time);
}
BrowserThread::PostTask(client_thread_id, FROM_HERE,
- base::Bind(callback,
- use_zygote,
- base::Passed(&process)));
+ base::Bind(callback, zygote, base::Passed(&process)));
#endif // !defined(OS_ANDROID)
}
-void TerminateOnLauncherThread(bool zygote, base::Process process) {
+void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) {
DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
#if defined(OS_ANDROID)
VLOG(1) << "ChromeProcess: Stopping process with handle "
@@ -300,7 +359,7 @@ void TerminateOnLauncherThread(bool zygote, base::Process process) {
if (zygote) {
// If the renderer was created via a zygote, we have to proxy the reaping
// through the zygote process.
- ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
+ zygote->EnsureProcessTerminated(process.Handle());
} else
#endif // !OS_MACOSX
base::EnsureProcessTerminated(std::move(process));
@@ -330,7 +389,7 @@ ChildProcessLauncher::ChildProcessLauncher(
: client_(client),
termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
exit_code_(RESULT_CODE_NORMAL_EXIT),
- zygote_(false),
+ zygote_(nullptr),
starting_(true),
#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
@@ -386,6 +445,8 @@ void ChildProcessLauncher::Launch(
NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
weak_factory_.GetWeakPtr(),
terminate_child_on_shutdown_));
+ mojo::edk::ScopedPlatformHandle client_handle =
+ mojo_platform_channel_.PassClientHandle();
BrowserThread::PostTask(
BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_,
@@ -393,15 +454,15 @@ void ChildProcessLauncher::Launch(
#if defined(OS_ANDROID)
base::Passed(&ipcfd),
#endif
- cmd_line));
+ base::Passed(&client_handle), cmd_line));
}
void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
DCHECK(CalledOnValidThread());
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
if (zygote_) {
- termination_status_ = ZygoteHostImpl::GetInstance()->
- GetTerminationStatus(process_.Handle(), known_dead, &exit_code_);
+ termination_status_ = zygote_->GetTerminationStatus(
+ process_.Handle(), known_dead, &exit_code_);
} else if (known_dead) {
termination_status_ =
base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_);
@@ -434,9 +495,10 @@ void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
void ChildProcessLauncher::DidLaunch(
base::WeakPtr<ChildProcessLauncher> instance,
bool terminate_on_shutdown,
- bool zygote,
+ ZygoteHandle zygote,
#if defined(OS_ANDROID)
base::ScopedFD ipcfd,
+ base::ScopedFD mojo_fd,
#endif
base::Process process) {
if (!process.IsValid())
@@ -459,16 +521,21 @@ void ChildProcessLauncher::DidLaunch(
}
}
-void ChildProcessLauncher::Notify(
- bool zygote,
+void ChildProcessLauncher::Notify(ZygoteHandle zygote,
#if defined(OS_ANDROID)
- base::ScopedFD ipcfd,
+ base::ScopedFD ipcfd,
#endif
- base::Process process) {
+ base::Process process) {
DCHECK(CalledOnValidThread());
starting_ = false;
process_ = std::move(process);
+ if (process_.IsValid()) {
+ // Set up Mojo IPC to the new process.
+ mojo::edk::ChildProcessLaunched(process_.Handle(),
+ mojo_platform_channel_.PassServerHandle());
+ }
+
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
zygote_ = zygote;
#endif
diff --git a/chromium/content/browser/child_process_launcher.h b/chromium/content/browser/child_process_launcher.h
index c4f63210af1..710247778bb 100644
--- a/chromium/content/browser/child_process_launcher.h
+++ b/chromium/content/browser/child_process_launcher.h
@@ -15,13 +15,14 @@
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/common/sandboxed_process_launcher_delegate.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
namespace base {
class CommandLine;
}
namespace content {
-class SandboxedProcessLauncherDelegate;
// Launches a process asynchronously and notifies the client of the process
// handle when it's available. It's used to avoid blocking the calling thread
@@ -95,14 +96,15 @@ class CONTENT_EXPORT ChildProcessLauncher : public base::NonThreadSafe {
// client went away.
static void DidLaunch(base::WeakPtr<ChildProcessLauncher> instance,
bool terminate_on_shutdown,
- bool zygote,
+ ZygoteHandle zygote,
#if defined(OS_ANDROID)
base::ScopedFD ipcfd,
+ base::ScopedFD mojo_fd,
#endif
base::Process process);
// Notifies the client about the result of the operation.
- void Notify(bool zygote,
+ void Notify(ZygoteHandle zygote,
#if defined(OS_ANDROID)
base::ScopedFD ipcfd,
#endif
@@ -122,12 +124,15 @@ class CONTENT_EXPORT ChildProcessLauncher : public base::NonThreadSafe {
base::Process process_;
base::TerminationStatus termination_status_;
int exit_code_;
- bool zygote_;
+ ZygoteHandle zygote_;
bool starting_;
// Controls whether the child process should be terminated on browser
// shutdown. Default behavior is to terminate the child.
const bool terminate_child_on_shutdown_;
+ // Platform channel used to establish Mojo IPC.
+ mojo::edk::PlatformChannelPair mojo_platform_channel_;
+
base::WeakPtrFactory<ChildProcessLauncher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChildProcessLauncher);
diff --git a/chromium/content/browser/child_process_security_policy_impl.cc b/chromium/content/browser/child_process_security_policy_impl.cc
index 639401fc731..bd84239b04f 100644
--- a/chromium/content/browser/child_process_security_policy_impl.cc
+++ b/chromium/content/browser/child_process_security_policy_impl.cc
@@ -14,7 +14,6 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
-#include "content/browser/plugin_process_host.h"
#include "content/browser/site_instance_impl.h"
#include "content/common/site_isolation_policy.h"
#include "content/public/browser/child_process_data.h"
@@ -602,7 +601,7 @@ bool ChildProcessSecurityPolicyImpl::CanRequestURL(
if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL))
return true; // Every child process can request <about:blank>.
- // URLs like <about:memory> and <about:crash> shouldn't be requestable by
+ // URLs like <about:version> and <about:crash> shouldn't be requestable by
// any child process. Also, this case covers <javascript:...>, which should
// be handled internally by the process and not kicked up to the browser.
return false;
@@ -818,8 +817,11 @@ bool ChildProcessSecurityPolicyImpl::CanAccessDataForOrigin(int child_id,
const GURL& gurl) {
base::AutoLock lock(lock_);
SecurityStateMap::iterator state = security_state_.find(child_id);
- if (state == security_state_.end())
- return false;
+ if (state == security_state_.end()) {
+ // TODO(nick): Returning true instead of false here is a temporary
+ // workaround for https://crbug.com/600441
+ return true;
+ }
return state->second->CanAccessDataForOrigin(gurl);
}
diff --git a/chromium/content/browser/child_process_security_policy_unittest.cc b/chromium/content/browser/child_process_security_policy_unittest.cc
index 23604683ad3..455da447dd3 100644
--- a/chromium/content/browser/child_process_security_policy_unittest.cc
+++ b/chromium/content/browser/child_process_security_policy_unittest.cc
@@ -203,21 +203,22 @@ TEST_F(ChildProcessSecurityPolicyTest, AboutTest) {
EXPECT_TRUE(p->CanCommitURL(kRendererID, GURL("aBouT:BlAnK")));
EXPECT_TRUE(p->CanCommitURL(kRendererID, GURL("aBouT:blank")));
- EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory")));
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash")));
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache")));
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang")));
- EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:version")));
EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:crash")));
EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:cache")));
EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:hang")));
+ EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:version")));
- EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("aBoUt:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("aBoUt:version")));
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:CrASh")));
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("abOuT:cAChe")));
- EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("aBoUt:memory")));
+ EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("aBoUt:version")));
EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("about:CrASh")));
EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("abOuT:cAChe")));
+ EXPECT_FALSE(p->CanCommitURL(kRendererID, GURL("aBoUt:version")));
// Requests for about: pages should be denied.
p->GrantRequestURL(kRendererID, GURL("about:crash"));
diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.h b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h
index d8e0153fd63..004b2087c78 100644
--- a/chromium/content/browser/cocoa/system_hotkey_helper_mac.h
+++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
diff --git a/chromium/content/browser/cocoa/system_hotkey_map.mm b/chromium/content/browser/cocoa/system_hotkey_map.mm
index da04fa8b844..6ee40574420 100644
--- a/chromium/content/browser/cocoa/system_hotkey_map.mm
+++ b/chromium/content/browser/cocoa/system_hotkey_map.mm
@@ -4,6 +4,10 @@
#import "content/browser/cocoa/system_hotkey_map.h"
+#import <Carbon/Carbon.h>
+
+#include "base/mac/scoped_nsobject.h"
+
#pragma mark - NSDictionary Helper Functions
namespace {
@@ -75,11 +79,32 @@ bool SystemHotkeyMap::ParseDictionary(NSDictionary* dictionary) {
if (!dictionary)
return false;
- NSDictionary* hotkey_dictionaries =
+ NSDictionary* user_hotkey_dictionaries =
DictionaryForKey(dictionary, @"AppleSymbolicHotKeys");
- if (!hotkey_dictionaries)
+ if (!user_hotkey_dictionaries)
return false;
+ // Start with a dictionary of default OS X hotkeys that are not necessarily
+ // listed in com.apple.symbolichotkeys.plist, but should still be handled as
+ // reserved.
+ // If the user has overridden or disabled any of these hotkeys,
+ // -NSMutableDictionary addEntriesFromDictionary:] will ensure that the new
+ // values are used.
+ // See https://crbug.com/145062#c8
+ base::scoped_nsobject<NSMutableDictionary> hotkey_dictionaries([@{
+ // Default Window switch key binding: Command + `
+ // Note: The first parameter @96 is not used by |SystemHotkeyMap|.
+ @"27" : @{
+ @"enabled" : @YES,
+ @"value" : @{
+ @"type" : @"standard",
+ @"parameters" :
+ @[ @96 /* unused */, @(kVK_ANSI_Grave), @(NSCommandKeyMask) ],
+ }
+ }
+ } mutableCopy]);
+ [hotkey_dictionaries addEntriesFromDictionary:user_hotkey_dictionaries];
+
for (NSString* hotkey_system_effect in [hotkey_dictionaries allKeys]) {
if (![hotkey_system_effect isKindOfClass:[NSString class]])
continue;
diff --git a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
index 37638d472ac..a0798bec241 100644
--- a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
+++ b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
@@ -134,13 +134,13 @@ TEST_F(SystemHotkeyMapTest, ParseMouse) {
bool result = map.ParseDictionary(dictionary);
EXPECT_TRUE(result);
- // Command + ` is a common key binding. It is missing.
- // TODO(erikchen): OSX uses the default value when the keybinding is missing,
- // so the hotkey should still be reserved.
- // http://crbug.com/383558
+ // Command + ` is a common key binding. It is missing, but since OS X uses the
+ // default value the hotkey should still be reserved.
+ // https://crbug.com/383558
+ // https://crbug.com/145062
unsigned short key_code = kVK_ANSI_Grave;
NSUInteger modifiers = NSCommandKeyMask;
- EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+ EXPECT_TRUE(map.IsHotkeyReserved(key_code, modifiers));
// There is a mouse keybinding for 0x08. It should not apply to keyboard
// hotkeys.
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface.h b/chromium/content/browser/compositor/browser_compositor_output_surface.h
index 6e5ac7796b2..b3b9a4bd7a7 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.h
@@ -36,7 +36,7 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface
bool BindToClient(cc::OutputSurfaceClient* client) override;
cc::OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
- // ui::CompositorOutputSurface::Observer implementation.
+ // ui::CompositorVSyncManager::Observer implementation.
void OnUpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
diff --git a/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
index 2b1c3eca645..3e9886b0fc9 100644
--- a/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
+++ b/chromium/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
@@ -6,9 +6,10 @@
#include <stddef.h>
-#include "cc/output/overlay_strategy_sandwich.h"
+#include "base/command_line.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "ui/base/ui_base_switches.h"
namespace content {
@@ -31,7 +32,11 @@ void BrowserCompositorOverlayCandidateValidatorMac::GetStrategies(
}
bool BrowserCompositorOverlayCandidateValidatorMac::AllowCALayerOverlays() {
- if (software_mirror_active_ || ca_layers_disabled_)
+ static bool overlays_disabled_at_command_line =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableMacOverlays);
+ if (software_mirror_active_ || ca_layers_disabled_ ||
+ overlays_disabled_at_command_line)
return false;
return true;
}
diff --git a/chromium/content/browser/compositor/buffer_queue.cc b/chromium/content/browser/compositor/buffer_queue.cc
index dbe2ee24b7c..cafb6d96a18 100644
--- a/chromium/content/browser/compositor/buffer_queue.cc
+++ b/chromium/content/browser/compositor/buffer_queue.cc
@@ -6,12 +6,13 @@
#include "base/containers/adapters.h"
#include "build/build_config.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/image_transport_factory.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/service/image_factory.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
@@ -20,13 +21,12 @@
namespace content {
-BufferQueue::BufferQueue(
- scoped_refptr<cc::ContextProvider> context_provider,
- unsigned int texture_target,
- unsigned int internalformat,
- GLHelper* gl_helper,
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
- int surface_id)
+BufferQueue::BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ unsigned int texture_target,
+ unsigned int internalformat,
+ GLHelper* gl_helper,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ int surface_id)
: context_provider_(context_provider),
fbo_(0),
allocated_count_(0),
@@ -222,10 +222,9 @@ scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() {
DCHECK_LT(allocated_count_, 4U);
scoped_ptr<gfx::GpuMemoryBuffer> buffer(
- gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout(
- size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat(
- internal_format_),
- surface_id_));
+ gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
+ size_, gpu::DefaultBufferFormatForImageFormat(internal_format_),
+ gfx::BufferUsage::SCANOUT, surface_id_));
if (!buffer.get()) {
gl->DeleteTextures(1, &texture);
DLOG(ERROR) << "Failed to allocate GPU memory buffer";
diff --git a/chromium/content/browser/compositor/buffer_queue.h b/chromium/content/browser/compositor/buffer_queue.h
index 4c7d9439f9d..47b4a7dd00a 100644
--- a/chromium/content/browser/compositor/buffer_queue.h
+++ b/chromium/content/browser/compositor/buffer_queue.h
@@ -25,9 +25,12 @@ namespace gfx {
class GpuMemoryBuffer;
}
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
namespace content {
-class BrowserGpuMemoryBufferManager;
class GLHelper;
// Provides a surface that manages its own buffers, backed by GpuMemoryBuffers
@@ -40,7 +43,7 @@ class CONTENT_EXPORT BufferQueue {
unsigned int texture_target,
unsigned int internalformat,
GLHelper* gl_helper,
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
int surface_id);
virtual ~BufferQueue();
@@ -112,7 +115,7 @@ class CONTENT_EXPORT BufferQueue {
// may be nullptr, if they represent frames that have been destroyed.
std::deque<scoped_ptr<AllocatedSurface>> in_flight_surfaces_;
GLHelper* gl_helper_;
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
int surface_id_;
DISALLOW_COPY_AND_ASSIGN(BufferQueue);
diff --git a/chromium/content/browser/compositor/buffer_queue_unittest.cc b/chromium/content/browser/compositor/buffer_queue_unittest.cc
index 323d7ae8fd2..6e1dc9f05af 100644
--- a/chromium/content/browser/compositor/buffer_queue_unittest.cc
+++ b/chromium/content/browser/compositor/buffer_queue_unittest.cc
@@ -11,9 +11,9 @@
#include "cc/test/test_context_provider.h"
#include "cc/test/test_web_graphics_context_3d.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,10 +57,15 @@ class StubBrowserGpuMemoryBufferManager : public BrowserGpuMemoryBufferManager {
void set_allocate_succeeds(bool value) { allocate_succeeds_ = value; }
- scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
+ gfx::BufferUsage usage,
int32_t surface_id) override {
+ if (!surface_id) {
+ return BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
+ size, format, usage, surface_id);
+ }
if (allocate_succeeds_)
return make_scoped_ptr<gfx::GpuMemoryBuffer>(new StubGpuMemoryBufferImpl);
return nullptr;
diff --git a/chromium/content/browser/compositor/gl_helper.cc b/chromium/content/browser/compositor/gl_helper.cc
new file mode 100644
index 00000000000..55493e90068
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper.cc
@@ -0,0 +1,1226 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/gl_helper.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <queue>
+#include <string>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/compositor/gl_helper_readback_support.h"
+#include "content/browser/compositor/gl_helper_scaling.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace {
+
+class ScopedFlush {
+ public:
+ explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
+
+ ~ScopedFlush() { gl_->Flush(); }
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
+};
+
+// Helper class for allocating and holding an RGBA texture of a given
+// size and an associated framebuffer.
+class TextureFrameBufferPair {
+ public:
+ TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
+ : texture_(gl), framebuffer_(gl), size_(size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
+ gl, framebuffer_);
+ gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, texture_, 0);
+ }
+
+ GLuint texture() const { return texture_.id(); }
+ GLuint framebuffer() const { return framebuffer_.id(); }
+ gfx::Size size() const { return size_; }
+
+ private:
+ content::ScopedTexture texture_;
+ content::ScopedFramebuffer framebuffer_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair);
+};
+
+// Helper class for holding a scaler, a texture for the output of that
+// scaler and an associated frame buffer. This is inteded to be used
+// when the output of a scaler is to be sent to a readback.
+class ScalerHolder {
+ public:
+ ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
+ : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
+
+ void Scale(GLuint src_texture) {
+ scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
+ }
+
+ content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
+ TextureFrameBufferPair* texture_and_framebuffer() {
+ return &texture_and_framebuffer_;
+ }
+ GLuint texture() const { return texture_and_framebuffer_.texture(); }
+
+ private:
+ TextureFrameBufferPair texture_and_framebuffer_;
+ scoped_ptr<content::GLHelper::ScalerInterface> scaler_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScalerHolder);
+};
+
+} // namespace
+
+namespace content {
+typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
+
+// Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
+// the data needed for it.
+class GLHelper::CopyTextureToImpl
+ : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
+ public:
+ CopyTextureToImpl(GLES2Interface* gl,
+ gpu::ContextSupport* context_support,
+ GLHelper* helper)
+ : gl_(gl),
+ context_support_(context_support),
+ helper_(helper),
+ flush_(gl),
+ max_draw_buffers_(0) {
+ const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
+ if (!extensions)
+ return;
+ std::string extensions_string =
+ " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
+ if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
+ gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
+ }
+ }
+ ~CopyTextureToImpl() { CancelRequests(); }
+
+ GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token) {
+ return helper_->ConsumeMailboxToTexture(mailbox, sync_token);
+ }
+
+ void CropScaleReadbackAndCleanTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality);
+
+ void ReadbackTextureSync(GLuint texture,
+ const gfx::Rect& src_rect,
+ unsigned char* out,
+ SkColorType format);
+
+ void ReadbackTextureAsync(GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback);
+
+ // Reads back bytes from the currently bound frame buffer.
+ // Note that dst_size is specified in bytes, not pixels.
+ void ReadbackAsync(
+ const gfx::Size& dst_size,
+ int32_t bytes_per_row, // generally dst_size.width() * 4
+ int32_t row_stride_bytes, // generally dst_size.width() * 4
+ unsigned char* out,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
+ const base::Callback<void(bool)>& callback);
+
+ void ReadbackPlane(TextureFrameBufferPair* source,
+ const scoped_refptr<media::VideoFrame>& target,
+ int plane,
+ int size_shift,
+ const gfx::Rect& paste_rect,
+ ReadbackSwizzle swizzle,
+ const base::Callback<void(bool)>& callback);
+
+ GLuint CopyAndScaleTexture(GLuint texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ GLHelper::ScalerQuality quality);
+
+ ReadbackYUVInterface* CreateReadbackPipelineYUV(
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ bool use_mrt);
+
+ // Returns the maximum number of draw buffers available,
+ // 0 if GL_EXT_draw_buffers is not available.
+ GLint MaxDrawBuffers() const { return max_draw_buffers_; }
+
+ FormatSupport GetReadbackConfig(SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel);
+
+ private:
+ // A single request to CropScaleReadbackAndCleanTexture.
+ // The main thread can cancel the request, before it's handled by the helper
+ // thread, by resetting the texture and pixels fields. Alternatively, the
+ // thread marks that it handles the request by resetting the pixels field
+ // (meaning it guarantees that the callback with be called).
+ // In either case, the callback must be called exactly once, and the texture
+ // must be deleted by the main thread gl.
+ struct Request {
+ Request(const gfx::Size& size_,
+ int32_t bytes_per_row_,
+ int32_t row_stride_bytes_,
+ unsigned char* pixels_,
+ const base::Callback<void(bool)>& callback_)
+ : done(false),
+ size(size_),
+ bytes_per_row(bytes_per_row_),
+ row_stride_bytes(row_stride_bytes_),
+ pixels(pixels_),
+ callback(callback_),
+ buffer(0),
+ query(0) {}
+
+ bool done;
+ bool result;
+ gfx::Size size;
+ int bytes_per_row;
+ int row_stride_bytes;
+ unsigned char* pixels;
+ base::Callback<void(bool)> callback;
+ GLuint buffer;
+ GLuint query;
+ };
+
+ // We must take care to call the callbacks last, as they may
+ // end up destroying the gl_helper and make *this invalid.
+ // We stick the finished requests in a stack object that calls
+ // the callbacks when it goes out of scope.
+ class FinishRequestHelper {
+ public:
+ FinishRequestHelper() {}
+ ~FinishRequestHelper() {
+ while (!requests_.empty()) {
+ Request* request = requests_.front();
+ requests_.pop();
+ request->callback.Run(request->result);
+ delete request;
+ }
+ }
+ void Add(Request* r) { requests_.push(r); }
+
+ private:
+ std::queue<Request*> requests_;
+ DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper);
+ };
+
+ // A readback pipeline that also converts the data to YUV before
+ // reading it back.
+ class ReadbackYUVImpl : public ReadbackYUVInterface {
+ public:
+ ReadbackYUVImpl(GLES2Interface* gl,
+ CopyTextureToImpl* copy_impl,
+ GLHelperScaling* scaler_impl,
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ ReadbackSwizzle swizzle);
+
+ void ReadbackYUV(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
+ const base::Callback<void(bool)>& callback) override;
+
+ ScalerInterface* scaler() override { return scaler_.scaler(); }
+
+ private:
+ GLES2Interface* gl_;
+ CopyTextureToImpl* copy_impl_;
+ gfx::Size dst_size_;
+ ReadbackSwizzle swizzle_;
+ ScalerHolder scaler_;
+ ScalerHolder y_;
+ ScalerHolder u_;
+ ScalerHolder v_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl);
+ };
+
+ // A readback pipeline that also converts the data to YUV before
+ // reading it back. This one uses Multiple Render Targets, which
+ // may not be supported on all platforms.
+ class ReadbackYUV_MRT : public ReadbackYUVInterface {
+ public:
+ ReadbackYUV_MRT(GLES2Interface* gl,
+ CopyTextureToImpl* copy_impl,
+ GLHelperScaling* scaler_impl,
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ ReadbackSwizzle swizzle);
+
+ void ReadbackYUV(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
+ const base::Callback<void(bool)>& callback) override;
+
+ ScalerInterface* scaler() override { return scaler_.scaler(); }
+
+ private:
+ GLES2Interface* gl_;
+ CopyTextureToImpl* copy_impl_;
+ gfx::Size dst_size_;
+ GLHelper::ScalerQuality quality_;
+ ReadbackSwizzle swizzle_;
+ ScalerHolder scaler_;
+ scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
+ scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
+ TextureFrameBufferPair y_;
+ ScopedTexture uv_;
+ TextureFrameBufferPair u_;
+ TextureFrameBufferPair v_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT);
+ };
+
+ // Copies the block of pixels specified with |src_subrect| from |src_texture|,
+ // scales it to |dst_size|, writes it into a texture, and returns its ID.
+ // |src_size| is the size of |src_texture|.
+ GLuint ScaleTexture(GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ SkColorType color_type,
+ GLHelper::ScalerQuality quality);
+
+ // Converts each four consecutive pixels of the source texture into one pixel
+ // in the result texture with each pixel channel representing the grayscale
+ // color of one of the four original pixels:
+ // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4
+ // The resulting texture is still an RGBA texture (which is ~4 times narrower
+ // than the original). If rendered directly, it wouldn't show anything useful,
+ // but the data in it can be used to construct a grayscale image.
+ // |encoded_texture_size| is the exact size of the resulting RGBA texture. It
+ // is equal to src_size.width()/4 rounded upwards. Some channels in the last
+ // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain
+ // useful data.
+ // If swizzle is set to true, the transformed pixels are reordered:
+ // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4.
+ GLuint EncodeTextureAsGrayscale(GLuint src_texture,
+ const gfx::Size& src_size,
+ gfx::Size* const encoded_texture_size,
+ bool vertically_flip_texture,
+ bool swizzle);
+
+ static void nullcallback(bool success) {}
+ void ReadbackDone(Request* request, int bytes_per_pixel);
+ void FinishRequest(Request* request,
+ bool result,
+ FinishRequestHelper* helper);
+ void CancelRequests();
+
+ static const float kRGBtoYColorWeights[];
+ static const float kRGBtoUColorWeights[];
+ static const float kRGBtoVColorWeights[];
+ static const float kRGBtoGrayscaleColorWeights[];
+
+ GLES2Interface* gl_;
+ gpu::ContextSupport* context_support_;
+ GLHelper* helper_;
+
+ // A scoped flush that will ensure all resource deletions are flushed when
+ // this object is destroyed. Must be declared before other Scoped* fields.
+ ScopedFlush flush_;
+
+ std::queue<Request*> request_queue_;
+ GLint max_draw_buffers_;
+};
+
+GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle) {
+ InitScalerImpl();
+ return scaler_impl_->CreateScaler(quality, src_size, src_subrect, dst_size,
+ vertically_flip_texture, swizzle);
+}
+
+GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ SkColorType color_type,
+ GLHelper::ScalerQuality quality) {
+ GLuint dst_texture = 0u;
+ gl_->GenTextures(1, &dst_texture);
+ {
+ GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
+
+ // Use GL_RGBA for destination/temporary texture unless we're working with
+ // 16-bit data
+ if (color_type == kRGB_565_SkColorType) {
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ }
+
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, format, dst_size.width(),
+ dst_size.height(), 0, format, type, NULL);
+ }
+ scoped_ptr<ScalerInterface> scaler(
+ helper_->CreateScaler(quality, src_size, src_subrect, dst_size,
+ vertically_flip_texture, swizzle));
+ scaler->Scale(src_texture, dst_texture);
+ return dst_texture;
+}
+
+GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ gfx::Size* const encoded_texture_size,
+ bool vertically_flip_texture,
+ bool swizzle) {
+ GLuint dst_texture = 0u;
+ gl_->GenTextures(1, &dst_texture);
+ // The size of the encoded texture.
+ *encoded_texture_size =
+ gfx::Size((src_size.width() + 3) / 4, src_size.height());
+ {
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, encoded_texture_size->width(),
+ encoded_texture_size->height(), 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+ }
+
+ helper_->InitScalerImpl();
+ scoped_ptr<ScalerInterface> grayscale_scaler(
+ helper_->scaler_impl_.get()->CreatePlanarScaler(
+ src_size,
+ gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()),
+ *encoded_texture_size, vertically_flip_texture, swizzle,
+ kRGBtoGrayscaleColorWeights));
+ grayscale_scaler->Scale(src_texture, dst_texture);
+ return dst_texture;
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackAsync(
+ const gfx::Size& dst_size,
+ int32_t bytes_per_row,
+ int32_t row_stride_bytes,
+ unsigned char* out,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
+ const base::Callback<void(bool)>& callback) {
+ TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync");
+ Request* request =
+ new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
+ request_queue_.push(request);
+ request->buffer = 0u;
+
+ gl_->GenBuffers(1, &request->buffer);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
+ gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ bytes_per_pixel * dst_size.GetArea(), NULL, GL_STREAM_READ);
+
+ request->query = 0u;
+ gl_->GenQueriesEXT(1, &request->query);
+ gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
+ gl_->ReadPixels(0, 0, dst_size.width(), dst_size.height(), format, type,
+ NULL);
+ gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ context_support_->SignalQuery(
+ request->query, base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
+ request, bytes_per_pixel));
+}
+
+void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality) {
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ SkColorType readback_color_type = out_color_type;
+ // Single-component textures are not supported by all GPUs, so we implement
+ // kAlpha_8_SkColorType support here via a special encoding (see below) using
+ // a 32-bit texture to represent an 8-bit image.
+ // Thus we use generic 32-bit readback in this case.
+ if (out_color_type == kAlpha_8_SkColorType) {
+ readback_color_type = kRGBA_8888_SkColorType;
+ }
+
+ FormatSupport supported = GetReadbackConfig(readback_color_type, true,
+ &format, &type, &bytes_per_pixel);
+
+ if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
+ callback.Run(false);
+ return;
+ }
+
+ GLuint texture = src_texture;
+
+ // Scale texture if needed
+ // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we
+ // can do just as well in EncodeTextureAsGrayscale, which we will do if
+ // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step
+ // in that case.
+ bool scale_texture = out_color_type != kAlpha_8_SkColorType ||
+ quality != GLHelper::SCALER_QUALITY_FAST;
+ if (scale_texture) {
+ // Don't swizzle during the scale step for kAlpha_8_SkColorType.
+ // We will swizzle in the encode step below if needed.
+ bool scale_swizzle = out_color_type == kAlpha_8_SkColorType
+ ? false
+ : supported == GLHelperReadbackSupport::SWIZZLE;
+ texture = ScaleTexture(src_texture, src_size, src_subrect, dst_size, true,
+ scale_swizzle, out_color_type == kAlpha_8_SkColorType
+ ? kN32_SkColorType
+ : out_color_type,
+ quality);
+ DCHECK(texture);
+ }
+
+ gfx::Size readback_texture_size = dst_size;
+ // Encode texture to grayscale if needed.
+ if (out_color_type == kAlpha_8_SkColorType) {
+ // Do the vertical flip here if we haven't already done it when we scaled
+ // the texture.
+ bool encode_as_grayscale_vertical_flip = !scale_texture;
+ // EncodeTextureAsGrayscale by default creates a texture which should be
+ // read back as RGBA, so need to swizzle if the readback format is BGRA.
+ bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT;
+ GLuint tmp_texture = EncodeTextureAsGrayscale(
+ texture, dst_size, &readback_texture_size,
+ encode_as_grayscale_vertical_flip, encode_as_grayscale_swizzle);
+ // If the scaled texture was created - delete it
+ if (scale_texture)
+ gl_->DeleteTextures(1, &texture);
+ texture = tmp_texture;
+ DCHECK(texture);
+ }
+
+ // Readback the pixels of the resulting texture
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
+ dst_framebuffer);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture, 0);
+
+ int32_t bytes_per_row = out_color_type == kAlpha_8_SkColorType
+ ? dst_size.width()
+ : dst_size.width() * bytes_per_pixel;
+
+ ReadbackAsync(readback_texture_size, bytes_per_row, bytes_per_row, out,
+ format, type, bytes_per_pixel, callback);
+ gl_->DeleteTextures(1, &texture);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackTextureSync(GLuint texture,
+ const gfx::Rect& src_rect,
+ unsigned char* out,
+ SkColorType color_type) {
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported =
+ GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
+ if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
+ return;
+ }
+
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
+ dst_framebuffer);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture, 0);
+ gl_->ReadPixels(src_rect.x(), src_rect.y(), src_rect.width(),
+ src_rect.height(), format, type, out);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
+ GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback) {
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported =
+ GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
+ if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
+ callback.Run(false);
+ return;
+ }
+
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
+ dst_framebuffer);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture, 0);
+ ReadbackAsync(dst_size, dst_size.width() * bytes_per_pixel,
+ dst_size.width() * bytes_per_pixel, out, format, type,
+ bytes_per_pixel, callback);
+}
+
+GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ GLHelper::ScalerQuality quality) {
+ return ScaleTexture(src_texture, src_size, gfx::Rect(src_size), dst_size,
+ vertically_flip_texture, false,
+ kRGBA_8888_SkColorType, // GL_RGBA
+ quality);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
+ int bytes_per_pixel) {
+ TRACE_EVENT0("gpu.capture",
+ "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
+ finished_request->done = true;
+
+ FinishRequestHelper finish_request_helper;
+
+ // We process transfer requests in the order they were received, regardless
+ // of the order we get the callbacks in.
+ while (!request_queue_.empty()) {
+ Request* request = request_queue_.front();
+ if (!request->done) {
+ break;
+ }
+
+ bool result = false;
+ if (request->buffer != 0) {
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
+ unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+ if (data) {
+ result = true;
+ if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
+ request->bytes_per_row == request->row_stride_bytes) {
+ memcpy(request->pixels, data,
+ request->size.GetArea() * bytes_per_pixel);
+ } else {
+ unsigned char* out = request->pixels;
+ for (int y = 0; y < request->size.height(); y++) {
+ memcpy(out, data, request->bytes_per_row);
+ out += request->row_stride_bytes;
+ data += request->size.width() * bytes_per_pixel;
+ }
+ }
+ gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+ }
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ }
+ FinishRequest(request, result, &finish_request_helper);
+ }
+}
+
+void GLHelper::CopyTextureToImpl::FinishRequest(
+ Request* request,
+ bool result,
+ FinishRequestHelper* finish_request_helper) {
+ TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest");
+ DCHECK(request_queue_.front() == request);
+ request_queue_.pop();
+ request->result = result;
+ ScopedFlush flush(gl_);
+ if (request->query != 0) {
+ gl_->DeleteQueriesEXT(1, &request->query);
+ request->query = 0;
+ }
+ if (request->buffer != 0) {
+ gl_->DeleteBuffers(1, &request->buffer);
+ request->buffer = 0;
+ }
+ finish_request_helper->Add(request);
+}
+
+void GLHelper::CopyTextureToImpl::CancelRequests() {
+ FinishRequestHelper finish_request_helper;
+ while (!request_queue_.empty()) {
+ Request* request = request_queue_.front();
+ FinishRequest(request, false, &finish_request_helper);
+ }
+}
+
+FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
+ SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel) {
+ return helper_->readback_support_->GetReadbackConfig(
+ color_type, can_swizzle, format, type, bytes_per_pixel);
+}
+
+GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
+ : gl_(gl),
+ context_support_(context_support),
+ readback_support_(new GLHelperReadbackSupport(gl)) {}
+
+GLHelper::~GLHelper() {}
+
+void GLHelper::CropScaleReadbackAndCleanTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality) {
+ InitCopyTextToImpl();
+ copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(
+ src_texture, src_size, src_subrect, dst_size, out, out_color_type,
+ callback, quality);
+}
+
+void GLHelper::CropScaleReadbackAndCleanMailbox(
+ const gpu::Mailbox& src_mailbox,
+ const gpu::SyncToken& sync_token,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality) {
+ GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_token);
+ CropScaleReadbackAndCleanTexture(mailbox_texture, src_size, src_subrect,
+ dst_size, out, out_color_type, callback,
+ quality);
+ gl_->DeleteTextures(1, &mailbox_texture);
+}
+
+void GLHelper::ReadbackTextureSync(GLuint texture,
+ const gfx::Rect& src_rect,
+ unsigned char* out,
+ SkColorType format) {
+ InitCopyTextToImpl();
+ copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
+}
+
+void GLHelper::ReadbackTextureAsync(
+ GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback) {
+ InitCopyTextToImpl();
+ copy_texture_to_impl_->ReadbackTextureAsync(texture, dst_size, out,
+ color_type, callback);
+}
+
+GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
+ InitCopyTextToImpl();
+ return copy_texture_to_impl_->CopyAndScaleTexture(
+ texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
+}
+
+GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ ScalerQuality quality) {
+ InitCopyTextToImpl();
+ return copy_texture_to_impl_->CopyAndScaleTexture(
+ texture, src_size, dst_size, vertically_flip_texture, quality);
+}
+
+GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
+ GLuint shader = gl_->CreateShader(type);
+ GLint length = strlen(source);
+ gl_->ShaderSource(shader, 1, &source, &length);
+ gl_->CompileShader(shader);
+ GLint compile_status = 0;
+ gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+ if (!compile_status) {
+ GLint log_length = 0;
+ gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
+ if (log_length) {
+ scoped_ptr<GLchar[]> log(new GLchar[log_length]);
+ GLsizei returned_log_length = 0;
+ gl_->GetShaderInfoLog(shader, log_length, &returned_log_length,
+ log.get());
+ LOG(ERROR) << std::string(log.get(), returned_log_length);
+ }
+ gl_->DeleteShader(shader);
+ return 0;
+ }
+ return shader;
+}
+
+void GLHelper::InitCopyTextToImpl() {
+ // Lazily initialize |copy_texture_to_impl_|
+ if (!copy_texture_to_impl_)
+ copy_texture_to_impl_.reset(
+ new CopyTextureToImpl(gl_, context_support_, this));
+}
+
+void GLHelper::InitScalerImpl() {
+ // Lazily initialize |scaler_impl_|
+ if (!scaler_impl_)
+ scaler_impl_.reset(new GLHelperScaling(gl_, this));
+}
+
+GLint GLHelper::MaxDrawBuffers() {
+ InitCopyTextToImpl();
+ return copy_texture_to_impl_->MaxDrawBuffers();
+}
+
+void GLHelper::CopySubBufferDamage(GLenum target,
+ GLuint texture,
+ GLuint previous_texture,
+ const SkRegion& new_damage,
+ const SkRegion& old_damage) {
+ SkRegion region(old_damage);
+ if (region.op(new_damage, SkRegion::kDifference_Op)) {
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
+ dst_framebuffer);
+ gl_->BindTexture(target, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target,
+ previous_texture, 0);
+ for (SkRegion::Iterator it(region); !it.done(); it.next()) {
+ const SkIRect& rect = it.rect();
+ gl_->CopyTexSubImage2D(target, 0, rect.x(), rect.y(), rect.x(), rect.y(),
+ rect.width(), rect.height());
+ }
+ gl_->BindTexture(target, 0);
+ gl_->Flush();
+ }
+}
+
+GLuint GLHelper::CreateTexture() {
+ GLuint texture = 0u;
+ gl_->GenTextures(1, &texture);
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ return texture;
+}
+
+void GLHelper::DeleteTexture(GLuint texture_id) {
+ gl_->DeleteTextures(1, &texture_id);
+}
+
+void GLHelper::GenerateSyncToken(gpu::SyncToken* sync_token) {
+ const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM();
+ gl_->ShallowFlushCHROMIUM();
+ gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData());
+}
+
+void GLHelper::WaitSyncToken(const gpu::SyncToken& sync_token) {
+ gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+}
+
+gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
+ GLuint texture_id) {
+ gpu::Mailbox mailbox;
+ gl_->GenMailboxCHROMIUM(mailbox.name);
+ gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
+
+ gpu::SyncToken sync_token;
+ GenerateSyncToken(&sync_token);
+
+ return gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D);
+}
+
+GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token) {
+ if (mailbox.IsZero())
+ return 0;
+ if (sync_token.HasData())
+ WaitSyncToken(sync_token);
+ GLuint texture =
+ gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ return texture;
+}
+
+void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0,
+ GL_RGB, GL_UNSIGNED_BYTE, NULL);
+}
+
+void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.x(),
+ rect.y(), rect.width(), rect.height());
+}
+
+void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(),
+ size.height(), 0);
+}
+
+void GLHelper::Flush() {
+ gl_->Flush();
+}
+
+void GLHelper::InsertOrderingBarrier() {
+ gl_->OrderingBarrierCHROMIUM();
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackPlane(
+ TextureFrameBufferPair* source,
+ const scoped_refptr<media::VideoFrame>& target,
+ int plane,
+ int size_shift,
+ const gfx::Rect& paste_rect,
+ ReadbackSwizzle swizzle,
+ const base::Callback<void(bool)>& callback) {
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
+ const size_t offset = target->stride(plane) * (paste_rect.y() >> size_shift) +
+ (paste_rect.x() >> size_shift);
+ ReadbackAsync(source->size(), paste_rect.width() >> size_shift,
+ target->stride(plane), target->data(plane) + offset,
+ (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
+ GL_UNSIGNED_BYTE, 4, callback);
+}
+
+const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
+ 0.257f, 0.504f, 0.098f, 0.0625f};
+const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
+ -0.148f, -0.291f, 0.439f, 0.5f};
+const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
+ 0.439f, -0.368f, -0.071f, 0.5f};
+const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = {
+ 0.213f, 0.715f, 0.072f, 0.0f};
+
+// YUV readback constructors. Initiates the main scaler pipeline and
+// one planar scaler for each of the Y, U and V planes.
+GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
+ GLES2Interface* gl,
+ CopyTextureToImpl* copy_impl,
+ GLHelperScaling* scaler_impl,
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
+ : gl_(gl),
+ copy_impl_(copy_impl),
+ dst_size_(dst_size),
+ swizzle_(swizzle),
+ scaler_(gl,
+ scaler_impl->CreateScaler(quality,
+ src_size,
+ src_subrect,
+ dst_size,
+ flip_vertically,
+ false)),
+ y_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_size,
+ gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()),
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
+ false,
+ (swizzle == kSwizzleBGRA),
+ kRGBtoYColorWeights)),
+ u_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_size,
+ gfx::Rect(0,
+ 0,
+ (dst_size.width() + 7) & ~7,
+ (dst_size.height() + 1) & ~1),
+ gfx::Size((dst_size.width() + 7) / 8, (dst_size.height() + 1) / 2),
+ false,
+ (swizzle == kSwizzleBGRA),
+ kRGBtoUColorWeights)),
+ v_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_size,
+ gfx::Rect(0,
+ 0,
+ (dst_size.width() + 7) & ~7,
+ (dst_size.height() + 1) & ~1),
+ gfx::Size((dst_size.width() + 7) / 8, (dst_size.height() + 1) / 2),
+ false,
+ (swizzle == kSwizzleBGRA),
+ kRGBtoVColorWeights)) {
+ DCHECK(!(dst_size.width() & 1));
+ DCHECK(!(dst_size.height() & 1));
+}
+
+static void CallbackKeepingVideoFrameAlive(
+ scoped_refptr<media::VideoFrame> video_frame,
+ const base::Callback<void(bool)>& callback,
+ bool success) {
+ callback.Run(success);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV(
+ const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
+ const base::Callback<void(bool)>& callback) {
+ DCHECK(!(paste_location.x() & 1));
+ DCHECK(!(paste_location.y() & 1));
+
+ GLuint mailbox_texture =
+ copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token);
+
+ // Scale texture to right size.
+ scaler_.Scale(mailbox_texture);
+ gl_->DeleteTextures(1, &mailbox_texture);
+
+ // Convert the scaled texture in to Y, U and V planes.
+ y_.Scale(scaler_.texture());
+ u_.Scale(scaler_.texture());
+ v_.Scale(scaler_.texture());
+
+ const gfx::Rect paste_rect(paste_location, dst_size_);
+ if (!target->visible_rect().Contains(paste_rect)) {
+ LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
+ callback.Run(false);
+ return;
+ }
+
+ // Read back planes, one at a time. Keep the video frame alive while doing the
+ // readback.
+ copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), target,
+ media::VideoFrame::kYPlane, 0, paste_rect, swizzle_,
+ base::Bind(&nullcallback));
+ copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), target,
+ media::VideoFrame::kUPlane, 1, paste_rect, swizzle_,
+ base::Bind(&nullcallback));
+ copy_impl_->ReadbackPlane(
+ v_.texture_and_framebuffer(), target, media::VideoFrame::kVPlane, 1,
+ paste_rect, swizzle_,
+ base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ media::LetterboxYUV(target.get(), paste_rect);
+}
+
+// YUV readback constructors. Initiates the main scaler pipeline and
+// one planar scaler for each of the Y, U and V planes.
+GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
+ GLES2Interface* gl,
+ CopyTextureToImpl* copy_impl,
+ GLHelperScaling* scaler_impl,
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
+ : gl_(gl),
+ copy_impl_(copy_impl),
+ dst_size_(dst_size),
+ quality_(quality),
+ swizzle_(swizzle),
+ scaler_(gl,
+ scaler_impl->CreateScaler(quality,
+ src_size,
+ src_subrect,
+ dst_size,
+ false,
+ false)),
+ pass1_shader_(scaler_impl->CreateYuvMrtShader(
+ dst_size,
+ gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()),
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
+ flip_vertically,
+ (swizzle == kSwizzleBGRA),
+ GLHelperScaling::SHADER_YUV_MRT_PASS1)),
+ pass2_shader_(scaler_impl->CreateYuvMrtShader(
+ gfx::Size((dst_size.width() + 3) / 4, dst_size.height()),
+ gfx::Rect(0, 0, (dst_size.width() + 7) / 8 * 2, dst_size.height()),
+ gfx::Size((dst_size.width() + 7) / 8, (dst_size.height() + 1) / 2),
+ false,
+ (swizzle == kSwizzleBGRA),
+ GLHelperScaling::SHADER_YUV_MRT_PASS2)),
+ y_(gl, gfx::Size((dst_size.width() + 3) / 4, dst_size.height())),
+ uv_(gl),
+ u_(gl,
+ gfx::Size((dst_size.width() + 7) / 8, (dst_size.height() + 1) / 2)),
+ v_(gl,
+ gfx::Size((dst_size.width() + 7) / 8, (dst_size.height() + 1) / 2)) {
+ DCHECK(!(dst_size.width() & 1));
+ DCHECK(!(dst_size.height() & 1));
+
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (dst_size.width() + 3) / 4,
+ dst_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV(
+ const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
+ const base::Callback<void(bool)>& callback) {
+ DCHECK(!(paste_location.x() & 1));
+ DCHECK(!(paste_location.y() & 1));
+
+ GLuint mailbox_texture =
+ copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token);
+
+ GLuint texture;
+ if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
+ // Optimization: SCALER_QUALITY_FAST is just a single bilinear
+ // pass, which pass1_shader_ can do just as well, so let's skip
+ // the actual scaling in that case.
+ texture = mailbox_texture;
+ } else {
+ // Scale texture to right size.
+ scaler_.Scale(mailbox_texture);
+ texture = scaler_.texture();
+ }
+
+ std::vector<GLuint> outputs(2);
+ // Convert the scaled texture in to Y, U and V planes.
+ outputs[0] = y_.texture();
+ outputs[1] = uv_;
+ pass1_shader_->Execute(texture, outputs);
+
+ gl_->DeleteTextures(1, &mailbox_texture);
+
+ outputs[0] = u_.texture();
+ outputs[1] = v_.texture();
+ pass2_shader_->Execute(uv_, outputs);
+
+ const gfx::Rect paste_rect(paste_location, dst_size_);
+ if (!target->visible_rect().Contains(paste_rect)) {
+ LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!";
+ callback.Run(false);
+ return;
+ }
+
+ // Read back planes, one at a time.
+ copy_impl_->ReadbackPlane(&y_, target, media::VideoFrame::kYPlane, 0,
+ paste_rect, swizzle_, base::Bind(&nullcallback));
+ copy_impl_->ReadbackPlane(&u_, target, media::VideoFrame::kUPlane, 1,
+ paste_rect, swizzle_, base::Bind(&nullcallback));
+ copy_impl_->ReadbackPlane(
+ &v_, target, media::VideoFrame::kVPlane, 1, paste_rect, swizzle_,
+ base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ media::LetterboxYUV(target.get(), paste_rect);
+}
+
+bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
+ DCHECK(readback_support_.get());
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport support = readback_support_->GetReadbackConfig(
+ color_type, false, &format, &type, &bytes_per_pixel);
+
+ return (support == GLHelperReadbackSupport::SUPPORTED);
+}
+
+ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ bool use_mrt) {
+ helper_->InitScalerImpl();
+ // Just query if the best readback configuration needs a swizzle In
+ // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported = GetReadbackConfig(kRGBA_8888_SkColorType, true,
+ &format, &type, &bytes_per_pixel);
+ DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
+ type == GL_UNSIGNED_BYTE);
+
+ ReadbackSwizzle swizzle = kSwizzleNone;
+ if (supported == GLHelperReadbackSupport::SWIZZLE)
+ swizzle = kSwizzleBGRA;
+
+ if (max_draw_buffers_ >= 2 && use_mrt) {
+ return new ReadbackYUV_MRT(gl_, this, helper_->scaler_impl_.get(), quality,
+ src_size, src_subrect, dst_size, flip_vertically,
+ swizzle);
+ }
+ return new ReadbackYUVImpl(gl_, this, helper_->scaler_impl_.get(), quality,
+ src_size, src_subrect, dst_size, flip_vertically,
+ swizzle);
+}
+
+ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
+ ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ bool use_mrt) {
+ InitCopyTextToImpl();
+ return copy_texture_to_impl_->CreateReadbackPipelineYUV(
+ quality, src_size, src_subrect, dst_size, flip_vertically, use_mrt);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/gl_helper.h b/chromium/content/browser/compositor/gl_helper.h
new file mode 100644
index 00000000000..ebfc1a33c0b
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper.h
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_GL_HELPER_H_
+#define CONTENT_BROWSER_COMPOSITOR_GL_HELPER_H_
+
+#include "base/atomicops.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace gfx {
+class Point;
+class Rect;
+class Size;
+}
+
+namespace gpu {
+class ContextSupport;
+struct Mailbox;
+}
+
+namespace media {
+class VideoFrame;
+};
+
+class SkRegion;
+
+namespace content {
+
+class GLHelperScaling;
+
+class ScopedGLuint {
+ public:
+ typedef void (gpu::gles2::GLES2Interface::*GenFunc)(GLsizei n, GLuint* ids);
+ typedef void (gpu::gles2::GLES2Interface::*DeleteFunc)(GLsizei n,
+ const GLuint* ids);
+ ScopedGLuint(gpu::gles2::GLES2Interface* gl,
+ GenFunc gen_func,
+ DeleteFunc delete_func)
+ : gl_(gl), id_(0u), delete_func_(delete_func) {
+ (gl_->*gen_func)(1, &id_);
+ }
+
+ operator GLuint() const { return id_; }
+
+ GLuint id() const { return id_; }
+
+ ~ScopedGLuint() {
+ if (id_ != 0) {
+ (gl_->*delete_func_)(1, &id_);
+ }
+ }
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+ GLuint id_;
+ DeleteFunc delete_func_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedGLuint);
+};
+
+class ScopedBuffer : public ScopedGLuint {
+ public:
+ explicit ScopedBuffer(gpu::gles2::GLES2Interface* gl)
+ : ScopedGLuint(gl,
+ &gpu::gles2::GLES2Interface::GenBuffers,
+ &gpu::gles2::GLES2Interface::DeleteBuffers) {}
+};
+
+class ScopedFramebuffer : public ScopedGLuint {
+ public:
+ explicit ScopedFramebuffer(gpu::gles2::GLES2Interface* gl)
+ : ScopedGLuint(gl,
+ &gpu::gles2::GLES2Interface::GenFramebuffers,
+ &gpu::gles2::GLES2Interface::DeleteFramebuffers) {}
+};
+
+class ScopedTexture : public ScopedGLuint {
+ public:
+ explicit ScopedTexture(gpu::gles2::GLES2Interface* gl)
+ : ScopedGLuint(gl,
+ &gpu::gles2::GLES2Interface::GenTextures,
+ &gpu::gles2::GLES2Interface::DeleteTextures) {}
+};
+
+template <GLenum Target>
+class ScopedBinder {
+ public:
+ typedef void (gpu::gles2::GLES2Interface::*BindFunc)(GLenum target,
+ GLuint id);
+ ScopedBinder(gpu::gles2::GLES2Interface* gl, GLuint id, BindFunc bind_func)
+ : gl_(gl), bind_func_(bind_func) {
+ (gl_->*bind_func_)(Target, id);
+ }
+
+ virtual ~ScopedBinder() { (gl_->*bind_func_)(Target, 0); }
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+ BindFunc bind_func_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
+};
+
+template <GLenum Target>
+class ScopedBufferBinder : ScopedBinder<Target> {
+ public:
+ ScopedBufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
+ : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindBuffer) {}
+};
+
+template <GLenum Target>
+class ScopedFramebufferBinder : ScopedBinder<Target> {
+ public:
+ ScopedFramebufferBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
+ : ScopedBinder<Target>(gl,
+ id,
+ &gpu::gles2::GLES2Interface::BindFramebuffer) {}
+};
+
+template <GLenum Target>
+class ScopedTextureBinder : ScopedBinder<Target> {
+ public:
+ ScopedTextureBinder(gpu::gles2::GLES2Interface* gl, GLuint id)
+ : ScopedBinder<Target>(gl, id, &gpu::gles2::GLES2Interface::BindTexture) {
+ }
+};
+
+class ReadbackYUVInterface;
+class GLHelperReadbackSupport;
+
+// Provides higher level operations on top of the gpu::gles2::GLES2Interface
+// interfaces.
+class CONTENT_EXPORT GLHelper {
+ public:
+ GLHelper(gpu::gles2::GLES2Interface* gl,
+ gpu::ContextSupport* context_support);
+ ~GLHelper();
+
+ enum ScalerQuality {
+ // Bilinear single pass, fastest possible.
+ SCALER_QUALITY_FAST = 1,
+
+ // Bilinear upscale + N * 50% bilinear downscales.
+ // This is still fast enough for most purposes and
+ // Image quality is nearly as good as the BEST option.
+ SCALER_QUALITY_GOOD = 2,
+
+ // Bicubic upscale + N * 50% bicubic downscales.
+ // Produces very good quality scaled images, but it's
+ // 2-8x slower than the "GOOD" quality, so it's not always
+ // worth it.
+ SCALER_QUALITY_BEST = 3,
+ };
+
+ // Copies the block of pixels specified with |src_subrect| from |src_texture|,
+ // scales it to |dst_size|, and writes it into |out|.
+ // |src_size| is the size of |src_texture|. The result is in |out_color_type|
+ // format and is potentially flipped vertically to make it a correct image
+ // representation. |callback| is invoked with the copy result when the copy
+ // operation has completed.
+ // Note that the src_texture will have the min/mag filter set to GL_LINEAR
+ // and wrap_s/t set to CLAMP_TO_EDGE in this call.
+ void CropScaleReadbackAndCleanTexture(
+ GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality);
+
+ // Copies the block of pixels specified with |src_subrect| from |src_mailbox|,
+ // scales it to |dst_size|, and writes it into |out|.
+ // |src_size| is the size of |src_mailbox|. The result is in |out_color_type|
+ // format and is potentially flipped vertically to make it a correct image
+ // representation. |callback| is invoked with the copy result when the copy
+ // operation has completed.
+ // Note that the texture bound to src_mailbox will have the min/mag filter set
+ // to GL_LINEAR and wrap_s/t set to CLAMP_TO_EDGE in this call. src_mailbox is
+ // assumed to be GL_TEXTURE_2D.
+ void CropScaleReadbackAndCleanMailbox(
+ const gpu::Mailbox& src_mailbox,
+ const gpu::SyncToken& sync_token,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ const SkColorType out_color_type,
+ const base::Callback<void(bool)>& callback,
+ GLHelper::ScalerQuality quality);
+
+ // Copies the texture data out of |texture| into |out|. |size| is the
+ // size of the texture. No post processing is applied to the pixels. The
+ // texture is assumed to have a format of GL_RGBA with a pixel type of
+ // GL_UNSIGNED_BYTE. This is a blocking call that calls glReadPixels on the
+ // current OpenGL context.
+ void ReadbackTextureSync(GLuint texture,
+ const gfx::Rect& src_rect,
+ unsigned char* out,
+ SkColorType format);
+
+ void ReadbackTextureAsync(GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback);
+
+ // Creates a copy of the specified texture. |size| is the size of the texture.
+ // Note that the src_texture will have the min/mag filter set to GL_LINEAR
+ // and wrap_s/t set to CLAMP_TO_EDGE in this call.
+ GLuint CopyTexture(GLuint texture, const gfx::Size& size);
+
+ // Creates a scaled copy of the specified texture. |src_size| is the size of
+ // the texture and |dst_size| is the size of the resulting copy.
+ // Note that the src_texture will have the min/mag filter set to GL_LINEAR
+ // and wrap_s/t set to CLAMP_TO_EDGE in this call.
+ GLuint CopyAndScaleTexture(GLuint texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ ScalerQuality quality);
+
+ // Returns the shader compiled from the source.
+ GLuint CompileShaderFromSource(const GLchar* source, GLenum type);
+
+ // Copies all pixels from |previous_texture| into |texture| that are
+ // inside the region covered by |old_damage| but not part of |new_damage|.
+ void CopySubBufferDamage(GLenum target,
+ GLuint texture,
+ GLuint previous_texture,
+ const SkRegion& new_damage,
+ const SkRegion& old_damage);
+
+ // Simply creates a texture.
+ GLuint CreateTexture();
+ // Deletes a texture.
+ void DeleteTexture(GLuint texture_id);
+
+ // Inserts a fence sync, flushes, and generates a sync token.
+ void GenerateSyncToken(gpu::SyncToken* sync_token);
+
+ // Wait for the sync token before executing further GL commands.
+ void WaitSyncToken(const gpu::SyncToken& sync_token);
+
+ // Creates a mailbox holder that is attached to the given texture id, with a
+ // sync point to wait on before using the mailbox. Returns a holder with an
+ // empty mailbox on failure.
+ // Note the texture is assumed to be GL_TEXTURE_2D.
+ gpu::MailboxHolder ProduceMailboxHolderFromTexture(GLuint texture_id);
+
+ // Creates a texture and consumes a mailbox into it. Returns 0 on failure.
+ // Note the mailbox is assumed to be GL_TEXTURE_2D.
+ GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token);
+
+ // Resizes the texture's size to |size|.
+ void ResizeTexture(GLuint texture, const gfx::Size& size);
+
+ // Copies the framebuffer data given in |rect| to |texture|.
+ void CopyTextureSubImage(GLuint texture, const gfx::Rect& rect);
+
+ // Copies the all framebuffer data to |texture|. |size| specifies the
+ // size of the framebuffer.
+ void CopyTextureFullImage(GLuint texture, const gfx::Size& size);
+
+ // Flushes GL commands.
+ void Flush();
+
+ // Force commands in the current command buffer to be executed before commands
+ // in other command buffers from the same process (ie channel to the GPU
+ // process).
+ void InsertOrderingBarrier();
+
+ // A scaler will cache all intermediate textures and programs
+ // needed to scale from a specified size to a destination size.
+ // If the source or destination sizes changes, you must create
+ // a new scaler.
+ class CONTENT_EXPORT ScalerInterface {
+ public:
+ ScalerInterface() {}
+ virtual ~ScalerInterface() {}
+
+ // Note that the src_texture will have the min/mag filter set to GL_LINEAR
+ // and wrap_s/t set to CLAMP_TO_EDGE in this call.
+ virtual void Scale(GLuint source_texture, GLuint dest_texture) = 0;
+ virtual const gfx::Size& SrcSize() = 0;
+ virtual const gfx::Rect& SrcSubrect() = 0;
+ virtual const gfx::Size& DstSize() = 0;
+ };
+
+ // Note that the quality may be adjusted down if texture
+ // allocations fail or hardware doesn't support the requtested
+ // quality. Note that ScalerQuality enum is arranged in
+ // numerical order for simplicity.
+ ScalerInterface* CreateScaler(ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle);
+
+ // Create a readback pipeline that will scale a subsection of the source
+ // texture, then convert it to YUV422 planar form and then read back that.
+ // This reduces the amount of memory read from GPU to CPU memory by a factor
+ // 2.6, which can be quite handy since readbacks have very limited speed
+ // on some platforms. All values in |dst_size| must be a multiple of two. If
+ // |use_mrt| is true, the pipeline will try to optimize the YUV conversion
+ // using the multi-render-target extension. |use_mrt| should only be set to
+ // false for testing.
+ ReadbackYUVInterface* CreateReadbackPipelineYUV(ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool flip_vertically,
+ bool use_mrt);
+
+ // Returns the maximum number of draw buffers available,
+ // 0 if GL_EXT_draw_buffers is not available.
+ GLint MaxDrawBuffers();
+
+ // Checks whether the readbback is supported for texture with the
+ // matching config. This doesnt check for cross format readbacks.
+ bool IsReadbackConfigSupported(SkColorType texture_format);
+
+ protected:
+ class CopyTextureToImpl;
+
+ // Creates |copy_texture_to_impl_| if NULL.
+ void InitCopyTextToImpl();
+ // Creates |scaler_impl_| if NULL.
+ void InitScalerImpl();
+
+ enum ReadbackSwizzle { kSwizzleNone = 0, kSwizzleBGRA };
+
+ gpu::gles2::GLES2Interface* gl_;
+ gpu::ContextSupport* context_support_;
+ scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_;
+ scoped_ptr<GLHelperScaling> scaler_impl_;
+ scoped_ptr<GLHelperReadbackSupport> readback_support_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLHelper);
+};
+
+// Similar to a ScalerInterface, a yuv readback pipeline will
+// cache a scaler and all intermediate textures and frame buffers
+// needed to scale, crop, letterbox and read back a texture from
+// the GPU into CPU-accessible RAM. A single readback pipeline
+// can handle multiple outstanding readbacks at the same time, but
+// if the source or destination sizes change, you'll need to create
+// a new readback pipeline.
+class CONTENT_EXPORT ReadbackYUVInterface {
+ public:
+ ReadbackYUVInterface() {}
+ virtual ~ReadbackYUVInterface() {}
+
+ // Note that |target| must use YV12 format. |paste_location| specifies where
+ // the captured pixels that are read back will be placed in the video frame.
+ // The region defined by the |paste_location| and the |dst_size| specified in
+ // the call to CreateReadbackPipelineYUV() must be fully contained within
+ // |target->visible_rect()|.
+ virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
+ const gpu::SyncToken& sync_token,
+ const scoped_refptr<media::VideoFrame>& target,
+ const gfx::Point& paste_location,
+ const base::Callback<void(bool)>& callback) = 0;
+ virtual GLHelper::ScalerInterface* scaler() = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_GL_HELPER_H_
diff --git a/chromium/content/browser/compositor/gl_helper_benchmark.cc b/chromium/content/browser/compositor/gl_helper_benchmark.cc
new file mode 100644
index 00000000000..845d82a4264
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_benchmark.cc
@@ -0,0 +1,247 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file looks like a unit test, but it contains benchmarks and test
+// utilities intended for manual evaluation of the scalers in
+// gl_helper*. These tests produce output in the form of files and printouts,
+// but cannot really "fail". There is no point in making these tests part
+// of any test automation run.
+
+#include <stddef.h>
+#include <stdio.h>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "content/browser/compositor/gl_helper.h"
+#include "content/browser/compositor/gl_helper_scaling.h"
+#include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkTypes.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gl/gl_surface.h"
+
+namespace content {
+
+content::GLHelper::ScalerQuality kQualities[] = {
+ content::GLHelper::SCALER_QUALITY_BEST,
+ content::GLHelper::SCALER_QUALITY_GOOD,
+ content::GLHelper::SCALER_QUALITY_FAST,
+};
+
+const char* kQualityNames[] = {
+ "best", "good", "fast",
+};
+
+class GLHelperTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = 8;
+ attributes.depth_size = 24;
+ attributes.red_size = 8;
+ attributes.green_size = 8;
+ attributes.blue_size = 8;
+ attributes.stencil_size = 8;
+ attributes.samples = 4;
+ attributes.sample_buffers = 1;
+ attributes.bind_generates_resource = false;
+
+ context_.reset(gpu::GLInProcessContext::Create(
+ nullptr, /* service */
+ nullptr, /* surface */
+ true, /* offscreen */
+ gfx::kNullAcceleratedWidget, /* window */
+ gfx::Size(1, 1), /* size */
+ nullptr, /* share_context */
+ attributes, gfx::PreferDiscreteGpu,
+ ::gpu::GLInProcessContextSharedMemoryLimits(),
+ nullptr, /* gpu_memory_buffer_manager */
+ nullptr /* image_factory */));
+ gl_ = context_->GetImplementation();
+ gpu::ContextSupport* support = context_->GetImplementation();
+
+ helper_.reset(new content::GLHelper(gl_, support));
+ helper_scaling_.reset(new content::GLHelperScaling(gl_, helper_.get()));
+ }
+
+ void TearDown() override {
+ helper_scaling_.reset(NULL);
+ helper_.reset(NULL);
+ context_.reset(NULL);
+ }
+
+ void LoadPngFileToSkBitmap(const base::FilePath& filename, SkBitmap* bitmap) {
+ std::string compressed;
+ base::ReadFileToString(base::MakeAbsoluteFilePath(filename), &compressed);
+ ASSERT_TRUE(compressed.size());
+ ASSERT_TRUE(gfx::PNGCodec::Decode(
+ reinterpret_cast<const unsigned char*>(compressed.data()),
+ compressed.size(), bitmap));
+ }
+
+ // Save the image to a png file. Used to create the initial test files.
+ void SaveToFile(SkBitmap* bitmap, const base::FilePath& filename) {
+ std::vector<unsigned char> compressed;
+ ASSERT_TRUE(gfx::PNGCodec::Encode(
+ static_cast<unsigned char*>(bitmap->getPixels()),
+ gfx::PNGCodec::FORMAT_BGRA,
+ gfx::Size(bitmap->width(), bitmap->height()),
+ static_cast<int>(bitmap->rowBytes()), true,
+ std::vector<gfx::PNGCodec::Comment>(), &compressed));
+ ASSERT_TRUE(compressed.size());
+ FILE* f = base::OpenFile(filename, "wb");
+ ASSERT_TRUE(f);
+ ASSERT_EQ(fwrite(&*compressed.begin(), 1, compressed.size(), f),
+ compressed.size());
+ base::CloseFile(f);
+ }
+
+ scoped_ptr<gpu::GLInProcessContext> context_;
+ gpu::gles2::GLES2Interface* gl_;
+ scoped_ptr<content::GLHelper> helper_;
+ scoped_ptr<content::GLHelperScaling> helper_scaling_;
+ std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+};
+
+TEST_F(GLHelperTest, ScaleBenchmark) {
+ int output_sizes[] = {1920, 1080, 1249, 720, // Output size on pixel
+ 256, 144};
+ int input_sizes[] = {3200, 2040, 2560, 1476, // Pixel tab size
+ 1920, 1080, 1280, 720, 800, 480, 256, 144};
+
+ for (size_t q = 0; q < arraysize(kQualities); q++) {
+ for (size_t outsize = 0; outsize < arraysize(output_sizes); outsize += 2) {
+ for (size_t insize = 0; insize < arraysize(input_sizes); insize += 2) {
+ uint32_t src_texture;
+ gl_->GenTextures(1, &src_texture);
+ uint32_t dst_texture;
+ gl_->GenTextures(1, &dst_texture);
+ uint32_t framebuffer;
+ gl_->GenFramebuffers(1, &framebuffer);
+ const gfx::Size src_size(input_sizes[insize], input_sizes[insize + 1]);
+ const gfx::Size dst_size(output_sizes[outsize],
+ output_sizes[outsize + 1]);
+ SkBitmap input;
+ input.allocN32Pixels(src_size.width(), src_size.height());
+
+ SkBitmap output_pixels;
+ output_pixels.allocN32Pixels(dst_size.width(), dst_size.height());
+
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ gl_->BindTexture(GL_TEXTURE_2D, dst_texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dst_size.width(),
+ dst_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ gl_->BindTexture(GL_TEXTURE_2D, src_texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_size.width(),
+ src_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ input.getPixels());
+
+ gfx::Rect src_subrect(0, 0, src_size.width(), src_size.height());
+ scoped_ptr<content::GLHelper::ScalerInterface> scaler(
+ helper_->CreateScaler(kQualities[q], src_size, src_subrect,
+ dst_size, false, false));
+ // Scale once beforehand before we start measuring.
+ scaler->Scale(src_texture, dst_texture);
+ gl_->Finish();
+
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ int iterations = 0;
+ base::TimeTicks end_time;
+ while (true) {
+ for (int i = 0; i < 50; i++) {
+ iterations++;
+ scaler->Scale(src_texture, dst_texture);
+ gl_->Flush();
+ }
+ gl_->Finish();
+ end_time = base::TimeTicks::Now();
+ if (iterations > 2000) {
+ break;
+ }
+ if ((end_time - start_time).InMillisecondsF() > 1000) {
+ break;
+ }
+ }
+ gl_->DeleteTextures(1, &dst_texture);
+ gl_->DeleteTextures(1, &src_texture);
+ gl_->DeleteFramebuffers(1, &framebuffer);
+
+ std::string name;
+ name = base::StringPrintf("scale_%dx%d_to_%dx%d_%s", src_size.width(),
+ src_size.height(), dst_size.width(),
+ dst_size.height(), kQualityNames[q]);
+
+ float ms = (end_time - start_time).InMillisecondsF() / iterations;
+ VLOG(0) << base::StringPrintf("*RESULT gpu_scale_time: %s=%.2f ms\n",
+ name.c_str(), ms);
+ }
+ }
+ }
+}
+
+// This is more of a test utility than a test.
+// Put an PNG image called "testimage.png" in your
+// current directory, then run this test. It will
+// create testoutput_Q_P.png, where Q is the scaling
+// mode and P is the scaling percentage taken from
+// the table below.
+TEST_F(GLHelperTest, DISABLED_ScaleTestImage) {
+ int percents[] = {
+ 230, 180, 150, 110, 90, 70, 50, 49, 40, 20, 10,
+ };
+
+ SkBitmap input;
+ LoadPngFileToSkBitmap(base::FilePath(FILE_PATH_LITERAL("testimage.png")),
+ &input);
+
+ uint32_t framebuffer;
+ gl_->GenFramebuffers(1, &framebuffer);
+ uint32_t src_texture;
+ gl_->GenTextures(1, &src_texture);
+ const gfx::Size src_size(input.width(), input.height());
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ gl_->BindTexture(GL_TEXTURE_2D, src_texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_size.width(),
+ src_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ input.getPixels());
+
+ for (size_t q = 0; q < arraysize(kQualities); q++) {
+ for (size_t p = 0; p < arraysize(percents); p++) {
+ const gfx::Size dst_size(input.width() * percents[p] / 100,
+ input.height() * percents[p] / 100);
+ uint32_t dst_texture = helper_->CopyAndScaleTexture(
+ src_texture, src_size, dst_size, false, kQualities[q]);
+
+ SkBitmap output_pixels;
+ output_pixels.allocN32Pixels(dst_size.width(), dst_size.height());
+
+ helper_->ReadbackTextureSync(
+ dst_texture, gfx::Rect(0, 0, dst_size.width(), dst_size.height()),
+ static_cast<unsigned char*>(output_pixels.getPixels()),
+ kN32_SkColorType);
+ gl_->DeleteTextures(1, &dst_texture);
+ std::string filename = base::StringPrintf("testoutput_%s_%d.ppm",
+ kQualityNames[q], percents[p]);
+ VLOG(0) << "Writing " << filename;
+ SaveToFile(&output_pixels, base::FilePath::FromUTF8Unsafe(filename));
+ }
+ }
+ gl_->DeleteTextures(1, &src_texture);
+ gl_->DeleteFramebuffers(1, &framebuffer);
+}
+
+} // namespace
diff --git a/chromium/content/browser/compositor/gl_helper_readback_support.cc b/chromium/content/browser/compositor/gl_helper_readback_support.cc
new file mode 100644
index 00000000000..c389eda6ba5
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_readback_support.cc
@@ -0,0 +1,172 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/gl_helper_readback_support.h"
+#include "base/logging.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+
+namespace content {
+
+GLHelperReadbackSupport::GLHelperReadbackSupport(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl) {
+ InitializeReadbackSupport();
+}
+
+GLHelperReadbackSupport::~GLHelperReadbackSupport() {}
+
+void GLHelperReadbackSupport::InitializeReadbackSupport() {
+ // We are concerned about 16, 32-bit formats only. The below are the most
+ // used 16, 32-bit formats. In future if any new format support is needed
+ // that should be added here. Initialize the array with
+ // GLHelperReadbackSupport::NOT_SUPPORTED as we dont know the supported
+ // formats yet.
+ for (int i = 0; i <= kLastEnum_SkColorType; ++i) {
+ format_support_table_[i] = GLHelperReadbackSupport::NOT_SUPPORTED;
+ }
+ // TODO(sikugu): kAlpha_8_SkColorType support check is failing on mesa.
+ // See crbug.com/415667.
+ CheckForReadbackSupport(kRGB_565_SkColorType);
+ CheckForReadbackSupport(kARGB_4444_SkColorType);
+ CheckForReadbackSupport(kRGBA_8888_SkColorType);
+ CheckForReadbackSupport(kBGRA_8888_SkColorType);
+ // Further any formats, support should be checked here.
+}
+
+void GLHelperReadbackSupport::CheckForReadbackSupport(
+ SkColorType texture_format) {
+ bool supports_format = false;
+ switch (texture_format) {
+ case kRGB_565_SkColorType:
+ supports_format = SupportsFormat(GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
+ break;
+ case kRGBA_8888_SkColorType:
+ // This is the baseline, assume always true.
+ supports_format = true;
+ break;
+ case kBGRA_8888_SkColorType:
+ supports_format = SupportsFormat(GL_BGRA_EXT, GL_UNSIGNED_BYTE);
+ break;
+ case kARGB_4444_SkColorType:
+ supports_format = false;
+ break;
+ default:
+ NOTREACHED();
+ supports_format = false;
+ break;
+ }
+ DCHECK((int)texture_format <= (int)kLastEnum_SkColorType);
+ format_support_table_[texture_format] =
+ supports_format ? GLHelperReadbackSupport::SUPPORTED
+ : GLHelperReadbackSupport::NOT_SUPPORTED;
+}
+
+void GLHelperReadbackSupport::GetAdditionalFormat(GLenum format,
+ GLenum type,
+ GLenum* format_out,
+ GLenum* type_out) {
+ for (unsigned int i = 0; i < format_cache_.size(); i++) {
+ if (format_cache_[i].format == format && format_cache_[i].type == type) {
+ *format_out = format_cache_[i].read_format;
+ *type_out = format_cache_[i].read_type;
+ return;
+ }
+ }
+
+ const int kTestSize = 64;
+ content::ScopedTexture dst_texture(gl_);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, format, kTestSize, kTestSize, 0, format,
+ type, NULL);
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
+ dst_framebuffer);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ dst_texture, 0);
+ GLint format_tmp = 0, type_tmp = 0;
+ gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format_tmp);
+ gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type_tmp);
+ *format_out = format_tmp;
+ *type_out = type_tmp;
+
+ struct FormatCacheEntry entry = {format, type, *format_out, *type_out};
+ format_cache_.push_back(entry);
+}
+
+bool GLHelperReadbackSupport::SupportsFormat(GLenum format, GLenum type) {
+ // GLES2.0 Specification says this pairing is always supported
+ // with additional format from GL_IMPLEMENTATION_COLOR_READ_FORMAT/TYPE
+ if (format == GL_RGBA && type == GL_UNSIGNED_BYTE)
+ return true;
+
+ bool supports_format = false;
+ GLenum ext_format = 0, ext_type = 0;
+ GetAdditionalFormat(format, type, &ext_format, &ext_type);
+ if ((ext_format == format) && (ext_type == type)) {
+ supports_format = true;
+ }
+ return supports_format;
+}
+
+GLHelperReadbackSupport::FormatSupport
+GLHelperReadbackSupport::GetReadbackConfig(SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel) {
+ DCHECK(format && type && bytes_per_pixel);
+ *bytes_per_pixel = 4;
+ *type = GL_UNSIGNED_BYTE;
+ GLenum new_format = 0, new_type = 0;
+ switch (color_type) {
+ case kRGB_565_SkColorType:
+ if (format_support_table_[color_type] ==
+ GLHelperReadbackSupport::SUPPORTED) {
+ *format = GL_RGB;
+ *type = GL_UNSIGNED_SHORT_5_6_5;
+ *bytes_per_pixel = 2;
+ return GLHelperReadbackSupport::SUPPORTED;
+ }
+ break;
+ case kRGBA_8888_SkColorType:
+ *format = GL_RGBA;
+ if (can_swizzle) {
+ // If GL_BGRA_EXT is advertised as the readback format through
+ // GL_IMPLEMENTATION_COLOR_READ_FORMAT then assume it is preferred by
+ // the implementation for performance.
+ GetAdditionalFormat(*format, *type, &new_format, &new_type);
+
+ if (new_format == GL_BGRA_EXT && new_type == GL_UNSIGNED_BYTE) {
+ *format = GL_BGRA_EXT;
+ return GLHelperReadbackSupport::SWIZZLE;
+ }
+ }
+ return GLHelperReadbackSupport::SUPPORTED;
+ case kBGRA_8888_SkColorType:
+ *format = GL_BGRA_EXT;
+ if (format_support_table_[color_type] ==
+ GLHelperReadbackSupport::SUPPORTED)
+ return GLHelperReadbackSupport::SUPPORTED;
+
+ if (can_swizzle) {
+ *format = GL_RGBA;
+ return GLHelperReadbackSupport::SWIZZLE;
+ }
+
+ break;
+ case kARGB_4444_SkColorType:
+ return GLHelperReadbackSupport::NOT_SUPPORTED;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ return GLHelperReadbackSupport::NOT_SUPPORTED;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/gl_helper_readback_support.h b/chromium/content/browser/compositor/gl_helper_readback_support.h
new file mode 100644
index 00000000000..8f83a1fbc6b
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_readback_support.h
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_GL_HELPER_READBACK_SUPPORT_H_
+#define CONTENT_BROWSER_COMPOSITOR_GL_HELPER_READBACK_SUPPORT_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "content/browser/compositor/gl_helper.h"
+
+namespace content {
+
+class CONTENT_EXPORT GLHelperReadbackSupport {
+ public:
+ enum FormatSupport { SUPPORTED, SWIZZLE, NOT_SUPPORTED };
+
+ GLHelperReadbackSupport(gpu::gles2::GLES2Interface* gl);
+
+ ~GLHelperReadbackSupport();
+
+ // For a given color type retrieve whether readback is supported and if so
+ // how it should be performed. The |format|, |type| and |bytes_per_pixel| are
+ // the values that should be used with glReadPixels to facilitate the
+ // readback. If |can_swizzle| is true then this method will return SWIZZLE if
+ // the data needs to be swizzled before using the returned |format| otherwise
+ // the method will return SUPPORTED to indicate that readback is permitted of
+ // this color othewise NOT_SUPPORTED will be returned. This method always
+ // overwrites the out values irrespective of the return value.
+ FormatSupport GetReadbackConfig(SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel);
+ // Provides the additional readback format/type pairing for a render target
+ // of a given format/type pairing
+ void GetAdditionalFormat(GLenum format,
+ GLenum type,
+ GLenum* format_out,
+ GLenum* type_out);
+
+ private:
+ struct FormatCacheEntry {
+ GLenum format;
+ GLenum type;
+ GLenum read_format;
+ GLenum read_type;
+ };
+
+ // This populates the format_support_table with the list of supported
+ // formats.
+ void InitializeReadbackSupport();
+
+ // This api is called once per format and it is done in the
+ // InitializeReadbackSupport. We should not use this any where
+ // except the InitializeReadbackSupport.Calling this at other places
+ // can distrub the state of normal gl operations.
+ void CheckForReadbackSupport(SkColorType texture_format);
+
+ // Helper functions for checking the supported texture formats.
+ // Avoid using this API in between texture operations, as this does some
+ // teture opertions (bind, attach) internally.
+ bool SupportsFormat(GLenum format, GLenum type);
+
+ FormatSupport format_support_table_[kLastEnum_SkColorType + 1];
+
+ gpu::gles2::GLES2Interface* gl_;
+ std::vector<struct FormatCacheEntry> format_cache_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_GL_HELPER_READBACK_SUPPORT_H_
diff --git a/chromium/content/browser/compositor/gl_helper_scaling.cc b/chromium/content/browser/compositor/gl_helper_scaling.cc
new file mode 100644
index 00000000000..0c7d9775f35
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_scaling.cc
@@ -0,0 +1,881 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/gl_helper_scaling.h"
+
+#include <stddef.h>
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace content {
+
+GLHelperScaling::GLHelperScaling(GLES2Interface* gl, GLHelper* helper)
+ : gl_(gl), helper_(helper), vertex_attributes_buffer_(gl_) {
+ InitBuffer();
+}
+
+GLHelperScaling::~GLHelperScaling() {}
+
+// Used to keep track of a generated shader program. The program
+// is passed in as text through Setup and is used by calling
+// UseProgram() with the right parameters. Note that |gl_|
+// and |helper_| are assumed to live longer than this program.
+class ShaderProgram : public base::RefCounted<ShaderProgram> {
+ public:
+ ShaderProgram(GLES2Interface* gl, GLHelper* helper)
+ : gl_(gl),
+ helper_(helper),
+ program_(gl_->CreateProgram()),
+ position_location_(-1),
+ texcoord_location_(-1),
+ src_subrect_location_(-1),
+ src_pixelsize_location_(-1),
+ dst_pixelsize_location_(-1),
+ scaling_vector_location_(-1),
+ color_weights_location_(-1) {}
+
+ // Compile shader program.
+ void Setup(const GLchar* vertex_shader_text,
+ const GLchar* fragment_shader_text);
+
+ // UseProgram must be called with GL_TEXTURE_2D bound to the
+ // source texture and GL_ARRAY_BUFFER bound to a vertex
+ // attribute buffer.
+ void UseProgram(const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool scale_x,
+ bool flip_y,
+ GLfloat color_weights[4]);
+
+ bool Initialized() const { return position_location_ != -1; }
+
+ private:
+ friend class base::RefCounted<ShaderProgram>;
+ ~ShaderProgram() { gl_->DeleteProgram(program_); }
+
+ GLES2Interface* gl_;
+ GLHelper* helper_;
+
+ // A program for copying a source texture into a destination texture.
+ GLuint program_;
+
+ // The location of the position in the program.
+ GLint position_location_;
+ // The location of the texture coordinate in the program.
+ GLint texcoord_location_;
+ // The location of the source texture in the program.
+ GLint texture_location_;
+ // The location of the texture coordinate of
+ // the sub-rectangle in the program.
+ GLint src_subrect_location_;
+ // Location of size of source image in pixels.
+ GLint src_pixelsize_location_;
+ // Location of size of destination image in pixels.
+ GLint dst_pixelsize_location_;
+ // Location of vector for scaling direction.
+ GLint scaling_vector_location_;
+ // Location of color weights.
+ GLint color_weights_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderProgram);
+};
+
+// Implementation of a single stage in a scaler pipeline. If the pipeline has
+// multiple stages, it calls Scale() on the subscaler, then further scales the
+// output. Caches textures and framebuffers to avoid allocating/deleting
+// them once per frame, which can be expensive on some drivers.
+class ScalerImpl : public GLHelper::ScalerInterface,
+ public GLHelperScaling::ShaderInterface {
+ public:
+ // |gl| and |copy_impl| are expected to live longer than this object.
+ // |src_size| is the size of the input texture in pixels.
+ // |dst_size| is the size of the output texutre in pixels.
+ // |src_subrect| is the portion of the src to copy to the output texture.
+ // If |scale_x| is true, we are scaling along the X axis, otherwise Y.
+ // If we are scaling in both X and Y, |scale_x| is ignored.
+ // If |vertically_flip_texture| is true, output will be upside-down.
+ // If |swizzle| is true, RGBA will be transformed into BGRA.
+ // |color_weights| are only used together with SHADER_PLANAR to specify
+ // how to convert RGB colors into a single value.
+ ScalerImpl(GLES2Interface* gl,
+ GLHelperScaling* scaler_helper,
+ const GLHelperScaling::ScalerStage& scaler_stage,
+ ScalerImpl* subscaler,
+ const float* color_weights)
+ : gl_(gl),
+ scaler_helper_(scaler_helper),
+ spec_(scaler_stage),
+ intermediate_texture_(0),
+ dst_framebuffer_(gl),
+ subscaler_(subscaler) {
+ if (color_weights) {
+ color_weights_[0] = color_weights[0];
+ color_weights_[1] = color_weights[1];
+ color_weights_[2] = color_weights[2];
+ color_weights_[3] = color_weights[3];
+ } else {
+ color_weights_[0] = 0.0;
+ color_weights_[1] = 0.0;
+ color_weights_[2] = 0.0;
+ color_weights_[3] = 0.0;
+ }
+ shader_program_ =
+ scaler_helper_->GetShaderProgram(spec_.shader, spec_.swizzle);
+
+ if (subscaler_) {
+ intermediate_texture_ = 0u;
+ gl_->GenTextures(1, &intermediate_texture_);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_,
+ intermediate_texture_);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spec_.src_size.width(),
+ spec_.src_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ NULL);
+ }
+ }
+
+ ~ScalerImpl() override {
+ if (intermediate_texture_) {
+ gl_->DeleteTextures(1, &intermediate_texture_);
+ }
+ }
+
+ // GLHelperShader::ShaderInterface implementation.
+ void Execute(GLuint source_texture,
+ const std::vector<GLuint>& dest_textures) override {
+ if (subscaler_) {
+ subscaler_->Scale(source_texture, intermediate_texture_);
+ source_texture = intermediate_texture_;
+ }
+
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
+ gl_, dst_framebuffer_);
+ DCHECK_GT(dest_textures.size(), 0U);
+ scoped_ptr<GLenum[]> buffers(new GLenum[dest_textures.size()]);
+ for (size_t t = 0; t < dest_textures.size(); t++) {
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dest_textures[t]);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + t,
+ GL_TEXTURE_2D, dest_textures[t], 0);
+ buffers[t] = GL_COLOR_ATTACHMENT0 + t;
+ }
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, source_texture);
+
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(
+ gl_, scaler_helper_->vertex_attributes_buffer_);
+ shader_program_->UseProgram(spec_.src_size, spec_.src_subrect,
+ spec_.dst_size, spec_.scale_x,
+ spec_.vertically_flip_texture, color_weights_);
+ gl_->Viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height());
+
+ if (dest_textures.size() > 1) {
+ DCHECK_LE(static_cast<int>(dest_textures.size()),
+ scaler_helper_->helper_->MaxDrawBuffers());
+ gl_->DrawBuffersEXT(dest_textures.size(), buffers.get());
+ }
+ // Conduct texture mapping by drawing a quad composed of two triangles.
+ gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ if (dest_textures.size() > 1) {
+ // Set the draw buffers back to not confuse others.
+ gl_->DrawBuffersEXT(1, &buffers[0]);
+ }
+ }
+
+ // GLHelper::ScalerInterface implementation.
+ void Scale(GLuint source_texture, GLuint dest_texture) override {
+ std::vector<GLuint> tmp(1);
+ tmp[0] = dest_texture;
+ Execute(source_texture, tmp);
+ }
+
+ const gfx::Size& SrcSize() override {
+ if (subscaler_) {
+ return subscaler_->SrcSize();
+ }
+ return spec_.src_size;
+ }
+ const gfx::Rect& SrcSubrect() override {
+ if (subscaler_) {
+ return subscaler_->SrcSubrect();
+ }
+ return spec_.src_subrect;
+ }
+ const gfx::Size& DstSize() override { return spec_.dst_size; }
+
+ private:
+ GLES2Interface* gl_;
+ GLHelperScaling* scaler_helper_;
+ GLHelperScaling::ScalerStage spec_;
+ GLfloat color_weights_[4];
+ GLuint intermediate_texture_;
+ scoped_refptr<ShaderProgram> shader_program_;
+ ScopedFramebuffer dst_framebuffer_;
+ scoped_ptr<ScalerImpl> subscaler_;
+};
+
+GLHelperScaling::ScalerStage::ScalerStage(ShaderType shader_,
+ gfx::Size src_size_,
+ gfx::Rect src_subrect_,
+ gfx::Size dst_size_,
+ bool scale_x_,
+ bool vertically_flip_texture_,
+ bool swizzle_)
+ : shader(shader_),
+ src_size(src_size_),
+ src_subrect(src_subrect_),
+ dst_size(dst_size_),
+ scale_x(scale_x_),
+ vertically_flip_texture(vertically_flip_texture_),
+ swizzle(swizzle_) {}
+
+GLHelperScaling::ScalerStage::ScalerStage(const ScalerStage& other) = default;
+
+// The important inputs for this function is |x_ops| and
+// |y_ops|. They represent scaling operations to be done
+// on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST,
+// then we will interpret these scale operations literally and we'll
+// create one scaler stage for each ScaleOp. However, if |quality|
+// is SCALER_QUALITY_GOOD, then we can do a whole bunch of optimizations
+// by combining two or more ScaleOps in to a single scaler stage.
+// Normally we process ScaleOps from |y_ops| first and |x_ops| after
+// all |y_ops| are processed, but sometimes we can combine one or more
+// operation from both queues essentially for free. This is the reason
+// why |x_ops| and |y_ops| aren't just one single queue.
+void GLHelperScaling::ConvertScalerOpsToScalerStages(
+ GLHelper::ScalerQuality quality,
+ gfx::Size src_size,
+ gfx::Rect src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ std::deque<GLHelperScaling::ScaleOp>* x_ops,
+ std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ std::vector<ScalerStage>* scaler_stages) {
+ while (!x_ops->empty() || !y_ops->empty()) {
+ gfx::Size intermediate_size = src_subrect.size();
+ std::deque<ScaleOp>* current_queue = NULL;
+
+ if (!y_ops->empty()) {
+ current_queue = y_ops;
+ } else {
+ current_queue = x_ops;
+ }
+
+ ShaderType current_shader = SHADER_BILINEAR;
+ switch (current_queue->front().scale_factor) {
+ case 0:
+ if (quality == GLHelper::SCALER_QUALITY_BEST) {
+ current_shader = SHADER_BICUBIC_UPSCALE;
+ }
+ break;
+ case 2:
+ if (quality == GLHelper::SCALER_QUALITY_BEST) {
+ current_shader = SHADER_BICUBIC_HALF_1D;
+ }
+ break;
+ case 3:
+ DCHECK(quality != GLHelper::SCALER_QUALITY_BEST);
+ current_shader = SHADER_BILINEAR3;
+ break;
+ default:
+ NOTREACHED();
+ }
+ bool scale_x = current_queue->front().scale_x;
+ current_queue->front().UpdateSize(&intermediate_size);
+ current_queue->pop_front();
+
+ // Optimization: Sometimes we can combine 2-4 scaling operations into
+ // one operation.
+ if (quality == GLHelper::SCALER_QUALITY_GOOD) {
+ if (!current_queue->empty() && current_shader == SHADER_BILINEAR) {
+ // Combine two steps in the same dimension.
+ current_queue->front().UpdateSize(&intermediate_size);
+ current_queue->pop_front();
+ current_shader = SHADER_BILINEAR2;
+ if (!current_queue->empty()) {
+ // Combine three steps in the same dimension.
+ current_queue->front().UpdateSize(&intermediate_size);
+ current_queue->pop_front();
+ current_shader = SHADER_BILINEAR4;
+ }
+ }
+ // Check if we can combine some steps in the other dimension as well.
+ // Since all shaders currently use GL_LINEAR, we can easily scale up
+ // or scale down by exactly 2x at the same time as we do another
+ // operation. Currently, the following mergers are supported:
+ // * 1 bilinear Y-pass with 1 bilinear X-pass (up or down)
+ // * 2 bilinear Y-passes with 2 bilinear X-passes
+ // * 1 bilinear Y-pass with N bilinear X-pass
+ // * N bilinear Y-passes with 1 bilinear X-pass (down only)
+ // Measurements indicate that generalizing this for 3x3 and 4x4
+ // makes it slower on some platforms, such as the Pixel.
+ if (!scale_x && x_ops->size() > 0 && x_ops->front().scale_factor <= 2) {
+ int x_passes = 0;
+ if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) {
+ // 2y + 2x passes
+ x_passes = 2;
+ current_shader = SHADER_BILINEAR2X2;
+ } else if (current_shader == SHADER_BILINEAR) {
+ // 1y + Nx passes
+ scale_x = true;
+ switch (x_ops->size()) {
+ case 0:
+ NOTREACHED();
+ case 1:
+ if (x_ops->front().scale_factor == 3) {
+ current_shader = SHADER_BILINEAR3;
+ }
+ x_passes = 1;
+ break;
+ case 2:
+ x_passes = 2;
+ current_shader = SHADER_BILINEAR2;
+ break;
+ default:
+ x_passes = 3;
+ current_shader = SHADER_BILINEAR4;
+ break;
+ }
+ } else if (x_ops->front().scale_factor == 2) {
+ // Ny + 1x-downscale
+ x_passes = 1;
+ }
+
+ for (int i = 0; i < x_passes; i++) {
+ x_ops->front().UpdateSize(&intermediate_size);
+ x_ops->pop_front();
+ }
+ }
+ }
+
+ scaler_stages->push_back(ScalerStage(current_shader, src_size, src_subrect,
+ intermediate_size, scale_x,
+ vertically_flip_texture, swizzle));
+ src_size = intermediate_size;
+ src_subrect = gfx::Rect(intermediate_size);
+ vertically_flip_texture = false;
+ swizzle = false;
+ }
+}
+
+void GLHelperScaling::ComputeScalerStages(
+ GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ std::vector<ScalerStage>* scaler_stages) {
+ if (quality == GLHelper::SCALER_QUALITY_FAST ||
+ src_subrect.size() == dst_size) {
+ scaler_stages->push_back(ScalerStage(SHADER_BILINEAR, src_size, src_subrect,
+ dst_size, false,
+ vertically_flip_texture, swizzle));
+ return;
+ }
+
+ std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
+ GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), dst_size.width(), true,
+ quality == GLHelper::SCALER_QUALITY_GOOD,
+ &x_ops);
+ GLHelperScaling::ScaleOp::AddOps(
+ src_subrect.height(), dst_size.height(), false,
+ quality == GLHelper::SCALER_QUALITY_GOOD, &y_ops);
+
+ ConvertScalerOpsToScalerStages(quality, src_size, src_subrect, dst_size,
+ vertically_flip_texture, swizzle, &x_ops,
+ &y_ops, scaler_stages);
+}
+
+GLHelper::ScalerInterface* GLHelperScaling::CreateScaler(
+ GLHelper::ScalerQuality quality,
+ gfx::Size src_size,
+ gfx::Rect src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle) {
+ std::vector<ScalerStage> scaler_stages;
+ ComputeScalerStages(quality, src_size, src_subrect, dst_size,
+ vertically_flip_texture, swizzle, &scaler_stages);
+
+ ScalerImpl* ret = NULL;
+ for (unsigned int i = 0; i < scaler_stages.size(); i++) {
+ ret = new ScalerImpl(gl_, this, scaler_stages[i], ret, NULL);
+ }
+ return ret;
+}
+
+GLHelper::ScalerInterface* GLHelperScaling::CreatePlanarScaler(
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ const float color_weights[4]) {
+ ScalerStage stage(SHADER_PLANAR, src_size, src_subrect, dst_size, true,
+ vertically_flip_texture, swizzle);
+ return new ScalerImpl(gl_, this, stage, NULL, color_weights);
+}
+
+GLHelperScaling::ShaderInterface* GLHelperScaling::CreateYuvMrtShader(
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ ShaderType shader) {
+ DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2);
+ ScalerStage stage(shader, src_size, src_subrect, dst_size, true,
+ vertically_flip_texture, swizzle);
+ return new ScalerImpl(gl_, this, stage, NULL, NULL);
+}
+
+const GLfloat GLHelperScaling::kVertexAttributes[] = {
+ -1.0f, -1.0f, 0.0f, 0.0f, // vertex 0
+ 1.0f, -1.0f, 1.0f, 0.0f, // vertex 1
+ -1.0f, 1.0f, 0.0f, 1.0f, // vertex 2
+ 1.0f, 1.0f, 1.0f, 1.0f,
+}; // vertex 3
+
+void GLHelperScaling::InitBuffer() {
+ ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(gl_,
+ vertex_attributes_buffer_);
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(kVertexAttributes), kVertexAttributes,
+ GL_STATIC_DRAW);
+}
+
+scoped_refptr<ShaderProgram> GLHelperScaling::GetShaderProgram(ShaderType type,
+ bool swizzle) {
+ ShaderProgramKeyType key(type, swizzle);
+ scoped_refptr<ShaderProgram>& cache_entry(shader_programs_[key]);
+ if (!cache_entry.get()) {
+ cache_entry = new ShaderProgram(gl_, helper_);
+ std::basic_string<GLchar> vertex_program;
+ std::basic_string<GLchar> fragment_program;
+ std::basic_string<GLchar> vertex_header;
+ std::basic_string<GLchar> fragment_directives;
+ std::basic_string<GLchar> fragment_header;
+ std::basic_string<GLchar> shared_variables;
+
+ vertex_header.append(
+ "precision highp float;\n"
+ "attribute vec2 a_position;\n"
+ "attribute vec2 a_texcoord;\n"
+ "uniform vec4 src_subrect;\n");
+
+ fragment_header.append(
+ "precision mediump float;\n"
+ "uniform sampler2D s_texture;\n");
+
+ vertex_program.append(
+ " gl_Position = vec4(a_position, 0.0, 1.0);\n"
+ " vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n");
+
+ switch (type) {
+ case SHADER_BILINEAR:
+ shared_variables.append("varying vec2 v_texcoord;\n");
+ vertex_program.append(" v_texcoord = texcoord;\n");
+ fragment_program.append(
+ " gl_FragColor = texture2D(s_texture, v_texcoord);\n");
+ break;
+
+ case SHADER_BILINEAR2:
+ // This is equivialent to two passes of the BILINEAR shader above.
+ // It can be used to scale an image down 1.0x-2.0x in either dimension,
+ // or exactly 4x.
+ shared_variables.append(
+ "varying vec4 v_texcoords;\n"); // 2 texcoords packed in one quad
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 4.0;\n"
+ " v_texcoords.xy = texcoord + step;\n"
+ " v_texcoords.zw = texcoord - step;\n");
+
+ fragment_program.append(
+ " gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n"
+ " texture2D(s_texture, v_texcoords.zw)) / 2.0;\n");
+ break;
+
+ case SHADER_BILINEAR3:
+ // This is kind of like doing 1.5 passes of the BILINEAR shader.
+ // It can be used to scale an image down 1.5x-3.0x, or exactly 6x.
+ shared_variables.append(
+ "varying vec4 v_texcoords1;\n" // 2 texcoords packed in one quad
+ "varying vec2 v_texcoords2;\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 3.0;\n"
+ " v_texcoords1.xy = texcoord + step;\n"
+ " v_texcoords1.zw = texcoord;\n"
+ " v_texcoords2 = texcoord - step;\n");
+ fragment_program.append(
+ " gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n"
+ " texture2D(s_texture, v_texcoords1.zw) +\n"
+ " texture2D(s_texture, v_texcoords2)) / 3.0;\n");
+ break;
+
+ case SHADER_BILINEAR4:
+ // This is equivialent to three passes of the BILINEAR shader above,
+ // It can be used to scale an image down 2.0x-4.0x or exactly 8x.
+ shared_variables.append("varying vec4 v_texcoords[2];\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 8.0;\n"
+ " v_texcoords[0].xy = texcoord - step * 3.0;\n"
+ " v_texcoords[0].zw = texcoord - step;\n"
+ " v_texcoords[1].xy = texcoord + step;\n"
+ " v_texcoords[1].zw = texcoord + step * 3.0;\n");
+ fragment_program.append(
+ " gl_FragColor = (\n"
+ " texture2D(s_texture, v_texcoords[0].xy) +\n"
+ " texture2D(s_texture, v_texcoords[0].zw) +\n"
+ " texture2D(s_texture, v_texcoords[1].xy) +\n"
+ " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
+ break;
+
+ case SHADER_BILINEAR2X2:
+ // This is equivialent to four passes of the BILINEAR shader above.
+ // Two in each dimension. It can be used to scale an image down
+ // 1.0x-2.0x in both X and Y directions. Or, it could be used to
+ // scale an image down by exactly 4x in both dimensions.
+ shared_variables.append("varying vec4 v_texcoords[2];\n");
+ vertex_header.append("uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n"
+ " v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n"
+ " v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n"
+ " v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n"
+ " v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n");
+ fragment_program.append(
+ " gl_FragColor = (\n"
+ " texture2D(s_texture, v_texcoords[0].xy) +\n"
+ " texture2D(s_texture, v_texcoords[0].zw) +\n"
+ " texture2D(s_texture, v_texcoords[1].xy) +\n"
+ " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
+ break;
+
+ case SHADER_BICUBIC_HALF_1D:
+ // This scales down texture by exactly half in one dimension.
+ // directions in one pass. We use bilinear lookup to reduce
+ // the number of texture reads from 8 to 4
+ shared_variables.append(
+ "const float CenterDist = 99.0 / 140.0;\n"
+ "const float LobeDist = 11.0 / 4.0;\n"
+ "const float CenterWeight = 35.0 / 64.0;\n"
+ "const float LobeWeight = -3.0 / 64.0;\n"
+ "varying vec4 v_texcoords[2];\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 src_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n"
+ " v_texcoords[0].xy = texcoord - LobeDist * step;\n"
+ " v_texcoords[0].zw = texcoord - CenterDist * step;\n"
+ " v_texcoords[1].xy = texcoord + CenterDist * step;\n"
+ " v_texcoords[1].zw = texcoord + LobeDist * step;\n");
+ fragment_program.append(
+ " gl_FragColor = \n"
+ // Lobe pixels
+ " (texture2D(s_texture, v_texcoords[0].xy) +\n"
+ " texture2D(s_texture, v_texcoords[1].zw)) *\n"
+ " LobeWeight +\n"
+ // Center pixels
+ " (texture2D(s_texture, v_texcoords[0].zw) +\n"
+ " texture2D(s_texture, v_texcoords[1].xy)) *\n"
+ " CenterWeight;\n");
+ break;
+
+ case SHADER_BICUBIC_UPSCALE:
+ // When scaling up, we need 4 texture reads, but we can
+ // save some instructions because will know in which range of
+ // the bicubic function each call call to the bicubic function
+ // will be in.
+ // Also, when sampling the bicubic function like this, the sum
+ // is always exactly one, so we can skip normalization as well.
+ shared_variables.append("varying vec2 v_texcoord;\n");
+ vertex_program.append(" v_texcoord = texcoord;\n");
+ fragment_header.append(
+ "uniform vec2 src_pixelsize;\n"
+ "uniform vec2 scaling_vector;\n"
+ "const float a = -0.5;\n"
+ // This function is equivialent to calling the bicubic
+ // function with x-1, x, 1-x and 2-x
+ // (assuming 0 <= x < 1)
+ "vec4 filt4(float x) {\n"
+ " return vec4(x * x * x, x * x, x, 1) *\n"
+ " mat4( a, -2.0 * a, a, 0.0,\n"
+ " a + 2.0, -a - 3.0, 0.0, 1.0,\n"
+ " -a - 2.0, 3.0 + 2.0 * a, -a, 0.0,\n"
+ " -a, a, 0.0, 0.0);\n"
+ "}\n"
+ "mat4 pixels_x(vec2 pos, vec2 step) {\n"
+ " return mat4(\n"
+ " texture2D(s_texture, pos - step),\n"
+ " texture2D(s_texture, pos),\n"
+ " texture2D(s_texture, pos + step),\n"
+ " texture2D(s_texture, pos + step * 2.0));\n"
+ "}\n");
+ fragment_program.append(
+ " vec2 pixel_pos = v_texcoord * src_pixelsize - \n"
+ " scaling_vector / 2.0;\n"
+ " float frac = fract(dot(pixel_pos, scaling_vector));\n"
+ " vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n"
+ " vec2 step = scaling_vector / src_pixelsize;\n"
+ " gl_FragColor = pixels_x(base, step) * filt4(frac);\n");
+ break;
+
+ case SHADER_PLANAR:
+ // Converts four RGBA pixels into one pixel. Each RGBA
+ // pixel will be dot-multiplied with the color weights and
+ // then placed into a component of the output. This is used to
+ // convert RGBA textures into Y, U and V textures. We do this
+ // because single-component textures are not renderable on all
+ // architectures.
+ shared_variables.append("varying vec4 v_texcoords[2];\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 4.0;\n"
+ " v_texcoords[0].xy = texcoord - step * 1.5;\n"
+ " v_texcoords[0].zw = texcoord - step * 0.5;\n"
+ " v_texcoords[1].xy = texcoord + step * 0.5;\n"
+ " v_texcoords[1].zw = texcoord + step * 1.5;\n");
+ fragment_header.append("uniform vec4 color_weights;\n");
+ fragment_program.append(
+ " gl_FragColor = color_weights * mat4(\n"
+ " vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n"
+ " vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n"
+ " vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n"
+ " vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n");
+ break;
+
+ case SHADER_YUV_MRT_PASS1:
+ // RGB24 to YV12 in two passes; writing two 8888 targets each pass.
+ //
+ // YV12 is full-resolution luma and half-resolution blue/red chroma.
+ //
+ // (original)
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX
+ // |
+ // | (y plane) (temporary)
+ // | YYYY YYYY UUVV UUVV
+ // +--> { YYYY YYYY + UUVV UUVV }
+ // YYYY YYYY UUVV UUVV
+ // First YYYY YYYY UUVV UUVV
+ // pass YYYY YYYY UUVV UUVV
+ // YYYY YYYY UUVV UUVV
+ // |
+ // | (u plane) (v plane)
+ // Second | UUUU VVVV
+ // pass +--> { UUUU + VVVV }
+ // UUUU VVVV
+ //
+ shared_variables.append("varying vec4 v_texcoords[2];\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 4.0;\n"
+ " v_texcoords[0].xy = texcoord - step * 1.5;\n"
+ " v_texcoords[0].zw = texcoord - step * 0.5;\n"
+ " v_texcoords[1].xy = texcoord + step * 0.5;\n"
+ " v_texcoords[1].zw = texcoord + step * 1.5;\n");
+ fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
+ fragment_header.append(
+ "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n"
+ "const float kYBias = 0.0625;\n"
+ // Divide U and V by two to compensate for averaging below.
+ "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n"
+ "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n"
+ "const float kUVBias = 0.5;\n");
+ fragment_program.append(
+ " vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n"
+ " vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n"
+ " vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n"
+ " vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n"
+ " vec3 pixel12 = pixel1 + pixel2;\n"
+ " vec3 pixel34 = pixel3 + pixel4;\n"
+ " gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n"
+ " dot(pixel2, kRGBtoY),\n"
+ " dot(pixel3, kRGBtoY),\n"
+ " dot(pixel4, kRGBtoY)) + kYBias;\n"
+ " gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n"
+ " dot(pixel34, kRGBtoU),\n"
+ " dot(pixel12, kRGBtoV),\n"
+ " dot(pixel34, kRGBtoV)) + kUVBias;\n");
+ break;
+
+ case SHADER_YUV_MRT_PASS2:
+ // We're just sampling two pixels and unswizzling them. There's
+ // no need to do vertical scaling with math, since bilinear
+ // interpolation in the sampler takes care of that.
+ shared_variables.append("varying vec4 v_texcoords;\n");
+ vertex_header.append(
+ "uniform vec2 scaling_vector;\n"
+ "uniform vec2 dst_pixelsize;\n");
+ vertex_program.append(
+ " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
+ " step /= 2.0;\n"
+ " v_texcoords.xy = texcoord - step * 0.5;\n"
+ " v_texcoords.zw = texcoord + step * 0.5;\n");
+ fragment_directives.append("#extension GL_EXT_draw_buffers : enable\n");
+ fragment_program.append(
+ " vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n"
+ " vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n"
+ " gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n"
+ " gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n");
+ break;
+ }
+ if (swizzle) {
+ switch (type) {
+ case SHADER_YUV_MRT_PASS1:
+ fragment_program.append(" gl_FragData[0] = gl_FragData[0].bgra;\n");
+ break;
+ case SHADER_YUV_MRT_PASS2:
+ fragment_program.append(" gl_FragData[0] = gl_FragData[0].bgra;\n");
+ fragment_program.append(" gl_FragData[1] = gl_FragData[1].bgra;\n");
+ break;
+ default:
+ fragment_program.append(" gl_FragColor = gl_FragColor.bgra;\n");
+ break;
+ }
+ }
+
+ vertex_program = vertex_header + shared_variables + "void main() {\n" +
+ vertex_program + "}\n";
+
+ fragment_program = fragment_directives + fragment_header +
+ shared_variables + "void main() {\n" + fragment_program +
+ "}\n";
+
+ cache_entry->Setup(vertex_program.c_str(), fragment_program.c_str());
+ }
+ return cache_entry;
+}
+
+void ShaderProgram::Setup(const GLchar* vertex_shader_text,
+ const GLchar* fragment_shader_text) {
+ // Shaders to map the source texture to |dst_texture_|.
+ GLuint vertex_shader =
+ helper_->CompileShaderFromSource(vertex_shader_text, GL_VERTEX_SHADER);
+ if (vertex_shader == 0)
+ return;
+
+ gl_->AttachShader(program_, vertex_shader);
+ gl_->DeleteShader(vertex_shader);
+
+ GLuint fragment_shader = helper_->CompileShaderFromSource(
+ fragment_shader_text, GL_FRAGMENT_SHADER);
+ if (fragment_shader == 0)
+ return;
+ gl_->AttachShader(program_, fragment_shader);
+ gl_->DeleteShader(fragment_shader);
+
+ gl_->LinkProgram(program_);
+
+ GLint link_status = 0;
+ gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status);
+ if (!link_status)
+ return;
+
+ position_location_ = gl_->GetAttribLocation(program_, "a_position");
+ texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord");
+ texture_location_ = gl_->GetUniformLocation(program_, "s_texture");
+ src_subrect_location_ = gl_->GetUniformLocation(program_, "src_subrect");
+ src_pixelsize_location_ = gl_->GetUniformLocation(program_, "src_pixelsize");
+ dst_pixelsize_location_ = gl_->GetUniformLocation(program_, "dst_pixelsize");
+ scaling_vector_location_ =
+ gl_->GetUniformLocation(program_, "scaling_vector");
+ color_weights_location_ = gl_->GetUniformLocation(program_, "color_weights");
+ // The only reason fetching these attribute locations should fail is
+ // if the context was spontaneously lost (i.e., because the GPU
+ // process crashed, perhaps deliberately for testing).
+ DCHECK(Initialized() || gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
+}
+
+void ShaderProgram::UseProgram(const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool scale_x,
+ bool flip_y,
+ GLfloat color_weights[4]) {
+ gl_->UseProgram(program_);
+
+ // OpenGL defines the last parameter to VertexAttribPointer as type
+ // "const GLvoid*" even though it is actually an offset into the buffer
+ // object's data store and not a pointer to the client's address space.
+ const void* offsets[2] = {0,
+ reinterpret_cast<const void*>(2 * sizeof(GLfloat))};
+
+ gl_->VertexAttribPointer(position_location_, 2, GL_FLOAT, GL_FALSE,
+ 4 * sizeof(GLfloat), offsets[0]);
+ gl_->EnableVertexAttribArray(position_location_);
+
+ gl_->VertexAttribPointer(texcoord_location_, 2, GL_FLOAT, GL_FALSE,
+ 4 * sizeof(GLfloat), offsets[1]);
+ gl_->EnableVertexAttribArray(texcoord_location_);
+
+ gl_->Uniform1i(texture_location_, 0);
+
+ // Convert |src_subrect| to texture coordinates.
+ GLfloat src_subrect_texcoord[] = {
+ static_cast<float>(src_subrect.x()) / src_size.width(),
+ static_cast<float>(src_subrect.y()) / src_size.height(),
+ static_cast<float>(src_subrect.width()) / src_size.width(),
+ static_cast<float>(src_subrect.height()) / src_size.height(),
+ };
+ if (flip_y) {
+ src_subrect_texcoord[1] += src_subrect_texcoord[3];
+ src_subrect_texcoord[3] *= -1.0;
+ }
+ gl_->Uniform4fv(src_subrect_location_, 1, src_subrect_texcoord);
+
+ gl_->Uniform2f(src_pixelsize_location_, src_size.width(), src_size.height());
+ gl_->Uniform2f(dst_pixelsize_location_, static_cast<float>(dst_size.width()),
+ static_cast<float>(dst_size.height()));
+
+ gl_->Uniform2f(scaling_vector_location_, scale_x ? 1.0 : 0.0,
+ scale_x ? 0.0 : 1.0);
+ gl_->Uniform4fv(color_weights_location_, 1, color_weights);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/gl_helper_scaling.h b/chromium/content/browser/compositor/gl_helper_scaling.h
new file mode 100644
index 00000000000..6fbc03342ad
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_scaling.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_GL_HELPER_SCALING_H_
+#define CONTENT_BROWSER_COMPOSITOR_GL_HELPER_SCALING_H_
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "base/macros.h"
+#include "content/browser/compositor/gl_helper.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+class ShaderProgram;
+class ScalerImpl;
+class GLHelperTest;
+
+// Implements GPU texture scaling methods.
+// Note that you should probably not use this class directly.
+// See gl_helper.cc::CreateScaler instead.
+class CONTENT_EXPORT GLHelperScaling {
+ public:
+ enum ShaderType {
+ SHADER_BILINEAR,
+ SHADER_BILINEAR2,
+ SHADER_BILINEAR3,
+ SHADER_BILINEAR4,
+ SHADER_BILINEAR2X2,
+ SHADER_BICUBIC_UPSCALE,
+ SHADER_BICUBIC_HALF_1D,
+ SHADER_PLANAR,
+ SHADER_YUV_MRT_PASS1,
+ SHADER_YUV_MRT_PASS2,
+ };
+
+ // Similar to ScalerInterface, but can generate multiple outputs.
+ // Used for YUV conversion in gl_helper.c
+ class CONTENT_EXPORT ShaderInterface {
+ public:
+ ShaderInterface() {}
+ virtual ~ShaderInterface() {}
+ // Note that the src_texture will have the min/mag filter set to GL_LINEAR
+ // and wrap_s/t set to CLAMP_TO_EDGE in this call.
+ virtual void Execute(GLuint source_texture,
+ const std::vector<GLuint>& dest_textures) = 0;
+ };
+
+ typedef std::pair<ShaderType, bool> ShaderProgramKeyType;
+
+ GLHelperScaling(gpu::gles2::GLES2Interface* gl, GLHelper* helper);
+ ~GLHelperScaling();
+ void InitBuffer();
+
+ GLHelper::ScalerInterface* CreateScaler(GLHelper::ScalerQuality quality,
+ gfx::Size src_size,
+ gfx::Rect src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle);
+
+ GLHelper::ScalerInterface* CreatePlanarScaler(const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ const float color_weights[4]);
+
+ ShaderInterface* CreateYuvMrtShader(const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ ShaderType shader);
+
+ private:
+ // A ScaleOp represents a pass in a scaler pipeline, in one dimension.
+ // Note that when quality is GOOD, multiple scaler passes will be
+ // combined into one operation for increased performance.
+ // Exposed in the header file for testing purposes.
+ struct ScaleOp {
+ ScaleOp(int factor, bool x, int size)
+ : scale_factor(factor), scale_x(x), scale_size(size) {}
+
+ // Calculate a set of ScaleOp needed to convert an image of size
+ // |src| into an image of size |dst|. If |scale_x| is true, then
+ // the calculations are for the X axis of the image, otherwise Y.
+ // If |allow3| is true, we can use a SHADER_BILINEAR3 to replace
+ // a scale up and scale down with a 3-tap bilinear scale.
+ // The calculated ScaleOps are added to |ops|.
+ static void AddOps(int src,
+ int dst,
+ bool scale_x,
+ bool allow3,
+ std::deque<ScaleOp>* ops) {
+ int num_downscales = 0;
+ if (allow3 && dst * 3 >= src && dst * 2 < src) {
+ // Technically, this should be a scale up and then a
+ // scale down, but it makes the optimization code more
+ // complicated.
+ ops->push_back(ScaleOp(3, scale_x, dst));
+ return;
+ }
+ while ((dst << num_downscales) < src) {
+ num_downscales++;
+ }
+ if ((dst << num_downscales) != src) {
+ ops->push_back(ScaleOp(0, scale_x, dst << num_downscales));
+ }
+ while (num_downscales) {
+ num_downscales--;
+ ops->push_back(ScaleOp(2, scale_x, dst << num_downscales));
+ }
+ }
+
+ // Update |size| to its new size. Before calling this function
+ // |size| should be the size of the input image. After calling it,
+ // |size| will be the size of the image after this particular
+ // scaling operation.
+ void UpdateSize(gfx::Size* subrect) {
+ if (scale_x) {
+ subrect->set_width(scale_size);
+ } else {
+ subrect->set_height(scale_size);
+ }
+ }
+
+ // A scale factor of 0 means upscale
+ // 2 means 50% scale
+ // 3 means 33% scale, etc.
+ int scale_factor;
+ bool scale_x; // Otherwise y
+ int scale_size; // Size to scale to.
+ };
+
+ // Full specification for a single scaling stage.
+ struct ScalerStage {
+ ScalerStage(ShaderType shader_,
+ gfx::Size src_size_,
+ gfx::Rect src_subrect_,
+ gfx::Size dst_size_,
+ bool scale_x_,
+ bool vertically_flip_texture_,
+ bool swizzle_);
+ ScalerStage(const ScalerStage& other);
+ ShaderType shader;
+ gfx::Size src_size;
+ gfx::Rect src_subrect;
+ gfx::Size dst_size;
+ bool scale_x;
+ bool vertically_flip_texture;
+ bool swizzle;
+ };
+
+ // Compute a vector of scaler stages for a particular
+ // set of input/output parameters.
+ void ComputeScalerStages(GLHelper::ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ std::vector<ScalerStage>* scaler_stages);
+
+ // Take two queues of ScaleOp structs and generate a
+ // vector of scaler stages. This is the second half of
+ // ComputeScalerStages.
+ void ConvertScalerOpsToScalerStages(
+ GLHelper::ScalerQuality quality,
+ gfx::Size src_size,
+ gfx::Rect src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ std::deque<GLHelperScaling::ScaleOp>* x_ops,
+ std::deque<GLHelperScaling::ScaleOp>* y_ops,
+ std::vector<ScalerStage>* scaler_stages);
+
+ scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
+
+ // Interleaved array of 2-dimentional vertex positions (x, y) and
+ // 2-dimentional texture coordinates (s, t).
+ static const GLfloat kVertexAttributes[];
+
+ gpu::gles2::GLES2Interface* gl_;
+ GLHelper* helper_;
+
+ // The buffer that holds the vertices and the texture coordinates data for
+ // drawing a quad.
+ ScopedBuffer vertex_attributes_buffer_;
+
+ std::map<ShaderProgramKeyType, scoped_refptr<ShaderProgram>> shader_programs_;
+
+ friend class ShaderProgram;
+ friend class ScalerImpl;
+ friend class GLHelperTest;
+ DISALLOW_COPY_AND_ASSIGN(GLHelperScaling);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_GL_HELPER_SCALING_H_
diff --git a/chromium/content/browser/compositor/gl_helper_unittest.cc b/chromium/content/browser/compositor/gl_helper_unittest.cc
new file mode 100644
index 00000000000..697c68ba47a
--- /dev/null
+++ b/chromium/content/browser/compositor/gl_helper_unittest.cc
@@ -0,0 +1,1828 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/compositor/gl_helper.h"
+#include "content/browser/compositor/gl_helper_readback_support.h"
+#include "content/browser/compositor/gl_helper_scaling.h"
+#include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "media/base/video_frame.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkTypes.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace content {
+
+content::GLHelper::ScalerQuality kQualities[] = {
+ content::GLHelper::SCALER_QUALITY_BEST,
+ content::GLHelper::SCALER_QUALITY_GOOD,
+ content::GLHelper::SCALER_QUALITY_FAST,
+};
+
+const char* kQualityNames[] = {
+ "best", "good", "fast",
+};
+
+class GLHelperTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = 8;
+ attributes.depth_size = 24;
+ attributes.red_size = 8;
+ attributes.green_size = 8;
+ attributes.blue_size = 8;
+ attributes.stencil_size = 8;
+ attributes.samples = 4;
+ attributes.sample_buffers = 1;
+ attributes.bind_generates_resource = false;
+
+ context_.reset(gpu::GLInProcessContext::Create(
+ nullptr, /* service */
+ nullptr, /* surface */
+ true, /* offscreen */
+ gfx::kNullAcceleratedWidget, /* window */
+ gfx::Size(1, 1), /* size */
+ nullptr, /* share_context */
+ attributes, gfx::PreferDiscreteGpu,
+ ::gpu::GLInProcessContextSharedMemoryLimits(),
+ nullptr, /* gpu_memory_buffer_manager */
+ nullptr /* image_factory */));
+ gl_ = context_->GetImplementation();
+ gpu::ContextSupport* support = context_->GetImplementation();
+
+ helper_.reset(new content::GLHelper(gl_, support));
+ helper_scaling_.reset(new content::GLHelperScaling(gl_, helper_.get()));
+ }
+
+ void TearDown() override {
+ helper_scaling_.reset(NULL);
+ helper_.reset(NULL);
+ context_.reset(NULL);
+ }
+
+ void StartTracing(const std::string& filter) {
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceConfig(filter,
+ base::trace_event::RECORD_UNTIL_FULL),
+ base::trace_event::TraceLog::RECORDING_MODE);
+ }
+
+ static void TraceDataCB(
+ const base::Callback<void()>& callback,
+ std::string* output,
+ const scoped_refptr<base::RefCountedString>& json_events_str,
+ bool has_more_events) {
+ if (output->size() > 1 && !json_events_str->data().empty()) {
+ output->append(",");
+ }
+ output->append(json_events_str->data());
+ if (!has_more_events) {
+ callback.Run();
+ }
+ }
+
+ // End tracing, return tracing data in a simple map
+ // of event name->counts.
+ void EndTracing(std::map<std::string, int>* event_counts) {
+ std::string json_data = "[";
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ base::RunLoop run_loop;
+ base::trace_event::TraceLog::GetInstance()->Flush(
+ base::Bind(&GLHelperTest::TraceDataCB, run_loop.QuitClosure(),
+ base::Unretained(&json_data)));
+ run_loop.Run();
+ json_data.append("]");
+
+ std::string error_msg;
+ scoped_ptr<base::Value> trace_data =
+ base::JSONReader::ReadAndReturnError(json_data, 0, NULL, &error_msg);
+ CHECK(trace_data) << "JSON parsing failed (" << error_msg
+ << ") JSON data:" << std::endl
+ << json_data;
+
+ base::ListValue* list;
+ CHECK(trace_data->GetAsList(&list));
+ for (size_t i = 0; i < list->GetSize(); i++) {
+ base::Value* item = NULL;
+ if (list->Get(i, &item)) {
+ base::DictionaryValue* dict;
+ CHECK(item->GetAsDictionary(&dict));
+ std::string name;
+ CHECK(dict->GetString("name", &name));
+ std::string trace_type;
+ CHECK(dict->GetString("ph", &trace_type));
+ // Count all except END traces, as they come in BEGIN/END pairs.
+ if (trace_type != "E" && trace_type != "e")
+ (*event_counts)[name]++;
+ VLOG(1) << "trace name: " << name;
+ }
+ }
+ }
+
+ // Bicubic filter kernel function.
+ static float Bicubic(float x) {
+ const float a = -0.5;
+ x = std::abs(x);
+ float x2 = x * x;
+ float x3 = x2 * x;
+ if (x <= 1) {
+ return (a + 2) * x3 - (a + 3) * x2 + 1;
+ } else if (x < 2) {
+ return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a;
+ } else {
+ return 0.0f;
+ }
+ }
+
+ // Look up a single channel value. Works for 4-channel and single channel
+ // bitmaps. Clamp x/y.
+ int Channel(SkBitmap* pixels, int x, int y, int c) {
+ if (pixels->bytesPerPixel() == 4) {
+ uint32_t* data =
+ pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)),
+ std::max(0, std::min(y, pixels->height() - 1)));
+ return (*data) >> (c * 8) & 0xff;
+ } else {
+ DCHECK_EQ(pixels->bytesPerPixel(), 1);
+ DCHECK_EQ(c, 0);
+ return *pixels->getAddr8(std::max(0, std::min(x, pixels->width() - 1)),
+ std::max(0, std::min(y, pixels->height() - 1)));
+ }
+ }
+
+ // Set a single channel value. Works for 4-channel and single channel
+ // bitmaps. Clamp x/y.
+ void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) {
+ DCHECK_GE(x, 0);
+ DCHECK_GE(y, 0);
+ DCHECK_LT(x, pixels->width());
+ DCHECK_LT(y, pixels->height());
+ if (pixels->bytesPerPixel() == 4) {
+ uint32_t* data = pixels->getAddr32(x, y);
+ v = std::max(0, std::min(v, 255));
+ *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8));
+ } else {
+ DCHECK_EQ(pixels->bytesPerPixel(), 1);
+ DCHECK_EQ(c, 0);
+ uint8_t* data = pixels->getAddr8(x, y);
+ v = std::max(0, std::min(v, 255));
+ *data = v;
+ }
+ }
+
+ // Print all the R, G, B or A values from an SkBitmap in a
+ // human-readable format.
+ void PrintChannel(SkBitmap* pixels, int c) {
+ for (int y = 0; y < pixels->height(); y++) {
+ std::string formatted;
+ for (int x = 0; x < pixels->width(); x++) {
+ formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c)));
+ }
+ LOG(ERROR) << formatted;
+ }
+ }
+
+ // Print out the individual steps of a scaler pipeline.
+ std::string PrintStages(
+ const std::vector<GLHelperScaling::ScalerStage>& scaler_stages) {
+ std::string ret;
+ for (size_t i = 0; i < scaler_stages.size(); i++) {
+ ret.append(base::StringPrintf(
+ "%dx%d -> %dx%d ", scaler_stages[i].src_size.width(),
+ scaler_stages[i].src_size.height(), scaler_stages[i].dst_size.width(),
+ scaler_stages[i].dst_size.height()));
+ bool xy_matters = false;
+ switch (scaler_stages[i].shader) {
+ case GLHelperScaling::SHADER_BILINEAR:
+ ret.append("bilinear");
+ break;
+ case GLHelperScaling::SHADER_BILINEAR2:
+ ret.append("bilinear2");
+ xy_matters = true;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR3:
+ ret.append("bilinear3");
+ xy_matters = true;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR4:
+ ret.append("bilinear4");
+ xy_matters = true;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR2X2:
+ ret.append("bilinear2x2");
+ break;
+ case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
+ ret.append("bicubic upscale");
+ xy_matters = true;
+ break;
+ case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
+ ret.append("bicubic 1/2");
+ xy_matters = true;
+ break;
+ case GLHelperScaling::SHADER_PLANAR:
+ ret.append("planar");
+ break;
+ case GLHelperScaling::SHADER_YUV_MRT_PASS1:
+ ret.append("rgb2yuv pass 1");
+ break;
+ case GLHelperScaling::SHADER_YUV_MRT_PASS2:
+ ret.append("rgb2yuv pass 2");
+ break;
+ }
+
+ if (xy_matters) {
+ if (scaler_stages[i].scale_x) {
+ ret.append(" X");
+ } else {
+ ret.append(" Y");
+ }
+ }
+ ret.append("\n");
+ }
+ return ret;
+ }
+
+ bool CheckScale(double scale, int samples, bool already_scaled) {
+ // 1:1 is valid if there is one sample.
+ if (samples == 1 && scale == 1.0) {
+ return true;
+ }
+ // Is it an exact down-scale (50%, 25%, etc.?)
+ if (scale == 2.0 * samples) {
+ return true;
+ }
+ // Upscales, only valid if we haven't already scaled in this dimension.
+ if (!already_scaled) {
+ // Is it a valid bilinear upscale?
+ if (samples == 1 && scale <= 1.0) {
+ return true;
+ }
+ // Multi-sample upscale-downscale combination?
+ if (scale > samples / 2.0 && scale < samples) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Make sure that the stages of the scaler pipeline are sane.
+ void ValidateScalerStages(
+ content::GLHelper::ScalerQuality quality,
+ const std::vector<GLHelperScaling::ScalerStage>& scaler_stages,
+ const gfx::Size& dst_size,
+ const std::string& message) {
+ bool previous_error = HasFailure();
+ // First, check that the input size for each stage is equal to
+ // the output size of the previous stage.
+ for (size_t i = 1; i < scaler_stages.size(); i++) {
+ EXPECT_EQ(scaler_stages[i - 1].dst_size.width(),
+ scaler_stages[i].src_size.width());
+ EXPECT_EQ(scaler_stages[i - 1].dst_size.height(),
+ scaler_stages[i].src_size.height());
+ EXPECT_EQ(scaler_stages[i].src_subrect.x(), 0);
+ EXPECT_EQ(scaler_stages[i].src_subrect.y(), 0);
+ EXPECT_EQ(scaler_stages[i].src_subrect.width(),
+ scaler_stages[i].src_size.width());
+ EXPECT_EQ(scaler_stages[i].src_subrect.height(),
+ scaler_stages[i].src_size.height());
+ }
+
+ // Check the output size matches the destination of the last stage
+ EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.width(),
+ dst_size.width());
+ EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.height(),
+ dst_size.height());
+
+ // Used to verify that up-scales are not attempted after some
+ // other scale.
+ bool scaled_x = false;
+ bool scaled_y = false;
+
+ for (size_t i = 0; i < scaler_stages.size(); i++) {
+ // Note: 2.0 means scaling down by 50%
+ double x_scale =
+ static_cast<double>(scaler_stages[i].src_subrect.width()) /
+ static_cast<double>(scaler_stages[i].dst_size.width());
+ double y_scale =
+ static_cast<double>(scaler_stages[i].src_subrect.height()) /
+ static_cast<double>(scaler_stages[i].dst_size.height());
+
+ int x_samples = 0;
+ int y_samples = 0;
+
+ // Codify valid scale operations.
+ switch (scaler_stages[i].shader) {
+ case GLHelperScaling::SHADER_PLANAR:
+ case GLHelperScaling::SHADER_YUV_MRT_PASS1:
+ case GLHelperScaling::SHADER_YUV_MRT_PASS2:
+ EXPECT_TRUE(false) << "Invalid shader.";
+ break;
+
+ case GLHelperScaling::SHADER_BILINEAR:
+ if (quality != content::GLHelper::SCALER_QUALITY_FAST) {
+ x_samples = 1;
+ y_samples = 1;
+ }
+ break;
+ case GLHelperScaling::SHADER_BILINEAR2:
+ x_samples = 2;
+ y_samples = 1;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR3:
+ x_samples = 3;
+ y_samples = 1;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR4:
+ x_samples = 4;
+ y_samples = 1;
+ break;
+ case GLHelperScaling::SHADER_BILINEAR2X2:
+ x_samples = 2;
+ y_samples = 2;
+ break;
+ case GLHelperScaling::SHADER_BICUBIC_UPSCALE:
+ if (scaler_stages[i].scale_x) {
+ EXPECT_LT(x_scale, 1.0);
+ EXPECT_EQ(y_scale, 1.0);
+ } else {
+ EXPECT_EQ(x_scale, 1.0);
+ EXPECT_LT(y_scale, 1.0);
+ }
+ break;
+ case GLHelperScaling::SHADER_BICUBIC_HALF_1D:
+ if (scaler_stages[i].scale_x) {
+ EXPECT_EQ(x_scale, 2.0);
+ EXPECT_EQ(y_scale, 1.0);
+ } else {
+ EXPECT_EQ(x_scale, 1.0);
+ EXPECT_EQ(y_scale, 2.0);
+ }
+ break;
+ }
+
+ if (!scaler_stages[i].scale_x) {
+ std::swap(x_samples, y_samples);
+ }
+
+ if (x_samples) {
+ EXPECT_TRUE(CheckScale(x_scale, x_samples, scaled_x)) << "x_scale = "
+ << x_scale;
+ }
+ if (y_samples) {
+ EXPECT_TRUE(CheckScale(y_scale, y_samples, scaled_y)) << "y_scale = "
+ << y_scale;
+ }
+
+ if (x_scale != 1.0) {
+ scaled_x = true;
+ }
+ if (y_scale != 1.0) {
+ scaled_y = true;
+ }
+ }
+
+ if (HasFailure() && !previous_error) {
+ LOG(ERROR) << "Invalid scaler stages: " << message;
+ LOG(ERROR) << "Scaler stages:";
+ LOG(ERROR) << PrintStages(scaler_stages);
+ }
+ }
+
+ // Compares two bitmaps taking color types into account. Checks whether each
+ // component of each pixel is no more than |maxdiff| apart. If bitmaps are not
+ // similar enough, prints out |truth|, |other|, |source|, |scaler_stages|
+ // and |message|.
+ void Compare(SkBitmap* truth,
+ SkBitmap* other,
+ int maxdiff,
+ SkBitmap* source,
+ const std::vector<GLHelperScaling::ScalerStage>& scaler_stages,
+ std::string message) {
+ EXPECT_EQ(truth->width(), other->width());
+ EXPECT_EQ(truth->height(), other->height());
+ bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType &&
+ other->colorType() == kBGRA_8888_SkColorType) ||
+ (truth->colorType() == kBGRA_8888_SkColorType &&
+ other->colorType() == kRGBA_8888_SkColorType);
+ EXPECT_TRUE(swizzle || truth->colorType() == other->colorType());
+ int bpp = truth->bytesPerPixel();
+ for (int x = 0; x < truth->width(); x++) {
+ for (int y = 0; y < truth->height(); y++) {
+ for (int c = 0; c < bpp; c++) {
+ int a = Channel(truth, x, y, c);
+ // swizzle when comparing if needed
+ int b = swizzle && (c == 0 || c == 2)
+ ? Channel(other, x, y, (c + 2) & 2)
+ : Channel(other, x, y, c);
+ EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c
+ << " " << message;
+ if (std::abs(a - b) > maxdiff) {
+ LOG(ERROR) << "-------expected--------";
+ for (int i = 0; i < bpp; i++) {
+ LOG(ERROR) << "Channel " << i << ":";
+ PrintChannel(truth, i);
+ }
+ LOG(ERROR) << "-------actual--------";
+ for (int i = 0; i < bpp; i++) {
+ LOG(ERROR) << "Channel " << i << ":";
+ PrintChannel(other, i);
+ }
+ if (source) {
+ LOG(ERROR) << "-------original--------";
+ for (int i = 0; i < source->bytesPerPixel(); i++) {
+ LOG(ERROR) << "Channel " << i << ":";
+ PrintChannel(source, i);
+ }
+ }
+ LOG(ERROR) << "-----Scaler stages------";
+ LOG(ERROR) << PrintStages(scaler_stages);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // Get a single R, G, B or A value as a float.
+ float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) {
+ return Channel(pixels, x, y, c) / 255.0;
+ }
+
+ // Works like a GL_LINEAR lookup on an SkBitmap.
+ float Bilinear(SkBitmap* pixels, float x, float y, int c) {
+ x -= 0.5;
+ y -= 0.5;
+ int base_x = static_cast<int>(floorf(x));
+ int base_y = static_cast<int>(floorf(y));
+ x -= base_x;
+ y -= base_y;
+ return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) +
+ ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) +
+ ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y +
+ ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y);
+ }
+
+ // Encodes an RGBA bitmap to grayscale.
+ // Reference implementation for
+ // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale.
+ void EncodeToGrayscaleSlow(SkBitmap* input, SkBitmap* output) {
+ const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f};
+ CHECK_EQ(kAlpha_8_SkColorType, output->colorType());
+ CHECK_EQ(input->width(), output->width());
+ CHECK_EQ(input->height(), output->height());
+ CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType);
+
+ for (int dst_y = 0; dst_y < output->height(); dst_y++) {
+ for (int dst_x = 0; dst_x < output->width(); dst_x++) {
+ float c0 = ChannelAsFloat(input, dst_x, dst_y, 0);
+ float c1 = ChannelAsFloat(input, dst_x, dst_y, 1);
+ float c2 = ChannelAsFloat(input, dst_x, dst_y, 2);
+ float value = c0 * kRGBtoGrayscaleColorWeights[0] +
+ c1 * kRGBtoGrayscaleColorWeights[1] +
+ c2 * kRGBtoGrayscaleColorWeights[2];
+ SetChannel(output, dst_x, dst_y, 0,
+ static_cast<int>(value * 255.0f + 0.5f));
+ }
+ }
+ }
+
+ // Very slow bicubic / bilinear scaler for reference.
+ void ScaleSlow(SkBitmap* input,
+ SkBitmap* output,
+ content::GLHelper::ScalerQuality quality) {
+ float xscale = static_cast<float>(input->width()) / output->width();
+ float yscale = static_cast<float>(input->height()) / output->height();
+ float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale;
+ float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale;
+ for (int dst_y = 0; dst_y < output->height(); dst_y++) {
+ for (int dst_x = 0; dst_x < output->width(); dst_x++) {
+ for (int channel = 0; channel < 4; channel++) {
+ float dst_x_in_src = (dst_x + 0.5f) * xscale;
+ float dst_y_in_src = (dst_y + 0.5f) * yscale;
+
+ float value = 0.0f;
+ float sum = 0.0f;
+ switch (quality) {
+ case content::GLHelper::SCALER_QUALITY_BEST:
+ for (int src_y = -10; src_y < input->height() + 10; ++src_y) {
+ float coeff_y =
+ Bicubic((src_y + 0.5f - dst_y_in_src) * clamped_yscale);
+ if (coeff_y == 0.0f) {
+ continue;
+ }
+ for (int src_x = -10; src_x < input->width() + 10; ++src_x) {
+ float coeff =
+ coeff_y *
+ Bicubic((src_x + 0.5f - dst_x_in_src) * clamped_xscale);
+ if (coeff == 0.0f) {
+ continue;
+ }
+ sum += coeff;
+ float c = ChannelAsFloat(input, src_x, src_y, channel);
+ value += c * coeff;
+ }
+ }
+ break;
+
+ case content::GLHelper::SCALER_QUALITY_GOOD: {
+ int xshift = 0, yshift = 0;
+ while ((output->width() << xshift) < input->width()) {
+ xshift++;
+ }
+ while ((output->height() << yshift) < input->height()) {
+ yshift++;
+ }
+ int xmag = 1 << xshift;
+ int ymag = 1 << yshift;
+ if (xmag == 4 && output->width() * 3 >= input->width()) {
+ xmag = 3;
+ }
+ if (ymag == 4 && output->height() * 3 >= input->height()) {
+ ymag = 3;
+ }
+ for (int x = 0; x < xmag; x++) {
+ for (int y = 0; y < ymag; y++) {
+ value += Bilinear(
+ input, (dst_x * xmag + x + 0.5) * xscale / xmag,
+ (dst_y * ymag + y + 0.5) * yscale / ymag, channel);
+ sum += 1.0;
+ }
+ }
+ break;
+ }
+
+ case content::GLHelper::SCALER_QUALITY_FAST:
+ value = Bilinear(input, dst_x_in_src, dst_y_in_src, channel);
+ sum = 1.0;
+ }
+ value /= sum;
+ SetChannel(output, dst_x, dst_y, channel,
+ static_cast<int>(value * 255.0f + 0.5f));
+ }
+ }
+ }
+ }
+
+ void FlipSKBitmap(SkBitmap* bitmap) {
+ int bpp = bitmap->bytesPerPixel();
+ DCHECK(bpp == 4 || bpp == 1);
+ int top_line = 0;
+ int bottom_line = bitmap->height() - 1;
+ while (top_line < bottom_line) {
+ for (int x = 0; x < bitmap->width(); x++) {
+ bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line),
+ *bitmap->getAddr32(x, bottom_line))
+ : std::swap(*bitmap->getAddr8(x, top_line),
+ *bitmap->getAddr8(x, bottom_line));
+ }
+ top_line++;
+ bottom_line--;
+ }
+ }
+
+ // Swaps red and blue channels in each pixel in a 32-bit bitmap.
+ void SwizzleSKBitmap(SkBitmap* bitmap) {
+ int bpp = bitmap->bytesPerPixel();
+ DCHECK(bpp == 4);
+ for (int y = 0; y < bitmap->height(); y++) {
+ for (int x = 0; x < bitmap->width(); x++) {
+ // Swap channels 0 and 2 (red and blue)
+ int c0 = Channel(bitmap, x, y, 0);
+ int c2 = Channel(bitmap, x, y, 2);
+ SetChannel(bitmap, x, y, 2, c0);
+ SetChannel(bitmap, x, y, 0, c2);
+ }
+ }
+ }
+
+ // gl_helper scales recursively, so we'll need to do that
+ // in the reference implementation too.
+ void ScaleSlowRecursive(SkBitmap* input,
+ SkBitmap* output,
+ content::GLHelper::ScalerQuality quality) {
+ if (quality == content::GLHelper::SCALER_QUALITY_FAST ||
+ quality == content::GLHelper::SCALER_QUALITY_GOOD) {
+ ScaleSlow(input, output, quality);
+ return;
+ }
+
+ float xscale = static_cast<float>(output->width()) / input->width();
+
+ // This corresponds to all the operations we can do directly.
+ float yscale = static_cast<float>(output->height()) / input->height();
+ if ((xscale == 1.0f && yscale == 1.0f) ||
+ (xscale == 0.5f && yscale == 1.0f) ||
+ (xscale == 1.0f && yscale == 0.5f) ||
+ (xscale >= 1.0f && yscale == 1.0f) ||
+ (xscale == 1.0f && yscale >= 1.0f)) {
+ ScaleSlow(input, output, quality);
+ return;
+ }
+
+ // Now we break the problem down into smaller pieces, using the
+ // operations available.
+ int xtmp = input->width();
+ int ytmp = input->height();
+
+ if (output->height() != input->height()) {
+ ytmp = output->height();
+ while (ytmp < input->height() && ytmp * 2 != input->height()) {
+ ytmp += ytmp;
+ }
+ } else {
+ xtmp = output->width();
+ while (xtmp < input->width() && xtmp * 2 != input->width()) {
+ xtmp += xtmp;
+ }
+ }
+
+ SkBitmap tmp;
+ tmp.allocN32Pixels(xtmp, ytmp);
+
+ ScaleSlowRecursive(input, &tmp, quality);
+ ScaleSlowRecursive(&tmp, output, quality);
+ }
+
+ // Creates an RGBA SkBitmap
+ scoped_ptr<SkBitmap> CreateTestBitmap(int width,
+ int height,
+ int test_pattern) {
+ scoped_ptr<SkBitmap> bitmap(new SkBitmap);
+ bitmap->allocPixels(SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType));
+
+ for (int x = 0; x < width; ++x) {
+ for (int y = 0; y < height; ++y) {
+ switch (test_pattern) {
+ case 0: // Smooth test pattern
+ SetChannel(bitmap.get(), x, y, 0, x * 10);
+ SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10);
+ SetChannel(bitmap.get(), x, y, 1, y * 10);
+ SetChannel(bitmap.get(), x, y, 2, (x + y) * 10);
+ SetChannel(bitmap.get(), x, y, 3, 255);
+ break;
+ case 1: // Small blocks
+ SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0);
+ SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0);
+ SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0);
+ SetChannel(bitmap.get(), x, y, 3, 255);
+ break;
+ case 2: // Medium blocks
+ SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50);
+ SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50);
+ SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5);
+ SetChannel(bitmap.get(), x, y, 3, 255);
+ break;
+ }
+ }
+ }
+ return bitmap;
+ }
+
+ // Binds texture and framebuffer and loads the bitmap pixels into the texture.
+ void BindTextureAndFrameBuffer(GLuint texture,
+ GLuint framebuffer,
+ SkBitmap* bitmap,
+ int width,
+ int height) {
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ gl_->BindTexture(GL_TEXTURE_2D, texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, bitmap->getPixels());
+ }
+
+ // Create a test image, transform it using
+ // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation
+ // and compare the results.
+ void TestCropScaleReadbackAndCleanTexture(int xsize,
+ int ysize,
+ int scaled_xsize,
+ int scaled_ysize,
+ int test_pattern,
+ SkColorType out_color_type,
+ bool swizzle,
+ size_t quality_index) {
+ DCHECK(out_color_type == kAlpha_8_SkColorType ||
+ out_color_type == kRGBA_8888_SkColorType ||
+ out_color_type == kBGRA_8888_SkColorType);
+ GLuint src_texture;
+ gl_->GenTextures(1, &src_texture);
+ GLuint framebuffer;
+ gl_->GenFramebuffers(1, &framebuffer);
+ scoped_ptr<SkBitmap> input_pixels =
+ CreateTestBitmap(xsize, ysize, test_pattern);
+ BindTextureAndFrameBuffer(src_texture, framebuffer, input_pixels.get(),
+ xsize, ysize);
+
+ std::string message = base::StringPrintf(
+ "input size: %dx%d "
+ "output size: %dx%d "
+ "pattern: %d , quality: %s, "
+ "out_color_type: %d",
+ xsize, ysize, scaled_xsize, scaled_ysize, test_pattern,
+ kQualityNames[quality_index], out_color_type);
+
+ // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture.
+ SkBitmap output_pixels;
+ output_pixels.allocPixels(SkImageInfo::Make(
+ scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType));
+ base::RunLoop run_loop;
+ gfx::Size encoded_texture_size;
+ helper_->CropScaleReadbackAndCleanTexture(
+ src_texture, gfx::Size(xsize, ysize), gfx::Rect(xsize, ysize),
+ gfx::Size(scaled_xsize, scaled_ysize),
+ static_cast<unsigned char*>(output_pixels.getPixels()), out_color_type,
+ base::Bind(&callcallback, run_loop.QuitClosure()),
+ kQualities[quality_index]);
+ run_loop.Run();
+ // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back.
+ FlipSKBitmap(&output_pixels);
+
+ // If the bitmap shouldn't have changed - compare against input.
+ if (xsize == scaled_xsize && ysize == scaled_ysize &&
+ out_color_type != kAlpha_8_SkColorType) {
+ const std::vector<GLHelperScaling::ScalerStage> dummy_stages;
+ Compare(input_pixels.get(), &output_pixels, 0, NULL, dummy_stages,
+ message + " comparing against input");
+ return;
+ }
+
+ // Now transform the bitmap using the reference implementation.
+ SkBitmap scaled_pixels;
+ scaled_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, scaled_ysize,
+ kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType));
+ SkBitmap truth_pixels;
+ // Step 1: Scale
+ ScaleSlowRecursive(input_pixels.get(), &scaled_pixels,
+ kQualities[quality_index]);
+ // Step 2: Encode to grayscale if needed.
+ if (out_color_type == kAlpha_8_SkColorType) {
+ truth_pixels.allocPixels(SkImageInfo::Make(
+ scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType));
+ EncodeToGrayscaleSlow(&scaled_pixels, &truth_pixels);
+ } else {
+ truth_pixels = scaled_pixels;
+ }
+
+ // Now compare the results.
+ SkAutoLockPixels lock_input(truth_pixels);
+ const std::vector<GLHelperScaling::ScalerStage> dummy_stages;
+ Compare(&truth_pixels, &output_pixels, 2, input_pixels.get(), dummy_stages,
+ message + " comparing against transformed/scaled");
+
+ gl_->DeleteTextures(1, &src_texture);
+ gl_->DeleteFramebuffers(1, &framebuffer);
+ }
+
+ // Scaling test: Create a test image, scale it using GLHelperScaling
+ // and a reference implementation and compare the results.
+ void TestScale(int xsize,
+ int ysize,
+ int scaled_xsize,
+ int scaled_ysize,
+ int test_pattern,
+ size_t quality_index,
+ bool flip) {
+ GLuint src_texture;
+ gl_->GenTextures(1, &src_texture);
+ GLuint framebuffer;
+ gl_->GenFramebuffers(1, &framebuffer);
+ scoped_ptr<SkBitmap> input_pixels =
+ CreateTestBitmap(xsize, ysize, test_pattern);
+ BindTextureAndFrameBuffer(src_texture, framebuffer, input_pixels.get(),
+ xsize, ysize);
+
+ std::string message = base::StringPrintf(
+ "input size: %dx%d "
+ "output size: %dx%d "
+ "pattern: %d quality: %s",
+ xsize, ysize, scaled_xsize, scaled_ysize, test_pattern,
+ kQualityNames[quality_index]);
+
+ std::vector<GLHelperScaling::ScalerStage> stages;
+ helper_scaling_->ComputeScalerStages(kQualities[quality_index],
+ gfx::Size(xsize, ysize),
+ gfx::Rect(0, 0, xsize, ysize),
+ gfx::Size(scaled_xsize, scaled_ysize),
+ flip,
+ false,
+ &stages);
+ ValidateScalerStages(kQualities[quality_index],
+ stages,
+ gfx::Size(scaled_xsize, scaled_ysize),
+ message);
+
+ GLuint dst_texture = helper_->CopyAndScaleTexture(
+ src_texture, gfx::Size(xsize, ysize),
+ gfx::Size(scaled_xsize, scaled_ysize), flip, kQualities[quality_index]);
+
+ SkBitmap output_pixels;
+ output_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, scaled_ysize,
+ kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType));
+
+ helper_->ReadbackTextureSync(
+ dst_texture, gfx::Rect(0, 0, scaled_xsize, scaled_ysize),
+ static_cast<unsigned char*>(output_pixels.getPixels()),
+ kRGBA_8888_SkColorType);
+ if (flip) {
+ // Flip the pixels back.
+ FlipSKBitmap(&output_pixels);
+ }
+
+ // If the bitmap shouldn't have changed - compare against input.
+ if (xsize == scaled_xsize && ysize == scaled_ysize) {
+ Compare(input_pixels.get(), &output_pixels, 0, NULL, stages,
+ message + " comparing against input");
+ return;
+ }
+
+ // Now scale the bitmap using the reference implementation.
+ SkBitmap truth_pixels;
+ truth_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, scaled_ysize,
+ kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType));
+ ScaleSlowRecursive(input_pixels.get(), &truth_pixels,
+ kQualities[quality_index]);
+ Compare(&truth_pixels, &output_pixels, 2, input_pixels.get(), stages,
+ message + " comparing against scaled");
+
+ gl_->DeleteTextures(1, &src_texture);
+ gl_->DeleteTextures(1, &dst_texture);
+ gl_->DeleteFramebuffers(1, &framebuffer);
+ }
+
+ // Create a scaling pipeline and check that it is made up of
+ // valid scaling operations.
+ void TestScalerPipeline(size_t quality,
+ int xsize,
+ int ysize,
+ int dst_xsize,
+ int dst_ysize) {
+ std::vector<GLHelperScaling::ScalerStage> stages;
+ helper_scaling_->ComputeScalerStages(
+ kQualities[quality], gfx::Size(xsize, ysize),
+ gfx::Rect(0, 0, xsize, ysize), gfx::Size(dst_xsize, dst_ysize), false,
+ false, &stages);
+ ValidateScalerStages(kQualities[quality], stages,
+ gfx::Size(dst_xsize, dst_ysize),
+ base::StringPrintf("input size: %dx%d "
+ "output size: %dx%d "
+ "quality: %s",
+ xsize, ysize, dst_xsize, dst_ysize,
+ kQualityNames[quality]));
+ }
+
+ // Create a scaling pipeline and make sure that the steps
+ // are exactly the steps we expect.
+ void CheckPipeline(content::GLHelper::ScalerQuality quality,
+ int xsize,
+ int ysize,
+ int dst_xsize,
+ int dst_ysize,
+ const std::string& description) {
+ std::vector<GLHelperScaling::ScalerStage> stages;
+ helper_scaling_->ComputeScalerStages(
+ quality, gfx::Size(xsize, ysize), gfx::Rect(0, 0, xsize, ysize),
+ gfx::Size(dst_xsize, dst_ysize), false, false, &stages);
+ ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, stages,
+ gfx::Size(dst_xsize, dst_ysize), "");
+ EXPECT_EQ(PrintStages(stages), description);
+ }
+
+ // Note: Left/Right means Top/Bottom when used for Y dimension.
+ enum Margin {
+ MarginLeft,
+ MarginMiddle,
+ MarginRight,
+ MarginInvalid,
+ };
+
+ static Margin NextMargin(Margin m) {
+ switch (m) {
+ case MarginLeft:
+ return MarginMiddle;
+ case MarginMiddle:
+ return MarginRight;
+ case MarginRight:
+ return MarginInvalid;
+ default:
+ return MarginInvalid;
+ }
+ }
+
+ int compute_margin(int insize, int outsize, Margin m) {
+ int available = outsize - insize;
+ switch (m) {
+ default:
+ EXPECT_TRUE(false) << "This should not happen.";
+ return 0;
+ case MarginLeft:
+ return 0;
+ case MarginMiddle:
+ return (available / 2) & ~1;
+ case MarginRight:
+ return available;
+ }
+ }
+
+ // Convert 0.0 - 1.0 to 0 - 255
+ int float_to_byte(float v) {
+ int ret = static_cast<int>(floorf(v * 255.0f + 0.5f));
+ if (ret < 0) {
+ return 0;
+ }
+ if (ret > 255) {
+ return 255;
+ }
+ return ret;
+ }
+
+ static void callcallback(const base::Callback<void()>& callback,
+ bool result) {
+ callback.Run();
+ }
+
+ void PrintPlane(unsigned char* plane, int xsize, int stride, int ysize) {
+ for (int y = 0; y < ysize; y++) {
+ std::string formatted;
+ for (int x = 0; x < xsize; x++) {
+ formatted.append(base::StringPrintf("%3d, ", plane[y * stride + x]));
+ }
+ LOG(ERROR) << formatted << " (" << (plane + y * stride) << ")";
+ }
+ }
+
+ // Compare two planes make sure that each component of each pixel
+ // is no more than |maxdiff| apart.
+ void ComparePlane(unsigned char* truth,
+ int truth_stride,
+ unsigned char* other,
+ int other_stride,
+ int maxdiff,
+ int xsize,
+ int ysize,
+ SkBitmap* source,
+ std::string message) {
+ for (int x = 0; x < xsize; x++) {
+ for (int y = 0; y < ysize; y++) {
+ int a = other[y * other_stride + x];
+ int b = truth[y * truth_stride + x];
+ EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " "
+ << message;
+ if (std::abs(a - b) > maxdiff) {
+ LOG(ERROR) << "-------expected--------";
+ PrintPlane(truth, xsize, truth_stride, ysize);
+ LOG(ERROR) << "-------actual--------";
+ PrintPlane(other, xsize, other_stride, ysize);
+ if (source) {
+ LOG(ERROR) << "-------before yuv conversion: red--------";
+ PrintChannel(source, 0);
+ LOG(ERROR) << "-------before yuv conversion: green------";
+ PrintChannel(source, 1);
+ LOG(ERROR) << "-------before yuv conversion: blue-------";
+ PrintChannel(source, 2);
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ void DrawGridToBitmap(int w,
+ int h,
+ SkColor background_color,
+ SkColor grid_color,
+ int grid_pitch,
+ int grid_width,
+ SkBitmap& bmp) {
+ ASSERT_GT(grid_pitch, 0);
+ ASSERT_GT(grid_width, 0);
+ ASSERT_NE(background_color, grid_color);
+
+ for (int y = 0; y < h; ++y) {
+ bool y_on_grid = ((y % grid_pitch) < grid_width);
+
+ for (int x = 0; x < w; ++x) {
+ bool on_grid = (y_on_grid || ((x % grid_pitch) < grid_width));
+
+ if (bmp.colorType() == kRGBA_8888_SkColorType ||
+ bmp.colorType() == kBGRA_8888_SkColorType) {
+ *bmp.getAddr32(x, y) = (on_grid ? grid_color : background_color);
+ } else if (bmp.colorType() == kRGB_565_SkColorType) {
+ *bmp.getAddr16(x, y) = (on_grid ? grid_color : background_color);
+ }
+ }
+ }
+ }
+
+ void DrawCheckerToBitmap(int w,
+ int h,
+ SkColor color1,
+ SkColor color2,
+ int rect_w,
+ int rect_h,
+ SkBitmap& bmp) {
+ ASSERT_GT(rect_w, 0);
+ ASSERT_GT(rect_h, 0);
+ ASSERT_NE(color1, color2);
+
+ for (int y = 0; y < h; ++y) {
+ bool y_bit = (((y / rect_h) & 0x1) == 0);
+
+ for (int x = 0; x < w; ++x) {
+ bool x_bit = (((x / rect_w) & 0x1) == 0);
+
+ bool use_color2 = (x_bit != y_bit); // xor
+ if (bmp.colorType() == kRGBA_8888_SkColorType ||
+ bmp.colorType() == kBGRA_8888_SkColorType) {
+ *bmp.getAddr32(x, y) = (use_color2 ? color2 : color1);
+ } else if (bmp.colorType() == kRGB_565_SkColorType) {
+ *bmp.getAddr16(x, y) = (use_color2 ? color2 : color1);
+ }
+ }
+ }
+ }
+
+ bool ColorComponentsClose(SkColor component1,
+ SkColor component2,
+ SkColorType color_type) {
+ int c1 = static_cast<int>(component1);
+ int c2 = static_cast<int>(component2);
+ bool result = false;
+ switch (color_type) {
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType:
+ result = (std::abs(c1 - c2) == 0);
+ break;
+ case kRGB_565_SkColorType:
+ result = (std::abs(c1 - c2) <= 7);
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ bool ColorsClose(SkColor color1, SkColor color2, SkColorType color_type) {
+ bool red = ColorComponentsClose(SkColorGetR(color1), SkColorGetR(color2),
+ color_type);
+ bool green = ColorComponentsClose(SkColorGetG(color1), SkColorGetG(color2),
+ color_type);
+ bool blue = ColorComponentsClose(SkColorGetB(color1), SkColorGetB(color2),
+ color_type);
+ bool alpha = ColorComponentsClose(SkColorGetA(color1), SkColorGetA(color2),
+ color_type);
+ if (color_type == kRGB_565_SkColorType) {
+ return red && blue && green;
+ }
+ return red && blue && green && alpha;
+ }
+
+ bool IsEqual(const SkBitmap& bmp1, const SkBitmap& bmp2) {
+ if (bmp1.isNull() && bmp2.isNull())
+ return true;
+ if (bmp1.width() != bmp2.width() || bmp1.height() != bmp2.height()) {
+ LOG(ERROR) << "Bitmap geometry check failure";
+ return false;
+ }
+ if (bmp1.colorType() != bmp2.colorType())
+ return false;
+
+ SkAutoLockPixels lock1(bmp1);
+ SkAutoLockPixels lock2(bmp2);
+ if (!bmp1.getPixels() || !bmp2.getPixels()) {
+ LOG(ERROR) << "Empty Bitmap!";
+ return false;
+ }
+ for (int y = 0; y < bmp1.height(); ++y) {
+ for (int x = 0; x < bmp1.width(); ++x) {
+ if (!ColorsClose(bmp1.getColor(x, y), bmp2.getColor(x, y),
+ bmp1.colorType())) {
+ LOG(ERROR) << "Bitmap color comparision failure";
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ void BindAndAttachTextureWithPixels(GLuint src_texture,
+ SkColorType color_type,
+ const gfx::Size& src_size,
+ const SkBitmap& input_pixels) {
+ gl_->BindTexture(GL_TEXTURE_2D, src_texture);
+ GLenum format = 0;
+ switch (color_type) {
+ case kBGRA_8888_SkColorType:
+ format = GL_BGRA_EXT;
+ break;
+ case kRGBA_8888_SkColorType:
+ format = GL_RGBA;
+ break;
+ case kRGB_565_SkColorType:
+ format = GL_RGB;
+ break;
+ default:
+ NOTREACHED();
+ }
+ GLenum type = (color_type == kRGB_565_SkColorType) ?
+ GL_UNSIGNED_SHORT_5_6_5 : GL_UNSIGNED_BYTE;
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, format, src_size.width(),
+ src_size.height(), 0, format, type,
+ input_pixels.getPixels());
+ }
+
+ void ReadBackTexture(GLuint src_texture,
+ const gfx::Size& src_size,
+ unsigned char* pixels,
+ SkColorType color_type,
+ bool async) {
+ if (async) {
+ base::RunLoop run_loop;
+ helper_->ReadbackTextureAsync(
+ src_texture, src_size, pixels, color_type,
+ base::Bind(&callcallback, run_loop.QuitClosure()));
+ run_loop.Run();
+ } else {
+ helper_->ReadbackTextureSync(src_texture, gfx::Rect(src_size), pixels,
+ color_type);
+ }
+ }
+ // Test basic format readback.
+ bool TestTextureFormatReadback(const gfx::Size& src_size,
+ SkColorType color_type,
+ bool async) {
+ SkImageInfo info = SkImageInfo::Make(src_size.width(), src_size.height(),
+ color_type, kPremul_SkAlphaType);
+ if (!helper_->IsReadbackConfigSupported(color_type)) {
+ LOG(INFO) << "Skipping test format not supported" << color_type;
+ return true;
+ }
+ GLuint src_texture;
+ gl_->GenTextures(1, &src_texture);
+ SkBitmap input_pixels;
+ input_pixels.allocPixels(info);
+ // Test Pattern-1, Fill with Plain color pattern.
+ // Erase the input bitmap with red color.
+ input_pixels.eraseColor(SK_ColorRED);
+ BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
+ input_pixels);
+ SkBitmap output_pixels;
+ output_pixels.allocPixels(info);
+ // Initialize the output bitmap with Green color.
+ // When the readback is over output bitmap should have the red color.
+ output_pixels.eraseColor(SK_ColorGREEN);
+ uint8_t* pixels = static_cast<uint8_t*>(output_pixels.getPixels());
+ ReadBackTexture(src_texture, src_size, pixels, color_type, async);
+ bool result = IsEqual(input_pixels, output_pixels);
+ if (!result) {
+ LOG(ERROR) << "Bitmap comparision failure Pattern-1";
+ return false;
+ }
+ const int rect_w = 10, rect_h = 4, src_grid_pitch = 10, src_grid_width = 4;
+ const SkColor color1 = SK_ColorRED, color2 = SK_ColorBLUE;
+ // Test Pattern-2, Fill with Grid Pattern.
+ DrawGridToBitmap(src_size.width(), src_size.height(), color2, color1,
+ src_grid_pitch, src_grid_width, input_pixels);
+ BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
+ input_pixels);
+ ReadBackTexture(src_texture, src_size, pixels, color_type, async);
+ result = IsEqual(input_pixels, output_pixels);
+ if (!result) {
+ LOG(ERROR) << "Bitmap comparision failure Pattern-2";
+ return false;
+ }
+ // Test Pattern-3, Fill with CheckerBoard Pattern.
+ DrawCheckerToBitmap(src_size.width(), src_size.height(), color1, color2,
+ rect_w, rect_h, input_pixels);
+ BindAndAttachTextureWithPixels(src_texture, color_type, src_size,
+ input_pixels);
+ ReadBackTexture(src_texture, src_size, pixels, color_type, async);
+ result = IsEqual(input_pixels, output_pixels);
+ if (!result) {
+ LOG(ERROR) << "Bitmap comparision failure Pattern-3";
+ return false;
+ }
+ gl_->DeleteTextures(1, &src_texture);
+ if (HasFailure()) {
+ return false;
+ }
+ return true;
+ }
+
+ // YUV readback test. Create a test pattern, convert to YUV
+ // with reference implementation and compare to what gl_helper
+ // returns.
+ void TestYUVReadback(int xsize,
+ int ysize,
+ int output_xsize,
+ int output_ysize,
+ int xmargin,
+ int ymargin,
+ int test_pattern,
+ bool flip,
+ bool use_mrt,
+ content::GLHelper::ScalerQuality quality) {
+ GLuint src_texture;
+ gl_->GenTextures(1, &src_texture);
+ SkBitmap input_pixels;
+ input_pixels.allocN32Pixels(xsize, ysize);
+
+ for (int x = 0; x < xsize; ++x) {
+ for (int y = 0; y < ysize; ++y) {
+ switch (test_pattern) {
+ case 0: // Smooth test pattern
+ SetChannel(&input_pixels, x, y, 0, x * 10);
+ SetChannel(&input_pixels, x, y, 1, y * 10);
+ SetChannel(&input_pixels, x, y, 2, (x + y) * 10);
+ SetChannel(&input_pixels, x, y, 3, 255);
+ break;
+ case 1: // Small blocks
+ SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0);
+ SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0);
+ SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0);
+ SetChannel(&input_pixels, x, y, 3, 255);
+ break;
+ case 2: // Medium blocks
+ SetChannel(&input_pixels, x, y, 0, 10 + x / 2 * 50);
+ SetChannel(&input_pixels, x, y, 1, 10 + y / 3 * 50);
+ SetChannel(&input_pixels, x, y, 2, (x + y) / 5 * 50 + 5);
+ SetChannel(&input_pixels, x, y, 3, 255);
+ break;
+ }
+ }
+ }
+
+ gl_->BindTexture(GL_TEXTURE_2D, src_texture);
+ gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsize, ysize, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, input_pixels.getPixels());
+
+ gpu::Mailbox mailbox;
+ gl_->GenMailboxCHROMIUM(mailbox.name);
+ EXPECT_FALSE(mailbox.IsZero());
+ gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ const GLuint64 fence_sync = gl_->InsertFenceSyncCHROMIUM();
+ gl_->ShallowFlushCHROMIUM();
+
+ gpu::SyncToken sync_token;
+ gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+
+ std::string message = base::StringPrintf(
+ "input size: %dx%d "
+ "output size: %dx%d "
+ "margin: %dx%d "
+ "pattern: %d %s %s",
+ xsize, ysize, output_xsize, output_ysize, xmargin, ymargin,
+ test_pattern, flip ? "flip" : "noflip", flip ? "mrt" : "nomrt");
+ scoped_ptr<ReadbackYUVInterface> yuv_reader(
+ helper_->CreateReadbackPipelineYUV(
+ quality, gfx::Size(xsize, ysize), gfx::Rect(0, 0, xsize, ysize),
+ gfx::Size(xsize, ysize), flip, use_mrt));
+
+ scoped_refptr<media::VideoFrame> output_frame =
+ media::VideoFrame::CreateFrame(
+ media::PIXEL_FORMAT_YV12,
+ // The coded size of the output frame is rounded up to the next
+ // 16-byte boundary. This tests that the readback is being
+ // positioned inside the frame's visible region, and not dependent
+ // on its coded size.
+ gfx::Size((output_xsize + 15) & ~15, (output_ysize + 15) & ~15),
+ gfx::Rect(0, 0, output_xsize, output_ysize),
+ gfx::Size(output_xsize, output_ysize),
+ base::TimeDelta::FromSeconds(0));
+ scoped_refptr<media::VideoFrame> truth_frame =
+ media::VideoFrame::CreateFrame(
+ media::PIXEL_FORMAT_YV12, gfx::Size(output_xsize, output_ysize),
+ gfx::Rect(0, 0, output_xsize, output_ysize),
+ gfx::Size(output_xsize, output_ysize),
+ base::TimeDelta::FromSeconds(0));
+
+ base::RunLoop run_loop;
+ yuv_reader->ReadbackYUV(mailbox, sync_token, output_frame.get(),
+ gfx::Point(xmargin, ymargin),
+ base::Bind(&callcallback, run_loop.QuitClosure()));
+ run_loop.Run();
+
+ if (flip) {
+ FlipSKBitmap(&input_pixels);
+ }
+
+ unsigned char* Y = truth_frame->visible_data(media::VideoFrame::kYPlane);
+ unsigned char* U = truth_frame->visible_data(media::VideoFrame::kUPlane);
+ unsigned char* V = truth_frame->visible_data(media::VideoFrame::kVPlane);
+ int32_t y_stride = truth_frame->stride(media::VideoFrame::kYPlane);
+ int32_t u_stride = truth_frame->stride(media::VideoFrame::kUPlane);
+ int32_t v_stride = truth_frame->stride(media::VideoFrame::kVPlane);
+ memset(Y, 0x00, y_stride * output_ysize);
+ memset(U, 0x80, u_stride * output_ysize / 2);
+ memset(V, 0x80, v_stride * output_ysize / 2);
+
+ const float kRGBtoYColorWeights[] = {0.257f, 0.504f, 0.098f, 0.0625f};
+ const float kRGBtoUColorWeights[] = {-0.148f, -0.291f, 0.439f, 0.5f};
+ const float kRGBtoVColorWeights[] = {0.439f, -0.368f, -0.071f, 0.5f};
+
+ for (int y = 0; y < ysize; y++) {
+ for (int x = 0; x < xsize; x++) {
+ Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte(
+ ChannelAsFloat(&input_pixels, x, y, 0) * kRGBtoYColorWeights[0] +
+ ChannelAsFloat(&input_pixels, x, y, 1) * kRGBtoYColorWeights[1] +
+ ChannelAsFloat(&input_pixels, x, y, 2) * kRGBtoYColorWeights[2] +
+ kRGBtoYColorWeights[3]);
+ }
+ }
+
+ for (int y = 0; y < ysize / 2; y++) {
+ for (int x = 0; x < xsize / 2; x++) {
+ U[(y + ymargin / 2) * u_stride + x + xmargin / 2] =
+ float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) *
+ kRGBtoUColorWeights[0] +
+ Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) *
+ kRGBtoUColorWeights[1] +
+ Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) *
+ kRGBtoUColorWeights[2] +
+ kRGBtoUColorWeights[3]);
+ V[(y + ymargin / 2) * v_stride + x + xmargin / 2] =
+ float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) *
+ kRGBtoVColorWeights[0] +
+ Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) *
+ kRGBtoVColorWeights[1] +
+ Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) *
+ kRGBtoVColorWeights[2] +
+ kRGBtoVColorWeights[3]);
+ }
+ }
+
+ ComparePlane(
+ Y, y_stride, output_frame->visible_data(media::VideoFrame::kYPlane),
+ output_frame->stride(media::VideoFrame::kYPlane), 2, output_xsize,
+ output_ysize, &input_pixels, message + " Y plane");
+ ComparePlane(
+ U, u_stride, output_frame->visible_data(media::VideoFrame::kUPlane),
+ output_frame->stride(media::VideoFrame::kUPlane), 2, output_xsize / 2,
+ output_ysize / 2, &input_pixels, message + " U plane");
+ ComparePlane(
+ V, v_stride, output_frame->visible_data(media::VideoFrame::kVPlane),
+ output_frame->stride(media::VideoFrame::kVPlane), 2, output_xsize / 2,
+ output_ysize / 2, &input_pixels, message + " V plane");
+
+ gl_->DeleteTextures(1, &src_texture);
+ }
+
+ void TestAddOps(int src, int dst, bool scale_x, bool allow3) {
+ std::deque<GLHelperScaling::ScaleOp> ops;
+ GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
+ // Scale factor 3 is a special case.
+ // It is currently only allowed by itself.
+ if (allow3 && dst * 3 >= src && dst * 2 < src) {
+ EXPECT_EQ(ops[0].scale_factor, 3);
+ EXPECT_EQ(ops.size(), 1U);
+ EXPECT_EQ(ops[0].scale_x, scale_x);
+ EXPECT_EQ(ops[0].scale_size, dst);
+ return;
+ }
+
+ for (size_t i = 0; i < ops.size(); i++) {
+ EXPECT_EQ(ops[i].scale_x, scale_x);
+ if (i == 0) {
+ // Only the first op is allowed to be a scale up.
+ // (Scaling up *after* scaling down would make it fuzzy.)
+ EXPECT_TRUE(ops[0].scale_factor == 0 || ops[0].scale_factor == 2);
+ } else {
+ // All other operations must be 50% downscales.
+ EXPECT_EQ(ops[i].scale_factor, 2);
+ }
+ }
+ // Check that the scale factors make sense and add up.
+ int tmp = dst;
+ for (int i = static_cast<int>(ops.size() - 1); i >= 0; i--) {
+ EXPECT_EQ(tmp, ops[i].scale_size);
+ if (ops[i].scale_factor == 0) {
+ EXPECT_EQ(i, 0);
+ EXPECT_GT(tmp, src);
+ tmp = src;
+ } else {
+ tmp *= ops[i].scale_factor;
+ }
+ }
+ EXPECT_EQ(tmp, src);
+ }
+
+ void CheckPipeline2(int xsize,
+ int ysize,
+ int dst_xsize,
+ int dst_ysize,
+ const std::string& description) {
+ std::vector<GLHelperScaling::ScalerStage> stages;
+ helper_scaling_->ConvertScalerOpsToScalerStages(
+ content::GLHelper::SCALER_QUALITY_GOOD, gfx::Size(xsize, ysize),
+ gfx::Rect(0, 0, xsize, ysize), gfx::Size(dst_xsize, dst_ysize), false,
+ false, &x_ops_, &y_ops_, &stages);
+ EXPECT_EQ(x_ops_.size(), 0U);
+ EXPECT_EQ(y_ops_.size(), 0U);
+ ValidateScalerStages(content::GLHelper::SCALER_QUALITY_GOOD, stages,
+ gfx::Size(dst_xsize, dst_ysize), "");
+ EXPECT_EQ(PrintStages(stages), description);
+ }
+
+ void CheckOptimizationsTest() {
+ // Basic upscale. X and Y should be combined into one pass.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
+ CheckPipeline2(1024, 768, 2000, 2000, "1024x768 -> 2000x2000 bilinear\n");
+
+ // X scaled 1/2, Y upscaled, should still be one pass.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 2000));
+ CheckPipeline2(1024, 768, 512, 2000, "1024x768 -> 512x2000 bilinear\n");
+
+ // X upscaled, Y scaled 1/2, one bilinear pass
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 2000));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
+ CheckPipeline2(1024, 768, 2000, 384, "1024x768 -> 2000x384 bilinear\n");
+
+ // X scaled 1/2, Y scaled 1/2, one bilinear pass
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 512));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 384));
+ CheckPipeline2(1024, 768, 512, 384, "1024x768 -> 512x384 bilinear\n");
+
+ // X scaled 1/2, Y scaled to 60%, one bilinear2 pass.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ CheckPipeline2(100, 100, 50, 60, "100x100 -> 50x60 bilinear2 Y\n");
+
+ // X scaled to 60%, Y scaled 1/2, one bilinear2 pass.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 50));
+ CheckPipeline2(100, 100, 60, 50, "100x100 -> 60x50 bilinear2 X\n");
+
+ // X scaled to 60%, Y scaled 60%, one bilinear2x2 pass.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ CheckPipeline2(100, 100, 60, 60, "100x100 -> 60x60 bilinear2x2\n");
+
+ // X scaled to 40%, Y scaled 40%, two bilinear3 passes.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
+ CheckPipeline2(100, 100, 40, 40,
+ "100x100 -> 100x40 bilinear3 Y\n"
+ "100x40 -> 40x40 bilinear3 X\n");
+
+ // X scaled to 60%, Y scaled 40%
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(3, false, 40));
+ CheckPipeline2(100, 100, 60, 40,
+ "100x100 -> 100x40 bilinear3 Y\n"
+ "100x40 -> 60x40 bilinear2 X\n");
+
+ // X scaled to 40%, Y scaled 60%
+ x_ops_.push_back(GLHelperScaling::ScaleOp(3, true, 40));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ CheckPipeline2(100, 100, 40, 60,
+ "100x100 -> 100x60 bilinear2 Y\n"
+ "100x60 -> 40x60 bilinear3 X\n");
+
+ // X scaled to 30%, Y scaled 30%
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 120));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 60));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 30));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
+ CheckPipeline2(100, 100, 30, 30,
+ "100x100 -> 100x30 bilinear4 Y\n"
+ "100x30 -> 30x30 bilinear4 X\n");
+
+ // X scaled to 50%, Y scaled 30%
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 50));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
+ CheckPipeline2(100, 100, 50, 30, "100x100 -> 50x30 bilinear4 Y\n");
+
+ // X scaled to 150%, Y scaled 30%
+ // Note that we avoid combinding X and Y passes
+ // as that would probably be LESS efficient here.
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 150));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 120));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 60));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 30));
+ CheckPipeline2(100, 100, 150, 30,
+ "100x100 -> 100x30 bilinear4 Y\n"
+ "100x30 -> 150x30 bilinear\n");
+
+ // X scaled to 1%, Y scaled 1%
+ x_ops_.push_back(GLHelperScaling::ScaleOp(0, true, 128));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 64));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 32));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 16));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 8));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 4));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 2));
+ x_ops_.push_back(GLHelperScaling::ScaleOp(2, true, 1));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(0, false, 128));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 64));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 32));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 16));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 8));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 4));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 2));
+ y_ops_.push_back(GLHelperScaling::ScaleOp(2, false, 1));
+ CheckPipeline2(100, 100, 1, 1,
+ "100x100 -> 100x32 bilinear4 Y\n"
+ "100x32 -> 100x4 bilinear4 Y\n"
+ "100x4 -> 64x1 bilinear2x2\n"
+ "64x1 -> 8x1 bilinear4 X\n"
+ "8x1 -> 1x1 bilinear4 X\n");
+ }
+
+ scoped_ptr<gpu::GLInProcessContext> context_;
+ gpu::gles2::GLES2Interface* gl_;
+ scoped_ptr<content::GLHelper> helper_;
+ scoped_ptr<content::GLHelperScaling> helper_scaling_;
+ std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+};
+
+class GLHelperPixelTest : public GLHelperTest {
+ private:
+ gfx::DisableNullDrawGLBindings enable_pixel_output_;
+};
+
+TEST_F(GLHelperTest, RGBASyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kRGBA_8888_SkColorType, false);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperTest, BGRASyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kBGRA_8888_SkColorType, false);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperTest, RGB565SyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kRGB_565_SkColorType, false);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperTest, RGBAASyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kRGBA_8888_SkColorType, true);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperTest, BGRAASyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kBGRA_8888_SkColorType, true);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperTest, RGB565ASyncReadbackTest) {
+ const int kTestSize = 64;
+ bool result = TestTextureFormatReadback(gfx::Size(kTestSize, kTestSize),
+ kRGB_565_SkColorType, true);
+ EXPECT_EQ(result, true);
+}
+
+TEST_F(GLHelperPixelTest, YUVReadbackOptTest) {
+ // This test uses the gpu.service/gpu_decoder tracing events to detect how
+ // many scaling passes are actually performed by the YUV readback pipeline.
+ StartTracing(TRACE_DISABLED_BY_DEFAULT(
+ "gpu.service") "," TRACE_DISABLED_BY_DEFAULT("gpu_decoder"));
+
+ TestYUVReadback(800, 400, 800, 400, 0, 0, 1, false, true,
+ content::GLHelper::SCALER_QUALITY_FAST);
+
+ std::map<std::string, int> event_counts;
+ EndTracing(&event_counts);
+ int draw_buffer_calls = event_counts["kDrawBuffersEXTImmediate"];
+ int draw_arrays_calls = event_counts["kDrawArrays"];
+ VLOG(1) << "Draw buffer calls: " << draw_buffer_calls;
+ VLOG(1) << "DrawArrays calls: " << draw_arrays_calls;
+
+ if (draw_buffer_calls) {
+ // When using MRT, the YUV readback code should only
+ // execute two draw arrays, and scaling should be integrated
+ // into those two calls since we are using the FAST scalign
+ // quality.
+ EXPECT_EQ(2, draw_arrays_calls);
+ } else {
+ // When not using MRT, there are three passes for the YUV,
+ // and one for the scaling.
+ EXPECT_EQ(4, draw_arrays_calls);
+ }
+}
+
+class GLHelperPixelYuvReadback
+ : public GLHelperPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<bool, bool, unsigned int, unsigned int>> {};
+
+int kYUVReadBackSizes[] = {2, 4, 14};
+
+TEST_P(GLHelperPixelYuvReadback, Test) {
+ bool flip = std::tr1::get<0>(GetParam());
+ bool use_mrt = std::tr1::get<1>(GetParam());
+ unsigned int x = std::tr1::get<2>(GetParam());
+ unsigned int y = std::tr1::get<3>(GetParam());
+
+ for (unsigned int ox = x; ox < arraysize(kYUVReadBackSizes); ox++) {
+ for (unsigned int oy = y; oy < arraysize(kYUVReadBackSizes); oy++) {
+ // If output is a subsection of the destination frame, (letterbox)
+ // then try different variations of where the subsection goes.
+ for (Margin xm = x < ox ? MarginLeft : MarginRight; xm <= MarginRight;
+ xm = NextMargin(xm)) {
+ for (Margin ym = y < oy ? MarginLeft : MarginRight; ym <= MarginRight;
+ ym = NextMargin(ym)) {
+ for (int pattern = 0; pattern < 3; pattern++) {
+ TestYUVReadback(
+ kYUVReadBackSizes[x], kYUVReadBackSizes[y],
+ kYUVReadBackSizes[ox], kYUVReadBackSizes[oy],
+ compute_margin(kYUVReadBackSizes[x], kYUVReadBackSizes[ox], xm),
+ compute_margin(kYUVReadBackSizes[y], kYUVReadBackSizes[oy], ym),
+ pattern, flip, use_mrt, content::GLHelper::SCALER_QUALITY_GOOD);
+ if (HasFailure()) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// First argument is intentionally empty.
+INSTANTIATE_TEST_CASE_P(
+ ,
+ GLHelperPixelYuvReadback,
+ ::testing::Combine(
+ ::testing::Bool(),
+ ::testing::Bool(),
+ ::testing::Range<unsigned int>(0, arraysize(kYUVReadBackSizes)),
+ ::testing::Range<unsigned int>(0, arraysize(kYUVReadBackSizes))));
+
+int kRGBReadBackSizes[] = {3, 6, 16};
+
+class GLHelperPixelReadbackTest
+ : public GLHelperPixelTest,
+ public ::testing::WithParamInterface<std::tr1::tuple<unsigned int,
+ unsigned int,
+ unsigned int,
+ unsigned int,
+ unsigned int>> {};
+
+// Per pixel tests, all sizes are small so that we can print
+// out the generated bitmaps.
+TEST_P(GLHelperPixelReadbackTest, ScaleTest) {
+ unsigned int q_index = std::tr1::get<0>(GetParam());
+ unsigned int x = std::tr1::get<1>(GetParam());
+ unsigned int y = std::tr1::get<2>(GetParam());
+ unsigned int dst_x = std::tr1::get<3>(GetParam());
+ unsigned int dst_y = std::tr1::get<4>(GetParam());
+
+ for (int flip = 0; flip <= 1; flip++) {
+ for (int pattern = 0; pattern < 3; pattern++) {
+ TestScale(kRGBReadBackSizes[x], kRGBReadBackSizes[y],
+ kRGBReadBackSizes[dst_x], kRGBReadBackSizes[dst_y], pattern,
+ q_index, flip == 1);
+ if (HasFailure()) {
+ return;
+ }
+ }
+ }
+}
+
+// Per pixel tests, all sizes are small so that we can print
+// out the generated bitmaps.
+TEST_P(GLHelperPixelReadbackTest, CropScaleReadbackAndCleanTextureTest) {
+ unsigned int q_index = std::tr1::get<0>(GetParam());
+ unsigned int x = std::tr1::get<1>(GetParam());
+ unsigned int y = std::tr1::get<2>(GetParam());
+ unsigned int dst_x = std::tr1::get<3>(GetParam());
+ unsigned int dst_y = std::tr1::get<4>(GetParam());
+
+ const SkColorType kColorTypes[] = {
+ kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType};
+ for (size_t color_type = 0; color_type < arraysize(kColorTypes);
+ color_type++) {
+ for (int pattern = 0; pattern < 3; pattern++) {
+ TestCropScaleReadbackAndCleanTexture(
+ kRGBReadBackSizes[x], kRGBReadBackSizes[y], kRGBReadBackSizes[dst_x],
+ kRGBReadBackSizes[dst_y], pattern, kColorTypes[color_type], false,
+ q_index);
+ if (HasFailure())
+ return;
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ,
+ GLHelperPixelReadbackTest,
+ ::testing::Combine(
+ ::testing::Range<unsigned int>(0, arraysize(kQualities)),
+ ::testing::Range<unsigned int>(0, arraysize(kRGBReadBackSizes)),
+ ::testing::Range<unsigned int>(0, arraysize(kRGBReadBackSizes)),
+ ::testing::Range<unsigned int>(0, arraysize(kRGBReadBackSizes)),
+ ::testing::Range<unsigned int>(0, arraysize(kRGBReadBackSizes))));
+
+// Validate that all scaling generates valid pipelines.
+TEST_F(GLHelperTest, ValidateScalerPipelines) {
+ int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096};
+ for (size_t q = 0; q < arraysize(kQualities); q++) {
+ for (size_t x = 0; x < arraysize(sizes); x++) {
+ for (size_t y = 0; y < arraysize(sizes); y++) {
+ for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) {
+ for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) {
+ TestScalerPipeline(q, sizes[x], sizes[y], sizes[dst_x],
+ sizes[dst_y]);
+ if (HasFailure()) {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Make sure we don't create overly complicated pipelines
+// for a few common use cases.
+TEST_F(GLHelperTest, CheckSpecificPipelines) {
+ // Upscale should be single pass.
+ CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 1024, 700, 1280, 720,
+ "1024x700 -> 1280x720 bilinear\n");
+ // Slight downscale should use BILINEAR2X2.
+ CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 1280, 720, 1024, 700,
+ "1280x720 -> 1024x700 bilinear2x2\n");
+ // Most common tab capture pipeline on the Pixel.
+ // Should be using two BILINEAR3 passes.
+ CheckPipeline(content::GLHelper::SCALER_QUALITY_GOOD, 2560, 1476, 1249, 720,
+ "2560x1476 -> 2560x720 bilinear3 Y\n"
+ "2560x720 -> 1249x720 bilinear3 X\n");
+}
+
+TEST_F(GLHelperTest, ScalerOpTest) {
+ for (int allow3 = 0; allow3 <= 1; allow3++) {
+ for (int dst = 1; dst < 2049; dst += 1 + (dst >> 3)) {
+ for (int src = 1; src < 2049; src++) {
+ TestAddOps(src, dst, allow3 == 1, (src & 1) == 1);
+ if (HasFailure()) {
+ LOG(ERROR) << "Failed for src=" << src << " dst=" << dst
+ << " allow3=" << allow3;
+ return;
+ }
+ }
+ }
+ }
+}
+
+TEST_F(GLHelperTest, CheckOptimizations) {
+ // Test in baseclass since it is friends with GLHelperScaling
+ CheckOptimizationsTest();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
index adf0764c65a..f3eb5f5aa20 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -41,12 +41,12 @@ GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
GpuBrowserCompositorOutputSurface::~GpuBrowserCompositorOutputSurface() {}
-CommandBufferProxyImpl*
+gpu::CommandBufferProxyImpl*
GpuBrowserCompositorOutputSurface::GetCommandBufferProxy() {
ContextProviderCommandBuffer* provider_command_buffer =
static_cast<content::ContextProviderCommandBuffer*>(
context_provider_.get());
- CommandBufferProxyImpl* command_buffer_proxy =
+ gpu::CommandBufferProxyImpl* command_buffer_proxy =
provider_command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
return command_buffer_proxy;
diff --git a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
index ae08e8d1a2d..4133bc36951 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -11,12 +11,15 @@
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "ui/gfx/swap_result.h"
+namespace gpu {
+class CommandBufferProxyImpl;
+}
+
namespace ui {
class CompositorVSyncManager;
}
namespace content {
-class CommandBufferProxyImpl;
class BrowserCompositorOverlayCandidateValidator;
class ReflectorTexture;
@@ -64,7 +67,7 @@ class GpuBrowserCompositorOutputSurface
ShouldShowFramesState should_show_frames_state_;
#endif
- CommandBufferProxyImpl* GetCommandBufferProxy();
+ gpu::CommandBufferProxyImpl* GetCommandBufferProxy();
base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&,
gfx::SwapResult)>
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.cc b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
index 874debf5f1e..9a4ad655d5b 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
@@ -26,6 +26,7 @@
#include "cc/surfaces/surface_manager.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
#include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
#include "content/browser/compositor/offscreen_browser_compositor_output_surface.h"
@@ -34,27 +35,24 @@
#include "content/browser/compositor/software_output_device_mus.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_constants.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
#if defined(MOJO_RUNNER_CLIENT)
#include "content/common/mojo/mojo_shell_connection_impl.h"
@@ -62,6 +60,7 @@
#if defined(OS_WIN)
#include "content/browser/compositor/software_output_device_win.h"
+#include "ui/gfx/win/rendering_window_manager.h"
#elif defined(USE_OZONE)
#include "content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.h"
#include "content/browser/compositor/software_output_device_ozone.h"
@@ -99,11 +98,9 @@ GpuProcessTransportFactory::GpuProcessTransportFactory()
: next_surface_id_namespace_(1u),
task_graph_runner_(new cc::SingleThreadTaskGraphRunner),
callback_factory_(this) {
- ui::Layer::InitializeUILayerSettings();
cc::SetClientNameForMetrics("Browser");
- if (UseSurfacesEnabled())
- surface_manager_ = make_scoped_ptr(new cc::SurfaceManager);
+ surface_manager_ = make_scoped_ptr(new cc::SurfaceManager);
task_graph_runner_->Start("CompositorTileWorker1",
base::SimpleThread::Options());
@@ -123,15 +120,11 @@ GpuProcessTransportFactory::~GpuProcessTransportFactory() {
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
-#if defined(OS_ANDROID)
- return CreateContextCommon(scoped_refptr<GpuChannelHost>(nullptr), 0);
-#else
CauseForGpuLaunch cause =
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
- scoped_refptr<GpuChannelHost> gpu_channel_host(
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause));
- return CreateContextCommon(gpu_channel_host, 0);
-#endif // OS_ANDROID
+ return CreateContextCommon(gpu_channel_host, gpu::kNullSurfaceHandle);
}
scoped_ptr<cc::SoftwareOutputDevice>
@@ -224,6 +217,11 @@ void GpuProcessTransportFactory::CreateOutputSurface(
data->surface = nullptr;
}
+#if defined(OS_WIN)
+ gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
+ compositor->widget());
+#endif
+
bool create_gpu_output_surface =
ShouldCreateGpuOutputSurface(compositor.get());
if (create_gpu_output_surface) {
@@ -262,6 +260,11 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
create_gpu_output_surface = false;
}
+#if defined(OS_WIN)
+ gfx::RenderingWindowManager::GetInstance()->RegisterParent(
+ compositor->widget());
+#endif
+
scoped_refptr<ContextProviderCommandBuffer> context_provider;
if (create_gpu_output_surface) {
// Try to reuse existing worker context provider.
@@ -274,20 +277,26 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
shared_worker_context_provider_lost = true;
}
}
- scoped_refptr<GpuChannelHost> gpu_channel_host =
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
if (gpu_channel_host.get()) {
+ GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
+ gpu::SurfaceHandle surface_handle =
+ data->surface_id ? tracker->GetSurfaceHandle(data->surface_id)
+ : gpu::kNullSurfaceHandle;
+ // This context is used for both the browser compositor and the display
+ // compositor.
context_provider = ContextProviderCommandBuffer::Create(
GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
- data->surface_id),
- BROWSER_COMPOSITOR_ONSCREEN_CONTEXT);
+ surface_handle),
+ DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT);
if (context_provider && !context_provider->BindToCurrentThread())
context_provider = nullptr;
if (!shared_worker_context_provider_ ||
shared_worker_context_provider_lost) {
shared_worker_context_provider_ = ContextProviderCommandBuffer::Create(
- GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
- 0),
+ GpuProcessTransportFactory::CreateContextCommon(
+ gpu_channel_host, gpu::kNullSurfaceHandle),
BROWSER_WORKER_CONTEXT);
if (shared_worker_context_provider_ &&
!shared_worker_context_provider_->BindToCurrentThread())
@@ -334,7 +343,7 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
GLenum format = GL_RGB;
#if defined(OS_MACOSX)
target = GL_TEXTURE_RECTANGLE_ARB;
- format = GL_BGRA_EXT;
+ format = GL_RGBA;
#endif
surface =
make_scoped_ptr(new GpuSurfacelessBrowserCompositorOutputSurface(
@@ -361,10 +370,10 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
if (data->reflector)
data->reflector->OnSourceSurfaceReady(data->surface);
- if (!UseSurfacesEnabled()) {
- compositor->SetOutputSurface(std::move(surface));
- return;
- }
+#if defined(OS_WIN)
+ gfx::RenderingWindowManager::GetInstance()->DoSetParentOnChild(
+ compositor->widget());
+#endif
// This gets a bit confusing. Here we have a ContextProvider in the |surface|
// configured to render directly to this widget. We need to make an
@@ -442,6 +451,10 @@ void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
DCHECK(!gl_helper_) << "Destroying the GLHelper should not cause a new "
"GLHelper to be created.";
}
+#if defined(OS_WIN)
+ gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
+ compositor->widget());
+#endif
}
bool GpuProcessTransportFactory::DoesCreateTestContexts() { return false; }
@@ -579,24 +592,13 @@ GpuProcessTransportFactory::CreatePerCompositorData(
DCHECK(!per_compositor_data_[compositor]);
gfx::AcceleratedWidget widget = compositor->widget();
- GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
PerCompositorData* data = new PerCompositorData;
if (compositor->widget() == gfx::kNullAcceleratedWidget) {
data->surface_id = 0;
} else {
+ GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
- // On Mac and Android, we can't pass the AcceleratedWidget, which is
- // process-local, so instead we pass the surface_id, so that we can look up
- // the AcceleratedWidget on the GPU side or when we receive
- // GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params.
- gfx::PluginWindowHandle handle = data->surface_id;
-#else
- gfx::PluginWindowHandle handle = widget;
-#endif
- tracker->SetSurfaceHandle(data->surface_id,
- gfx::GLSurfaceHandle(handle, gfx::NATIVE_DIRECT));
}
per_compositor_data_[compositor] = data;
@@ -606,31 +608,46 @@ GpuProcessTransportFactory::CreatePerCompositorData(
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
GpuProcessTransportFactory::CreateContextCommon(
- scoped_refptr<GpuChannelHost> gpu_channel_host,
- int surface_id) {
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+ gpu::SurfaceHandle surface_handle) {
if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
- return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
- blink::WebGraphicsContext3D::Attributes attrs;
- attrs.shareResources = true;
- attrs.depth = false;
- attrs.stencil = false;
- attrs.antialias = false;
- attrs.noAutomaticFlushes = true;
- bool lose_context_when_out_of_memory = true;
- if (!gpu_channel_host.get()) {
+ return nullptr;
+ if (!gpu_channel_host) {
LOG(ERROR) << "Failed to establish GPU channel.";
- return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+ return nullptr;
}
+
+ // This is called from a few places to create different contexts:
+ // - The shared main thread context (offscreen).
+ // - The compositor context, which is used by the browser compositor
+ // (offscreen) for synchronization mostly, and by the display compositor
+ // (onscreen) for actual GL drawing.
+ // - The compositor worker context (offscreen) used for GPU raster.
+ // So ask for capabilities needed by any of these cases (we can optimize by
+ // branching on |surface_handle| being null if these needs diverge).
+ //
+ // The default framebuffer for an offscreen context is not used, so it does
+ // not need alpha, stencil, depth, antialiasing. The display compositor does
+ // not use these things either, so we can request nothing here.
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = -1;
+ attributes.depth_size = 0;
+ attributes.stencil_size = 0;
+ attributes.samples = 0;
+ attributes.sample_buffers = 0;
+ attributes.bind_generates_resource = false;
+ attributes.lose_context_when_out_of_memory = true;
+
+ bool share_resources = true;
+ bool automatic_flushes = false;
+
GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
new WebGraphicsContext3DCommandBufferImpl(
- surface_id,
- url,
- gpu_channel_host.get(),
- attrs,
- lose_context_when_out_of_memory,
+ surface_handle, url, gpu_channel_host.get(), attributes,
+ gfx::PreferIntegratedGpu, share_resources, automatic_flushes,
WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
- NULL));
+ nullptr));
return context;
}
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.h b/chromium/content/browser/compositor/gpu_process_transport_factory.h
index ee8d60e9ac9..f4e007aa188 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.h
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.h
@@ -17,7 +17,8 @@
#include "base/observer_list.h"
#include "build/build_config.h"
#include "content/browser/compositor/image_transport_factory.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
+#include "gpu/ipc/common/surface_handle.h"
#include "ui/compositor/compositor.h"
namespace base {
@@ -94,8 +95,8 @@ class GpuProcessTransportFactory
bool create_gpu_output_surface,
int num_attempts);
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
- scoped_refptr<GpuChannelHost> gpu_channel_host,
- int surface_id);
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+ gpu::SurfaceHandle surface_handle);
void OnLostMainThreadSharedContextInsideCallback();
void OnLostMainThreadSharedContext();
diff --git a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
index 0913548f2fa..5e85a4e315d 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -10,10 +10,10 @@
#include "cc/output/output_surface_client.h"
#include "content/browser/compositor/browser_compositor_overlay_candidate_validator.h"
#include "content/browser/compositor/buffer_queue.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -29,7 +29,7 @@ GpuSurfacelessBrowserCompositorOutputSurface::
overlay_candidate_validator,
unsigned int target,
unsigned int internalformat,
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager)
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
: GpuBrowserCompositorOutputSurface(context,
worker_context,
vsync_manager,
diff --git a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
index a869fccd8cf..23412198d0e 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -7,9 +7,12 @@
#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
namespace content {
-class BrowserGpuMemoryBufferManager;
class BufferQueue;
class GLHelper;
@@ -25,7 +28,7 @@ class GpuSurfacelessBrowserCompositorOutputSurface
overlay_candidate_validator,
unsigned int target,
unsigned int internalformat,
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager);
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
~GpuSurfacelessBrowserCompositorOutputSurface() override;
private:
@@ -45,7 +48,7 @@ class GpuSurfacelessBrowserCompositorOutputSurface
unsigned int internalformat_;
scoped_ptr<GLHelper> gl_helper_;
scoped_ptr<BufferQueue> output_surface_;
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
};
} // namespace content
diff --git a/chromium/content/browser/compositor/owned_mailbox.cc b/chromium/content/browser/compositor/owned_mailbox.cc
index 912d4d569b7..8e0558212a6 100644
--- a/chromium/content/browser/compositor/owned_mailbox.cc
+++ b/chromium/content/browser/compositor/owned_mailbox.cc
@@ -5,8 +5,8 @@
#include "content/browser/compositor/owned_mailbox.h"
#include "base/logging.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/image_transport_factory.h"
-#include "content/common/gpu/client/gl_helper.h"
namespace content {
diff --git a/chromium/content/browser/compositor/reflector_texture.cc b/chromium/content/browser/compositor/reflector_texture.cc
index 231066275d9..c9b742d425f 100644
--- a/chromium/content/browser/compositor/reflector_texture.cc
+++ b/chromium/content/browser/compositor/reflector_texture.cc
@@ -4,9 +4,9 @@
#include "content/browser/compositor/reflector_texture.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/owned_mailbox.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
diff --git a/chromium/content/browser/compositor/software_output_device_mac.h b/chromium/content/browser/compositor/software_output_device_mac.h
index a613ab4b1d8..84e09873597 100644
--- a/chromium/content/browser/compositor/software_output_device_mac.h
+++ b/chromium/content/browser/compositor/software_output_device_mac.h
@@ -10,6 +10,8 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
#include "cc/output/software_output_device.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/vsync_provider.h"
@@ -63,7 +65,7 @@ class SoftwareOutputDeviceMac :
// The SkCanvas wrapps the mapped current IOSurface. It is valid only between
// BeginPaint and EndPaint.
- skia::RefPtr<SkCanvas> canvas_;
+ sk_sp<SkCanvas> canvas_;
gfx::VSyncProvider::UpdateVSyncCallback update_vsync_callback_;
diff --git a/chromium/content/browser/compositor/software_output_device_mac.mm b/chromium/content/browser/compositor/software_output_device_mac.mm
index e71f6782878..9c9c3931480 100644
--- a/chromium/content/browser/compositor/software_output_device_mac.mm
+++ b/chromium/content/browser/compositor/software_output_device_mac.mm
@@ -123,7 +123,7 @@ SkCanvas* SoftwareOutputDeviceMac::BeginPaint(
IOSurfaceGetBaseAddress(io_surfaces_[current_index_]));
size_t stride = IOSurfaceGetBytesPerRow(io_surfaces_[current_index_]);
- canvas_ = skia::AdoptRef(SkCanvas::NewRasterDirectN32(
+ canvas_ = sk_sp<SkCanvas>(SkCanvas::NewRasterDirectN32(
pixel_size_.width(), pixel_size_.height(), pixels, stride));
CopyPreviousBufferDamage(SkRegion(gfx::RectToSkIRect(new_damage_rect)));
@@ -141,7 +141,7 @@ void SoftwareOutputDeviceMac::EndPaint() {
DLOG(ERROR) << "Failed to unlock IOSurface " << io_result;
}
- canvas_ = nullptr;
+ canvas_.reset();
base::TimeTicks vsync_timebase;
base::TimeDelta vsync_interval;
ui::AcceleratedWidgetMacGotFrame(
diff --git a/chromium/content/browser/compositor/software_output_device_win.cc b/chromium/content/browser/compositor/software_output_device_win.cc
index a712def1911..3ab7677a543 100644
--- a/chromium/content/browser/compositor/software_output_device_win.cc
+++ b/chromium/content/browser/compositor/software_output_device_win.cc
@@ -122,7 +122,7 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
viewport_pixel_size_ = viewport_pixel_size;
if (backing_)
backing_->Resized();
- contents_.clear();
+ contents_.reset();
}
SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
@@ -141,7 +141,7 @@ SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
}
}
if (can_create_contents) {
- contents_ = skia::AdoptRef(skia::CreatePlatformCanvas(
+ contents_ = sk_sp<SkCanvas>(skia::CreatePlatformCanvas(
viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
shared_section, skia::CRASH_ON_FAILURE));
}
@@ -180,10 +180,10 @@ void SoftwareOutputDeviceWin::EndPaint() {
style |= WS_EX_LAYERED;
SetWindowLong(hwnd_, GWL_EXSTYLE, style);
- HDC dib_dc = skia::BeginPlatformPaint(contents_.get());
+ skia::ScopedPlatformPaint spp(contents_.get());
+ HDC dib_dc = spp.GetPlatformSurface();
::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
- skia::EndPlatformPaint(contents_.get());
} else {
HDC hdc = ::GetDC(hwnd_);
RECT src_rect = rect.ToRECT();
@@ -196,7 +196,7 @@ void SoftwareOutputDeviceWin::EndPaint() {
void SoftwareOutputDeviceWin::ReleaseContents() {
DCHECK(!contents_ || contents_->unique());
DCHECK(!in_paint_);
- contents_.clear();
+ contents_.reset();
}
} // namespace content
diff --git a/chromium/content/browser/compositor/software_output_device_win.h b/chromium/content/browser/compositor/software_output_device_win.h
index 1cc267dd55b..5c80340808c 100644
--- a/chromium/content/browser/compositor/software_output_device_win.h
+++ b/chromium/content/browser/compositor/software_output_device_win.h
@@ -13,6 +13,8 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "cc/output/software_output_device.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
namespace base {
class SharedMemory;
@@ -61,7 +63,7 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice {
private:
HWND hwnd_;
- skia::RefPtr<SkCanvas> contents_;
+ sk_sp<SkCanvas> contents_;
bool is_hwnd_composited_;
OutputDeviceBacking* backing_;
bool in_paint_;
diff --git a/chromium/content/browser/compositor/surface_utils.cc b/chromium/content/browser/compositor/surface_utils.cc
index 7ae05912a65..4f4b3bad88c 100644
--- a/chromium/content/browser/compositor/surface_utils.cc
+++ b/chromium/content/browser/compositor/surface_utils.cc
@@ -4,20 +4,162 @@
#include "content/browser/compositor/surface_utils.h"
+#include "base/callback_helpers.h"
+#include "base/memory/ref_counted.h"
#include "build/build_config.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/resources/single_release_callback.h"
#include "cc/surfaces/surface_id_allocator.h"
+#include "content/browser/compositor/gl_helper.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkLumaColorFilter.h"
+#include "ui/gfx/geometry/rect.h"
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
#include "content/browser/renderer_host/compositor_impl_android.h"
#else
#include "content/browser/compositor/image_transport_factory.h"
#include "ui/compositor/compositor.h"
#endif
+namespace {
+
+#if !defined(OS_ANDROID) || defined(USE_AURA)
+void CopyFromCompositingSurfaceFinished(
+ const content::ReadbackRequestCallback& callback,
+ scoped_ptr<cc::SingleReleaseCallback> release_callback,
+ scoped_ptr<SkBitmap> bitmap,
+ scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
+ bool result) {
+ bitmap_pixels_lock.reset();
+
+ gpu::SyncToken sync_token;
+ if (result) {
+ content::GLHelper* gl_helper =
+ content::ImageTransportFactory::GetInstance()->GetGLHelper();
+ if (gl_helper)
+ gl_helper->GenerateSyncToken(&sync_token);
+ }
+ const bool lost_resource = !sync_token.HasData();
+ release_callback->Run(sync_token, lost_resource);
+
+ callback.Run(*bitmap,
+ result ? content::READBACK_SUCCESS : content::READBACK_FAILED);
+}
+#endif
+
+// TODO(wjmaclean): There is significant overlap between
+// PrepareTextureCopyOutputResult and CopyFromCompositingSurfaceFinished in
+// this file, and the versions in RenderWidgetHostViewAndroid. They should
+// be merged. See https://crbug.com/582955
+void PrepareTextureCopyOutputResult(
+ const gfx::Size& dst_size_in_pixel,
+ const SkColorType color_type,
+ const content::ReadbackRequestCallback& callback,
+ scoped_ptr<cc::CopyOutputResult> result) {
+#if defined(OS_ANDROID) && !defined(USE_AURA)
+ // TODO(wjmaclean): See if there's an equivalent pathway for Android and
+ // implement it here.
+ callback.Run(SkBitmap(), content::READBACK_FAILED);
+#else
+ DCHECK(result->HasTexture());
+ base::ScopedClosureRunner scoped_callback_runner(
+ base::Bind(callback, SkBitmap(), content::READBACK_FAILED));
+
+ // TODO(siva.gunturi): We should be able to validate the format here using
+ // GLHelper::IsReadbackConfigSupported before we processs the result.
+ // See crbug.com/415682 and crbug.com/415131.
+ scoped_ptr<SkBitmap> bitmap(new SkBitmap);
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(
+ dst_size_in_pixel.width(), dst_size_in_pixel.height(), color_type,
+ kOpaque_SkAlphaType))) {
+ scoped_callback_runner.Reset(base::Bind(
+ callback, SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE));
+ return;
+ }
+
+ content::ImageTransportFactory* factory =
+ content::ImageTransportFactory::GetInstance();
+ content::GLHelper* gl_helper = factory->GetGLHelper();
+ if (!gl_helper)
+ return;
+
+ scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
+ new SkAutoLockPixels(*bitmap));
+ uint8_t* pixels = static_cast<uint8_t*>(bitmap->getPixels());
+
+ cc::TextureMailbox texture_mailbox;
+ scoped_ptr<cc::SingleReleaseCallback> release_callback;
+ result->TakeTexture(&texture_mailbox, &release_callback);
+ DCHECK(texture_mailbox.IsTexture());
+
+ ignore_result(scoped_callback_runner.Release());
+
+ gl_helper->CropScaleReadbackAndCleanMailbox(
+ texture_mailbox.mailbox(), texture_mailbox.sync_token(), result->size(),
+ gfx::Rect(result->size()), dst_size_in_pixel, pixels, color_type,
+ base::Bind(&CopyFromCompositingSurfaceFinished, callback,
+ base::Passed(&release_callback), base::Passed(&bitmap),
+ base::Passed(&bitmap_pixels_lock)),
+ content::GLHelper::SCALER_QUALITY_GOOD);
+#endif
+}
+
+void PrepareBitmapCopyOutputResult(
+ const gfx::Size& dst_size_in_pixel,
+ const SkColorType preferred_color_type,
+ const content::ReadbackRequestCallback& callback,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ SkColorType color_type = preferred_color_type;
+ if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
+ // Switch back to default colortype if format not supported.
+ color_type = kN32_SkColorType;
+ }
+ DCHECK(result->HasBitmap());
+ scoped_ptr<SkBitmap> source = result->TakeBitmap();
+ DCHECK(source);
+ SkBitmap scaled_bitmap;
+ if (source->width() != dst_size_in_pixel.width() ||
+ source->height() != dst_size_in_pixel.height()) {
+ scaled_bitmap = skia::ImageOperations::Resize(
+ *source, skia::ImageOperations::RESIZE_BEST, dst_size_in_pixel.width(),
+ dst_size_in_pixel.height());
+ } else {
+ scaled_bitmap = *source;
+ }
+ if (color_type == kN32_SkColorType) {
+ DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+ callback.Run(scaled_bitmap, content::READBACK_SUCCESS);
+ return;
+ }
+ DCHECK_EQ(color_type, kAlpha_8_SkColorType);
+ // The software path currently always returns N32 bitmap regardless of the
+ // |color_type| we ask for.
+ DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+ // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
+ SkBitmap grayscale_bitmap;
+ bool success = grayscale_bitmap.tryAllocPixels(
+ SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
+ if (!success) {
+ callback.Run(SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE);
+ return;
+ }
+ SkCanvas canvas(grayscale_bitmap);
+ SkPaint paint;
+ paint.setColorFilter(SkLumaColorFilter::Make());
+ canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
+ callback.Run(grayscale_bitmap, content::READBACK_SUCCESS);
+}
+
+} // namespace
+
namespace content {
scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() {
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
return CompositorImpl::CreateSurfaceIdAllocator();
#else
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
@@ -26,7 +168,7 @@ scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() {
}
cc::SurfaceManager* GetSurfaceManager() {
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
return CompositorImpl::GetSurfaceManager();
#else
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
@@ -34,4 +176,33 @@ cc::SurfaceManager* GetSurfaceManager() {
#endif
}
+void CopyFromCompositingSurfaceHasResult(
+ const gfx::Size& dst_size_in_pixel,
+ const SkColorType color_type,
+ const ReadbackRequestCallback& callback,
+ scoped_ptr<cc::CopyOutputResult> result) {
+ if (result->IsEmpty() || result->size().IsEmpty()) {
+ callback.Run(SkBitmap(), READBACK_FAILED);
+ return;
+ }
+
+ gfx::Size output_size_in_pixel;
+ if (dst_size_in_pixel.IsEmpty())
+ output_size_in_pixel = result->size();
+ else
+ output_size_in_pixel = dst_size_in_pixel;
+
+ if (result->HasTexture()) {
+ // GPU-accelerated path
+ PrepareTextureCopyOutputResult(output_size_in_pixel, color_type, callback,
+ std::move(result));
+ return;
+ }
+
+ DCHECK(result->HasBitmap());
+ // Software path
+ PrepareBitmapCopyOutputResult(output_size_in_pixel, color_type, callback,
+ std::move(result));
+}
+
} // namespace content
diff --git a/chromium/content/browser/compositor/surface_utils.h b/chromium/content/browser/compositor/surface_utils.h
index b56fef27170..6d986a9c8ca 100644
--- a/chromium/content/browser/compositor/surface_utils.h
+++ b/chromium/content/browser/compositor/surface_utils.h
@@ -6,8 +6,13 @@
#define CONTENT_BROWSER_COMPOSITOR_SURFACE_UTILS_H_
#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/readback_types.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
+class CopyOutputResult;
class SurfaceIdAllocator;
class SurfaceManager;
} // namespace cc
@@ -16,8 +21,15 @@ namespace content {
scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator();
+CONTENT_EXPORT
cc::SurfaceManager* GetSurfaceManager();
+void CopyFromCompositingSurfaceHasResult(
+ const gfx::Size& dst_size_in_pixel,
+ const SkColorType color_type,
+ const ReadbackRequestCallback& callback,
+ scoped_ptr<cc::CopyOutputResult> result);
+
} // namespace content
#endif // CONTENT_BROWSER_COMPOSITOR_SURFACE_UTILS_H_
diff --git a/chromium/content/browser/cross_site_transfer_browsertest.cc b/chromium/content/browser/cross_site_transfer_browsertest.cc
index fbe720d9e11..1b7c099e455 100644
--- a/chromium/content/browser/cross_site_transfer_browsertest.cc
+++ b/chromium/content/browser/cross_site_transfer_browsertest.cc
@@ -293,7 +293,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
// navigation. This test is the same as the test above, except transfering from
// in-process.
IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
- ReplaceEntryInProcessThenTranfers) {
+ ReplaceEntryInProcessThenTransfer) {
const NavigationController& controller =
shell()->web_contents()->GetController();
@@ -367,8 +367,8 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest,
"A.com", "/cross-site/" + url3b.host() + url3b.PathForRequest());
NavigateToURLContentInitiated(shell(), url3a, false, true);
- // There should be two history entries. url2b should have replaced url1. url2b
- // should not have replaced url3b.
+ // There should be two history entries. url2b should have replaced url1. url3b
+ // should not have replaced url2b.
EXPECT_TRUE(controller.GetPendingEntry() == nullptr);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
diff --git a/chromium/content/browser/database_util_unittest.cc b/chromium/content/browser/database_util_unittest.cc
index 50d68952b4a..9534cb98488 100644
--- a/chromium/content/browser/database_util_unittest.cc
+++ b/chromium/content/browser/database_util_unittest.cc
@@ -29,17 +29,6 @@ static void TestVfsFilePath(bool expected_result,
EXPECT_EQ(ASCIIToUTF16(expected_sqlite_suffix), sqlite_suffix);
}
-static GURL ToAndFromOriginIdentifier(const GURL origin_url) {
- std::string id = storage::GetIdentifierFromOrigin(origin_url);
- return storage::GetOriginFromIdentifier(id);
-}
-
-static void TestValidOriginIdentifier(bool expected_result,
- const std::string& id) {
- EXPECT_EQ(expected_result,
- DatabaseUtil::IsValidOriginIdentifier(id));
-}
-
namespace content {
// Test DatabaseUtil::CrackVfsFilePath on various inputs.
@@ -59,21 +48,5 @@ TEST(DatabaseUtilTest, CrackVfsFilePathTest) {
TestVfsFilePath(false, "/db_name#suffix");
}
-TEST(DatabaseUtilTest, OriginIdentifiers) {
- const GURL kFileOrigin(GURL("file:///").GetOrigin());
- const GURL kHttpOrigin(GURL("http://bar/").GetOrigin());
- EXPECT_EQ(kFileOrigin, ToAndFromOriginIdentifier(kFileOrigin));
- EXPECT_EQ(kHttpOrigin, ToAndFromOriginIdentifier(kHttpOrigin));
-}
-
-TEST(DatabaseUtilTest, IsValidOriginIdentifier) {
- TestValidOriginIdentifier(true, "http_bar_0");
- TestValidOriginIdentifier(false, "");
- TestValidOriginIdentifier(false, "bad..id");
- TestValidOriginIdentifier(false, "bad/id");
- TestValidOriginIdentifier(false, "bad\\id");
- TestValidOriginIdentifier(false, "http_bad:0_2");
- TestValidOriginIdentifier(false, std::string("bad\0id", 6));
-}
} // namespace content
diff --git a/chromium/content/browser/device_monitor_mac.h b/chromium/content/browser/device_monitor_mac.h
deleted file mode 100644
index 05eab158db8..00000000000
--- a/chromium/content/browser/device_monitor_mac.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
-#define CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
-
-#include "base/macros.h"
-#include "base/system_monitor/system_monitor.h"
-#include "base/threading/thread_checker.h"
-
-namespace {
-class DeviceMonitorMacImpl;
-}
-
-namespace content {
-
-// Class to track audio/video devices removal or addition via callback to
-// base::SystemMonitor ProcessDevicesChanged(). A single object of this class
-// is created from the browser main process and lives as long as this one.
-class DeviceMonitorMac {
- public:
- DeviceMonitorMac();
- ~DeviceMonitorMac();
-
- // Registers the observers for the audio/video device removal, connection and
- // suspension. The AVFoundation library is also loaded and initialised if the
- // OS supports it. The |device_task_runner| argument represents the thread on
- // which device enumeration will occur.
- void StartMonitoring(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
-
- // Method called by the internal DeviceMonitorMacImpl object
- // |device_monitor_impl_| when a device of type |type| has been added to or
- // removed from the system. This code executes in the notification thread
- // (QTKit or AVFoundation).
- void NotifyDeviceChanged(base::SystemMonitor::DeviceType type);
-
- private:
- scoped_ptr<DeviceMonitorMacImpl> device_monitor_impl_;
-
- // |thread_checker_| is used to check that constructor and StartMonitoring()
- // are called in the correct thread, the UI thread, that also owns the object.
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMac);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
diff --git a/chromium/content/browser/device_monitor_mac.mm b/chromium/content/browser/device_monitor_mac.mm
deleted file mode 100644
index 248b99dceda..00000000000
--- a/chromium/content/browser/device_monitor_mac.mm
+++ /dev/null
@@ -1,568 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/device_monitor_mac.h"
-
-#import <QTKit/QTKit.h>
-
-#include <set>
-
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/mac/bind_objc_block.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/threading/thread_checker.h"
-#include "content/public/browser/browser_thread.h"
-#import "media/base/mac/avfoundation_glue.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// This class is used to keep track of system devices names and their types.
-class DeviceInfo {
- public:
- enum DeviceType {
- kAudio,
- kVideo,
- kMuxed,
- kUnknown,
- kInvalid
- };
-
- DeviceInfo(const std::string& unique_id, DeviceType type)
- : unique_id_(unique_id), type_(type) {}
-
- // Operator== is needed here to use this class in a std::find. A given
- // |unique_id_| always has the same |type_| so for comparison purposes the
- // latter can be safely ignored.
- bool operator==(const DeviceInfo& device) const {
- return unique_id_ == device.unique_id_;
- }
-
- const std::string& unique_id() const { return unique_id_; }
- DeviceType type() const { return type_; }
-
- private:
- std::string unique_id_;
- DeviceType type_;
- // Allow generated copy constructor and assignment.
-};
-
-// Base abstract class used by DeviceMonitorMac to interact with either a QTKit
-// or an AVFoundation implementation of events and notifications.
-class DeviceMonitorMacImpl {
- public:
- explicit DeviceMonitorMacImpl(content::DeviceMonitorMac* monitor)
- : monitor_(monitor),
- cached_devices_(),
- device_arrival_(nil),
- device_removal_(nil) {
- DCHECK(monitor);
- // Initialise the devices_cache_ with a not-valid entry. For the case in
- // which there is one single device in the system and we get notified when
- // it gets removed, this will prevent the system from thinking that no
- // devices were added nor removed and not notifying the |monitor_|.
- cached_devices_.push_back(DeviceInfo("invalid", DeviceInfo::kInvalid));
- }
- virtual ~DeviceMonitorMacImpl() {}
-
- virtual void OnDeviceChanged() = 0;
-
- // Method called by the default notification center when a device is removed
- // or added to the system. It will compare the |cached_devices_| with the
- // current situation, update it, and, if there's an update, signal to
- // |monitor_| with the appropriate device type.
- void ConsolidateDevicesListAndNotify(
- const std::vector<DeviceInfo>& snapshot_devices);
-
- protected:
- content::DeviceMonitorMac* monitor_;
- std::vector<DeviceInfo> cached_devices_;
-
- // Handles to NSNotificationCenter block observers.
- id device_arrival_;
- id device_removal_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl);
-};
-
-void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
- const std::vector<DeviceInfo>& snapshot_devices) {
- bool video_device_added = false;
- bool audio_device_added = false;
- bool video_device_removed = false;
- bool audio_device_removed = false;
-
- // Compare the current system devices snapshot with the ones cached to detect
- // additions, present in the former but not in the latter. If we find a device
- // in snapshot_devices entry also present in cached_devices, we remove it from
- // the latter vector.
- std::vector<DeviceInfo>::const_iterator it;
- for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) {
- std::vector<DeviceInfo>::iterator cached_devices_iterator =
- std::find(cached_devices_.begin(), cached_devices_.end(), *it);
- if (cached_devices_iterator == cached_devices_.end()) {
- video_device_added |= ((it->type() == DeviceInfo::kVideo) ||
- (it->type() == DeviceInfo::kMuxed));
- audio_device_added |= ((it->type() == DeviceInfo::kAudio) ||
- (it->type() == DeviceInfo::kMuxed));
- DVLOG(1) << "Device has been added, id: " << it->unique_id();
- } else {
- cached_devices_.erase(cached_devices_iterator);
- }
- }
- // All the remaining entries in cached_devices are removed devices.
- for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) {
- video_device_removed |= ((it->type() == DeviceInfo::kVideo) ||
- (it->type() == DeviceInfo::kMuxed) ||
- (it->type() == DeviceInfo::kInvalid));
- audio_device_removed |= ((it->type() == DeviceInfo::kAudio) ||
- (it->type() == DeviceInfo::kMuxed) ||
- (it->type() == DeviceInfo::kInvalid));
- DVLOG(1) << "Device has been removed, id: " << it->unique_id();
- }
- // Update the cached devices with the current system snapshot.
- cached_devices_ = snapshot_devices;
-
- if (video_device_added || video_device_removed)
- monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
- if (audio_device_added || audio_device_removed)
- monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE);
-}
-
-class QTKitMonitorImpl : public DeviceMonitorMacImpl {
- public:
- explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
- ~QTKitMonitorImpl() override;
-
- void OnDeviceChanged() override;
-
- private:
- void CountDevices();
- void OnAttributeChanged(NSNotification* notification);
-
- id device_change_;
-};
-
-QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
- : DeviceMonitorMacImpl(monitor) {
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- device_arrival_ =
- [nc addObserverForName:QTCaptureDeviceWasConnectedNotification
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
- device_removal_ =
- [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
- device_change_ =
- [nc addObserverForName:QTCaptureDeviceAttributeDidChangeNotification
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnAttributeChanged(notification);}];
-}
-
-QTKitMonitorImpl::~QTKitMonitorImpl() {
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- [nc removeObserver:device_arrival_];
- [nc removeObserver:device_removal_];
- [nc removeObserver:device_change_];
-}
-
-void QTKitMonitorImpl::OnAttributeChanged(
- NSNotification* notification) {
- if ([[[notification userInfo]
- objectForKey:QTCaptureDeviceChangedAttributeKey]
- isEqualToString:QTCaptureDeviceSuspendedAttribute]) {
- OnDeviceChanged();
- }
-}
-
-void QTKitMonitorImpl::OnDeviceChanged() {
- std::vector<DeviceInfo> snapshot_devices;
-
- NSArray* devices = [QTCaptureDevice inputDevices];
- for (QTCaptureDevice* device in devices) {
- DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
- // Act as if suspended video capture devices are not attached. For
- // example, a laptop's internal webcam is suspended when the lid is closed.
- if ([device hasMediaType:QTMediaTypeVideo] &&
- ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
- boolValue]) {
- device_type = DeviceInfo::kVideo;
- } else if ([device hasMediaType:QTMediaTypeMuxed] &&
- ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
- boolValue]) {
- device_type = DeviceInfo::kMuxed;
- } else if ([device hasMediaType:QTMediaTypeSound] &&
- ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
- boolValue]) {
- device_type = DeviceInfo::kAudio;
- }
- snapshot_devices.push_back(
- DeviceInfo([[device uniqueID] UTF8String], device_type));
- }
- ConsolidateDevicesListAndNotify(snapshot_devices);
-}
-
-// Forward declaration for use by CrAVFoundationDeviceObserver.
-class SuspendObserverDelegate;
-
-} // namespace
-
-// This class is a Key-Value Observer (KVO) shim. It is needed because C++
-// classes cannot observe Key-Values directly. Created, manipulated, and
-// destroyed on the UI Thread by SuspendObserverDelegate.
-@interface CrAVFoundationDeviceObserver : NSObject {
- @private
- // Callback for device changed, has to run on Device Thread.
- base::Closure onDeviceChangedCallback_;
-
- // Member to keep track of the devices we are already monitoring.
- std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_;
-}
-
-- (id)initWithOnChangedCallback:(const base::Closure&)callback;
-- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device;
-- (void)stopObserving:(CrAVCaptureDevice*)device;
-- (void)clearOnDeviceChangedCallback;
-
-@end
-
-namespace {
-
-// This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
-// It is created and destroyed in UI thread by AVFoundationMonitorImpl, and it
-// operates on this thread except for the expensive device enumerations which
-// are run on Device Thread.
-class SuspendObserverDelegate :
- public base::RefCountedThreadSafe<SuspendObserverDelegate> {
- public:
- explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor);
-
- // Create |suspend_observer_| for all devices and register OnDeviceChanged()
- // as its change callback. Schedule bottom half in DoStartObserver().
- void StartObserver(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
- // Enumerate devices in |device_thread| and run the bottom half in
- // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event,
- // and our parent AVFoundationMonitorImpl calls on connect/disconnect device.
- void OnDeviceChanged(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_thread);
- // Remove the device monitor's weak reference. Remove ourselves as suspend
- // notification observer from |suspend_observer_|.
- void ResetDeviceMonitor();
-
- private:
- friend class base::RefCountedThreadSafe<SuspendObserverDelegate>;
-
- virtual ~SuspendObserverDelegate();
-
- // Bottom half of StartObserver(), starts |suspend_observer_| for all devices.
- // Assumes that |devices| has been retained prior to being called, and
- // releases it internally.
- void DoStartObserver(NSArray* devices);
- // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current
- // devices and composes a snapshot of them to send it to
- // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained
- // prior to being called, and releases it internally.
- void DoOnDeviceChanged(NSArray* devices);
-
- base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
- DeviceMonitorMacImpl* avfoundation_monitor_impl_;
-};
-
-SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
- : avfoundation_monitor_impl_(monitor) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void SuspendObserverDelegate::StartObserver(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- base::Closure on_device_changed_callback =
- base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
- this, device_thread);
- suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
- initWithOnChangedCallback:on_device_changed_callback]);
-
- // Enumerate the devices in Device thread and post the observers start to be
- // done on UI thread. The devices array is retained in |device_thread| and
- // released in DoStartObserver().
- base::PostTaskAndReplyWithResult(
- device_thread.get(),
- FROM_HERE,
- base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
- base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
-}
-
-void SuspendObserverDelegate::OnDeviceChanged(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Enumerate the devices in Device thread and post the consolidation of the
- // new devices and the old ones to be done on UI thread. The devices array
- // is retained in |device_thread| and released in DoOnDeviceChanged().
- PostTaskAndReplyWithResult(
- device_thread.get(),
- FROM_HERE,
- base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
- base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
-}
-
-void SuspendObserverDelegate::ResetDeviceMonitor() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- avfoundation_monitor_impl_ = NULL;
- [suspend_observer_ clearOnDeviceChangedCallback];
-}
-
-SuspendObserverDelegate::~SuspendObserverDelegate() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- base::scoped_nsobject<NSArray> auto_release(devices);
- for (CrAVCaptureDevice* device in devices) {
- base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
- [suspend_observer_ startObserving:device_ptr];
- }
-}
-
-void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- base::scoped_nsobject<NSArray> auto_release(devices);
- std::vector<DeviceInfo> snapshot_devices;
- for (CrAVCaptureDevice* device in devices) {
- base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
- [suspend_observer_ startObserving:device_ptr];
-
- BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
- [device isSuspended];
- DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
- if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
- if (suspended)
- continue;
- device_type = DeviceInfo::kVideo;
- } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) {
- device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed;
- } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
- device_type = DeviceInfo::kAudio;
- }
- snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
- device_type));
- }
- // Make sure no references are held to |devices| when
- // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager
- // and AudioCaptureManagers also enumerates the available devices but on
- // another thread.
- auto_release.reset();
- // |avfoundation_monitor_impl_| might have been NULLed asynchronously before
- // arriving at this line.
- if (avfoundation_monitor_impl_) {
- avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify(
- snapshot_devices);
- }
-}
-
-// AVFoundation implementation of the Mac Device Monitor, registers as a global
-// device connect/disconnect observer and plugs suspend/wake up device observers
-// per device. This class is created and lives in UI thread. Owns a
-// SuspendObserverDelegate that notifies when a device is suspended/resumed.
-class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
- public:
- AVFoundationMonitorImpl(
- content::DeviceMonitorMac* monitor,
- const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
- ~AVFoundationMonitorImpl() override;
-
- void OnDeviceChanged() override;
-
- private:
- // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
- // posting tasks to |suspend_observer_delegate_|; valid after
- // MediaStreamManager calls StartMonitoring().
- const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
-
- scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
-};
-
-AVFoundationMonitorImpl::AVFoundationMonitorImpl(
- content::DeviceMonitorMac* monitor,
- const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
- : DeviceMonitorMacImpl(monitor),
- device_task_runner_(device_task_runner),
- suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- device_arrival_ =
- [nc addObserverForName:AVFoundationGlue::
- AVCaptureDeviceWasConnectedNotification()
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
- device_removal_ =
- [nc addObserverForName:AVFoundationGlue::
- AVCaptureDeviceWasDisconnectedNotification()
- object:nil
- queue:nil
- usingBlock:^(NSNotification* notification) {
- OnDeviceChanged();}];
- suspend_observer_delegate_->StartObserver(device_task_runner_);
-}
-
-AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- suspend_observer_delegate_->ResetDeviceMonitor();
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- [nc removeObserver:device_arrival_];
- [nc removeObserver:device_removal_];
-}
-
-void AVFoundationMonitorImpl::OnDeviceChanged() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
-}
-
-} // namespace
-
-@implementation CrAVFoundationDeviceObserver
-
-- (id)initWithOnChangedCallback:(const base::Closure&)callback {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if ((self = [super init])) {
- DCHECK(!callback.is_null());
- onDeviceChangedCallback_ = callback;
- }
- return self;
-}
-
-- (void)dealloc {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
- monitoredDevices_.begin();
- while (it != monitoredDevices_.end())
- [self removeObservers:*(it++)];
- [super dealloc];
-}
-
-- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(device != nil);
- // Skip this device if there are already observers connected to it.
- if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
- monitoredDevices_.end()) {
- return;
- }
- [device addObserver:self
- forKeyPath:@"suspended"
- options:0
- context:device.get()];
- [device addObserver:self
- forKeyPath:@"connected"
- options:0
- context:device.get()];
- monitoredDevices_.insert(device);
-}
-
-- (void)stopObserving:(CrAVCaptureDevice*)device {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(device != nil);
-
- std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
- std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
- DCHECK(found != monitoredDevices_.end());
- [self removeObservers:*found];
- monitoredDevices_.erase(found);
-}
-
-- (void)clearOnDeviceChangedCallback {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- onDeviceChangedCallback_.Reset();
-}
-
-- (void)removeObservers:(CrAVCaptureDevice*)device {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
- if ([device observationInfo]) {
- [device removeObserver:self
- forKeyPath:@"suspended"];
- [device removeObserver:self
- forKeyPath:@"connected"];
- }
-}
-
-- (void)observeValueForKeyPath:(NSString*)keyPath
- ofObject:(id)object
- change:(NSDictionary*)change
- context:(void*)context {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if ([keyPath isEqual:@"suspended"])
- onDeviceChangedCallback_.Run();
- if ([keyPath isEqual:@"connected"])
- [self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
-}
-
-@end // @implementation CrAVFoundationDeviceObserver
-
-namespace content {
-
-DeviceMonitorMac::DeviceMonitorMac() {
- // Both QTKit and AVFoundation do not need to be fired up until the user
- // exercises a GetUserMedia. Bringing up either library and enumerating the
- // devices in the system is an operation taking in the range of hundred of ms,
- // so it is triggered explicitly from MediaStreamManager::StartMonitoring().
-}
-
-DeviceMonitorMac::~DeviceMonitorMac() {}
-
-void DeviceMonitorMac::StartMonitoring(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // We're on the UI thread so let's try to initialize AVFoundation and then
- // see if it's supported. IsAVFoundationSupported can't implicitly initialize
- // the library since it can be called on different threads.
- AVFoundationGlue::InitializeAVFoundation();
-
- if (AVFoundationGlue::IsAVFoundationSupported()) {
- // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
- // is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "458404 DeviceMonitorMac::StartMonitoring::AVFoundation"));
- DVLOG(1) << "Monitoring via AVFoundation";
- device_monitor_impl_.reset(new AVFoundationMonitorImpl(this,
- device_task_runner));
- } else {
- // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
- // is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "458404 DeviceMonitorMac::StartMonitoring::QTKit"));
- DVLOG(1) << "Monitoring via QTKit";
- device_monitor_impl_.reset(new QTKitMonitorImpl(this));
- }
-}
-
-void DeviceMonitorMac::NotifyDeviceChanged(
- base::SystemMonitor::DeviceType type) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // TODO(xians): Remove the global variable for SystemMonitor.
- base::SystemMonitor::Get()->ProcessDevicesChanged(type);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/device_monitor_udev.cc b/chromium/content/browser/device_monitor_udev.cc
deleted file mode 100644
index 822e995f47c..00000000000
--- a/chromium/content/browser/device_monitor_udev.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// libudev is used for monitoring device changes.
-
-#include "content/browser/device_monitor_udev.h"
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/system_monitor/system_monitor.h"
-#include "content/browser/udev_linux.h"
-#include "content/public/browser/browser_thread.h"
-#include "device/udev_linux/udev.h"
-
-namespace {
-
-struct SubsystemMap {
- base::SystemMonitor::DeviceType device_type;
- const char* subsystem;
- const char* devtype;
-};
-
-const char kAudioSubsystem[] = "sound";
-const char kVideoSubsystem[] = "video4linux";
-
-// Add more subsystems here for monitoring.
-const SubsystemMap kSubsystemMap[] = {
- { base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kAudioSubsystem, NULL },
- { base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kVideoSubsystem, NULL },
-};
-
-} // namespace
-
-namespace content {
-
-DeviceMonitorLinux::DeviceMonitorLinux() {
- DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&DeviceMonitorLinux::Initialize, base::Unretained(this)));
-}
-
-DeviceMonitorLinux::~DeviceMonitorLinux() {
-}
-
-void DeviceMonitorLinux::Initialize() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // We want to be notified of IO message loop destruction to delete |udev_|.
- base::MessageLoop::current()->AddDestructionObserver(this);
-
- std::vector<UdevLinux::UdevMonitorFilter> filters;
- for (size_t i = 0; i < arraysize(kSubsystemMap); ++i) {
- filters.push_back(UdevLinux::UdevMonitorFilter(
- kSubsystemMap[i].subsystem, kSubsystemMap[i].devtype));
- }
- udev_.reset(new UdevLinux(filters,
- base::Bind(&DeviceMonitorLinux::OnDevicesChanged,
- base::Unretained(this))));
-}
-
-void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() {
- // Called on IO thread.
- udev_.reset();
-}
-
-void DeviceMonitorLinux::OnDevicesChanged(udev_device* device) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(device);
-
- base::SystemMonitor::DeviceType device_type =
- base::SystemMonitor::DEVTYPE_UNKNOWN;
- std::string subsystem(device::udev_device_get_subsystem(device));
- for (size_t i = 0; i < arraysize(kSubsystemMap); ++i) {
- if (subsystem == kSubsystemMap[i].subsystem) {
- device_type = kSubsystemMap[i].device_type;
- break;
- }
- }
- DCHECK_NE(device_type, base::SystemMonitor::DEVTYPE_UNKNOWN);
-
- base::SystemMonitor::Get()->ProcessDevicesChanged(device_type);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/device_monitor_udev.h b/chromium/content/browser/device_monitor_udev.h
deleted file mode 100644
index 965055d93b2..00000000000
--- a/chromium/content/browser/device_monitor_udev.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This class is used to detect device change and notify base::SystemMonitor
-// on Linux.
-
-#ifndef CONTENT_BROWSER_DEVICE_MONITOR_UDEV_H_
-#define CONTENT_BROWSER_DEVICE_MONITOR_UDEV_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-
-extern "C" {
-struct udev_device;
-}
-
-namespace content {
-
-class UdevLinux;
-
-class DeviceMonitorLinux : public base::MessageLoop::DestructionObserver {
- public:
- DeviceMonitorLinux();
- ~DeviceMonitorLinux() override;
-
- private:
- // This object is deleted on the UI thread after the IO thread has been
- // destroyed. Need to know when IO thread is being destroyed so that
- // we can delete udev_.
- void WillDestroyCurrentMessageLoop() override;
-
- void Initialize();
- void OnDevicesChanged(udev_device* device);
-
- scoped_ptr<UdevLinux> udev_;
-
- DISALLOW_COPY_AND_ASSIGN(DeviceMonitorLinux);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVICE_MONITOR_UDEV_H_
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
index a9ab2ff1dc2..c8b37986c7d 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
@@ -194,7 +194,6 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
// On Mac we cannot provide absolute orientation.
orientation_buffer_->seqlock.WriteBegin();
orientation_buffer_->data.absolute = false;
- orientation_buffer_->data.hasAbsolute = true;
orientation_buffer_->seqlock.WriteEnd();
} else {
// No motion sensor available, fire an all-null event.
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc
index 709c25b595c..40471ca0a3b 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc
@@ -129,8 +129,7 @@ class DataFetcherSharedMemory::SensorEventSinkOrientation
buffer_->data.hasBeta = has_beta;
buffer_->data.gamma = gamma;
buffer_->data.hasGamma = has_gamma;
- buffer_->data.absolute = true;
- buffer_->data.hasAbsolute = has_alpha || has_beta || has_gamma;
+ buffer_->data.absolute = has_alpha || has_beta || has_gamma;
buffer_->data.allAvailableSensorsAreActive = true;
buffer_->seqlock.WriteEnd();
}
diff --git a/chromium/content/browser/device_sensors/device_light_message_filter.cc b/chromium/content/browser/device_sensors/device_light_message_filter.cc
index 797b3eade2c..dda05a86aa8 100644
--- a/chromium/content/browser/device_sensors/device_light_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_light_message_filter.cc
@@ -4,57 +4,28 @@
#include "content/browser/device_sensors/device_light_message_filter.h"
-#include "content/browser/device_sensors/device_inertial_sensor_service.h"
#include "content/common/device_sensors/device_light_messages.h"
namespace content {
DeviceLightMessageFilter::DeviceLightMessageFilter()
- : BrowserMessageFilter(DeviceLightMsgStart), is_started_(false) {
-}
+ : DeviceSensorMessageFilter(CONSUMER_TYPE_LIGHT, DeviceLightMsgStart) {}
-DeviceLightMessageFilter::~DeviceLightMessageFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (is_started_) {
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_LIGHT);
- }
-}
+DeviceLightMessageFilter::~DeviceLightMessageFilter() {}
bool DeviceLightMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DeviceLightMessageFilter, message)
- IPC_MESSAGE_HANDLER(DeviceLightHostMsg_StartPolling,
- OnDeviceLightStartPolling)
- IPC_MESSAGE_HANDLER(DeviceLightHostMsg_StopPolling, OnDeviceLightStopPolling)
+ IPC_MESSAGE_HANDLER(DeviceLightHostMsg_StartPolling, OnStartPolling)
+ IPC_MESSAGE_HANDLER(DeviceLightHostMsg_StopPolling, OnStopPolling)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void DeviceLightMessageFilter::OnDeviceLightStartPolling() {
- DCHECK(!is_started_);
- if (is_started_)
- return;
- is_started_ = true;
- DeviceInertialSensorService::GetInstance()->AddConsumer(CONSUMER_TYPE_LIGHT);
- DidStartDeviceLightPolling();
-}
-
-void DeviceLightMessageFilter::OnDeviceLightStopPolling() {
- DCHECK(is_started_);
- if (!is_started_)
- return;
- is_started_ = false;
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_LIGHT);
-}
-
-void DeviceLightMessageFilter::DidStartDeviceLightPolling() {
- Send(new DeviceLightMsg_DidStartPolling(
- DeviceInertialSensorService::GetInstance()
- ->GetSharedMemoryHandleForProcess(CONSUMER_TYPE_LIGHT,
- PeerHandle())));
+void DeviceLightMessageFilter::DidStartPolling(
+ base::SharedMemoryHandle handle) {
+ Send(new DeviceLightMsg_DidStartPolling(handle));
}
} // namespace content
diff --git a/chromium/content/browser/device_sensors/device_light_message_filter.h b/chromium/content/browser/device_sensors/device_light_message_filter.h
index 58246935a7e..bf302b7dd5a 100644
--- a/chromium/content/browser/device_sensors/device_light_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_light_message_filter.h
@@ -5,12 +5,11 @@
#ifndef CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_LIGHT_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_LIGHT_MESSAGE_FILTER_H_
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
+#include "content/browser/device_sensors/device_sensor_message_filter.h"
namespace content {
-class DeviceLightMessageFilter : public BrowserMessageFilter {
+class DeviceLightMessageFilter : public DeviceSensorMessageFilter {
public:
DeviceLightMessageFilter();
@@ -20,11 +19,8 @@ class DeviceLightMessageFilter : public BrowserMessageFilter {
private:
~DeviceLightMessageFilter() override;
- void OnDeviceLightStartPolling();
- void OnDeviceLightStopPolling();
- void DidStartDeviceLightPolling();
-
- bool is_started_;
+ // DeviceSensorMessageFilter implementation.
+ void DidStartPolling(base::SharedMemoryHandle handle) override;
DISALLOW_COPY_AND_ASSIGN(DeviceLightMessageFilter);
};
diff --git a/chromium/content/browser/device_sensors/device_motion_message_filter.cc b/chromium/content/browser/device_sensors/device_motion_message_filter.cc
index f874ea493a4..58a2b514b5b 100644
--- a/chromium/content/browser/device_sensors/device_motion_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_motion_message_filter.cc
@@ -4,59 +4,28 @@
#include "content/browser/device_sensors/device_motion_message_filter.h"
-#include "content/browser/device_sensors/device_inertial_sensor_service.h"
#include "content/common/device_sensors/device_motion_messages.h"
namespace content {
DeviceMotionMessageFilter::DeviceMotionMessageFilter()
- : BrowserMessageFilter(DeviceMotionMsgStart),
- is_started_(false) {
-}
+ : DeviceSensorMessageFilter(CONSUMER_TYPE_MOTION, DeviceMotionMsgStart) {}
-DeviceMotionMessageFilter::~DeviceMotionMessageFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (is_started_)
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_MOTION);
-}
+DeviceMotionMessageFilter::~DeviceMotionMessageFilter() {}
bool DeviceMotionMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DeviceMotionMessageFilter, message)
- IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StartPolling,
- OnDeviceMotionStartPolling)
- IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StopPolling,
- OnDeviceMotionStopPolling)
+ IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StartPolling, OnStartPolling)
+ IPC_MESSAGE_HANDLER(DeviceMotionHostMsg_StopPolling, OnStopPolling)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void DeviceMotionMessageFilter::OnDeviceMotionStartPolling() {
- DCHECK(!is_started_);
- if (is_started_)
- return;
- is_started_ = true;
- DeviceInertialSensorService::GetInstance()->AddConsumer(
- CONSUMER_TYPE_MOTION);
- DidStartDeviceMotionPolling();
-}
-
-void DeviceMotionMessageFilter::OnDeviceMotionStopPolling() {
- DCHECK(is_started_);
- if (!is_started_)
- return;
- is_started_ = false;
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_MOTION);
-}
-
-void DeviceMotionMessageFilter::DidStartDeviceMotionPolling() {
- Send(new DeviceMotionMsg_DidStartPolling(
- DeviceInertialSensorService::GetInstance()->
- GetSharedMemoryHandleForProcess(
- CONSUMER_TYPE_MOTION, PeerHandle())));
+void DeviceMotionMessageFilter::DidStartPolling(
+ base::SharedMemoryHandle handle) {
+ Send(new DeviceMotionMsg_DidStartPolling(handle));
}
} // namespace content
diff --git a/chromium/content/browser/device_sensors/device_motion_message_filter.h b/chromium/content/browser/device_sensors/device_motion_message_filter.h
index 36eb42aa127..3b0587d15da 100644
--- a/chromium/content/browser/device_sensors/device_motion_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_motion_message_filter.h
@@ -5,12 +5,11 @@
#ifndef CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_MOTION_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_MOTION_MESSAGE_FILTER_H_
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
+#include "content/browser/device_sensors/device_sensor_message_filter.h"
namespace content {
-class DeviceMotionMessageFilter : public BrowserMessageFilter {
+class DeviceMotionMessageFilter : public DeviceSensorMessageFilter {
public:
DeviceMotionMessageFilter();
@@ -20,11 +19,8 @@ class DeviceMotionMessageFilter : public BrowserMessageFilter {
private:
~DeviceMotionMessageFilter() override;
- void OnDeviceMotionStartPolling();
- void OnDeviceMotionStopPolling();
- void DidStartDeviceMotionPolling();
-
- bool is_started_;
+ // DeviceSensorMessageFilter implementation.
+ void DidStartPolling(base::SharedMemoryHandle handle) override;
DISALLOW_COPY_AND_ASSIGN(DeviceMotionMessageFilter);
};
diff --git a/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.cc b/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.cc
index 572952cea11..3aa6042e429 100644
--- a/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.cc
@@ -4,24 +4,16 @@
#include "content/browser/device_sensors/device_orientation_absolute_message_filter.h"
-#include "content/browser/device_sensors/device_inertial_sensor_service.h"
#include "content/common/device_sensors/device_orientation_messages.h"
namespace content {
DeviceOrientationAbsoluteMessageFilter::DeviceOrientationAbsoluteMessageFilter()
- : BrowserMessageFilter(DeviceOrientationMsgStart),
- is_started_(false) {
-}
+ : DeviceSensorMessageFilter(CONSUMER_TYPE_ORIENTATION_ABSOLUTE,
+ DeviceOrientationMsgStart) {}
DeviceOrientationAbsoluteMessageFilter::
- ~DeviceOrientationAbsoluteMessageFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (is_started_) {
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_ORIENTATION_ABSOLUTE);
- }
-}
+ ~DeviceOrientationAbsoluteMessageFilter() {}
bool DeviceOrientationAbsoluteMessageFilter::OnMessageReceived(
const IPC::Message& message) {
@@ -36,31 +28,9 @@ bool DeviceOrientationAbsoluteMessageFilter::OnMessageReceived(
return handled;
}
-void DeviceOrientationAbsoluteMessageFilter::OnStartPolling() {
- DCHECK(!is_started_);
- if (is_started_)
- return;
- is_started_ = true;
- DeviceInertialSensorService::GetInstance()->AddConsumer(
- CONSUMER_TYPE_ORIENTATION_ABSOLUTE);
- DidStartPolling();
-}
-
-void DeviceOrientationAbsoluteMessageFilter::OnStopPolling() {
- DCHECK(is_started_);
- if (!is_started_)
- return;
- is_started_ = false;
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_ORIENTATION_ABSOLUTE);
-}
-
-void DeviceOrientationAbsoluteMessageFilter::DidStartPolling() {
- Send(new DeviceOrientationAbsoluteMsg_DidStartPolling(
- DeviceInertialSensorService::GetInstance()->
- GetSharedMemoryHandleForProcess(
- CONSUMER_TYPE_ORIENTATION_ABSOLUTE,
- PeerHandle())));
+void DeviceOrientationAbsoluteMessageFilter::DidStartPolling(
+ base::SharedMemoryHandle handle) {
+ Send(new DeviceOrientationAbsoluteMsg_DidStartPolling(handle));
}
} // namespace content
diff --git a/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.h b/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.h
index 5ed5ac5467e..5e64bf8fe73 100644
--- a/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_orientation_absolute_message_filter.h
@@ -5,12 +5,12 @@
#ifndef CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_ORIENTATION_ABSOLUTE_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_ORIENTATION_ABSOLUTE_MESSAGE_FILTER_H_
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
+#include "content/browser/device_sensors/device_sensor_message_filter.h"
namespace content {
-class DeviceOrientationAbsoluteMessageFilter : public BrowserMessageFilter {
+class DeviceOrientationAbsoluteMessageFilter
+ : public DeviceSensorMessageFilter {
public:
DeviceOrientationAbsoluteMessageFilter();
@@ -20,11 +20,8 @@ class DeviceOrientationAbsoluteMessageFilter : public BrowserMessageFilter {
private:
~DeviceOrientationAbsoluteMessageFilter() override;
- void OnStartPolling();
- void OnStopPolling();
- void DidStartPolling();
-
- bool is_started_;
+ // DeviceSensorMessageFilter implementation.
+ void DidStartPolling(base::SharedMemoryHandle handle) override;
DISALLOW_COPY_AND_ASSIGN(DeviceOrientationAbsoluteMessageFilter);
};
diff --git a/chromium/content/browser/device_sensors/device_orientation_message_filter.cc b/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
index 63a9d6230f4..9b0aeb8b13a 100644
--- a/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
+++ b/chromium/content/browser/device_sensors/device_orientation_message_filter.cc
@@ -4,61 +4,30 @@
#include "content/browser/device_sensors/device_orientation_message_filter.h"
-#include "content/browser/device_sensors/device_inertial_sensor_service.h"
#include "content/common/device_sensors/device_orientation_messages.h"
namespace content {
DeviceOrientationMessageFilter::DeviceOrientationMessageFilter()
- : BrowserMessageFilter(DeviceOrientationMsgStart),
- is_started_(false) {
-}
+ : DeviceSensorMessageFilter(CONSUMER_TYPE_ORIENTATION,
+ DeviceOrientationMsgStart) {}
-DeviceOrientationMessageFilter::~DeviceOrientationMessageFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (is_started_)
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_ORIENTATION);
-}
+DeviceOrientationMessageFilter::~DeviceOrientationMessageFilter() {}
bool DeviceOrientationMessageFilter::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DeviceOrientationMessageFilter, message)
- IPC_MESSAGE_HANDLER(DeviceOrientationHostMsg_StartPolling,
- OnDeviceOrientationStartPolling)
- IPC_MESSAGE_HANDLER(DeviceOrientationHostMsg_StopPolling,
- OnDeviceOrientationStopPolling)
+ IPC_MESSAGE_HANDLER(DeviceOrientationHostMsg_StartPolling, OnStartPolling)
+ IPC_MESSAGE_HANDLER(DeviceOrientationHostMsg_StopPolling, OnStopPolling)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void DeviceOrientationMessageFilter::OnDeviceOrientationStartPolling() {
- DCHECK(!is_started_);
- if (is_started_)
- return;
- is_started_ = true;
- DeviceInertialSensorService::GetInstance()->AddConsumer(
- CONSUMER_TYPE_ORIENTATION);
- DidStartDeviceOrientationPolling();
-}
-
-void DeviceOrientationMessageFilter::OnDeviceOrientationStopPolling() {
- DCHECK(is_started_);
- if (!is_started_)
- return;
- is_started_ = false;
- DeviceInertialSensorService::GetInstance()->RemoveConsumer(
- CONSUMER_TYPE_ORIENTATION);
-}
-
-void DeviceOrientationMessageFilter::DidStartDeviceOrientationPolling() {
- Send(new DeviceOrientationMsg_DidStartPolling(
- DeviceInertialSensorService::GetInstance()->
- GetSharedMemoryHandleForProcess(
- CONSUMER_TYPE_ORIENTATION,
- PeerHandle())));
+void DeviceOrientationMessageFilter::DidStartPolling(
+ base::SharedMemoryHandle handle) {
+ Send(new DeviceOrientationMsg_DidStartPolling(handle));
}
} // namespace content
diff --git a/chromium/content/browser/device_sensors/device_orientation_message_filter.h b/chromium/content/browser/device_sensors/device_orientation_message_filter.h
index fb375d99439..21e445347a7 100644
--- a/chromium/content/browser/device_sensors/device_orientation_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_orientation_message_filter.h
@@ -5,12 +5,11 @@
#ifndef CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
+#include "content/browser/device_sensors/device_sensor_message_filter.h"
namespace content {
-class DeviceOrientationMessageFilter : public BrowserMessageFilter {
+class DeviceOrientationMessageFilter : public DeviceSensorMessageFilter {
public:
DeviceOrientationMessageFilter();
@@ -20,11 +19,8 @@ class DeviceOrientationMessageFilter : public BrowserMessageFilter {
private:
~DeviceOrientationMessageFilter() override;
- void OnDeviceOrientationStartPolling();
- void OnDeviceOrientationStopPolling();
- void DidStartDeviceOrientationPolling();
-
- bool is_started_;
+ // DeviceSensorMessageFilter implementation.
+ void DidStartPolling(base::SharedMemoryHandle handle) override;
DISALLOW_COPY_AND_ASSIGN(DeviceOrientationMessageFilter);
};
diff --git a/chromium/content/browser/device_sensors/device_sensor_message_filter.cc b/chromium/content/browser/device_sensors/device_sensor_message_filter.cc
new file mode 100644
index 00000000000..cb9e9e592a4
--- /dev/null
+++ b/chromium/content/browser/device_sensors/device_sensor_message_filter.cc
@@ -0,0 +1,44 @@
+// 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 "content/browser/device_sensors/device_sensor_message_filter.h"
+
+#include "content/browser/device_sensors/device_inertial_sensor_service.h"
+
+namespace content {
+
+DeviceSensorMessageFilter::DeviceSensorMessageFilter(
+ ConsumerType consumer_type, uint32_t message_class_to_filter)
+ : BrowserMessageFilter(message_class_to_filter),
+ consumer_type_(consumer_type),
+ is_started_(false) {
+}
+
+DeviceSensorMessageFilter::~DeviceSensorMessageFilter() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (is_started_)
+ DeviceInertialSensorService::GetInstance()->RemoveConsumer(consumer_type_);
+}
+
+void DeviceSensorMessageFilter::OnStartPolling() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!is_started_);
+ if (is_started_)
+ return;
+ is_started_ = true;
+ DeviceInertialSensorService::GetInstance()->AddConsumer(consumer_type_);
+ DidStartPolling(DeviceInertialSensorService::GetInstance()->
+ GetSharedMemoryHandleForProcess(consumer_type_, PeerHandle()));
+}
+
+void DeviceSensorMessageFilter::OnStopPolling() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(is_started_);
+ if (!is_started_)
+ return;
+ is_started_ = false;
+ DeviceInertialSensorService::GetInstance()->RemoveConsumer(consumer_type_);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/device_sensors/device_sensor_message_filter.h b/chromium/content/browser/device_sensors/device_sensor_message_filter.h
new file mode 100644
index 00000000000..13d0b0ac3ea
--- /dev/null
+++ b/chromium/content/browser/device_sensors/device_sensor_message_filter.h
@@ -0,0 +1,40 @@
+// 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 CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_SENSOR_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_SENSOR_MESSAGE_FILTER_H_
+
+#include "base/macros.h"
+#include "base/memory/shared_memory.h"
+#include "content/browser/device_sensors/device_sensors_consts.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+
+// A base class for device sensor related message filters.
+class DeviceSensorMessageFilter : public BrowserMessageFilter {
+ public:
+ DeviceSensorMessageFilter(ConsumerType consumer_type,
+ uint32_t message_class_to_filter);
+
+ protected:
+ // All methods below to be called on the IO thread.
+ ~DeviceSensorMessageFilter() override;
+
+ virtual void OnStartPolling();
+ virtual void OnStopPolling();
+ // To be overriden by the subclass in order to send the appropriate message
+ // to the renderer with a handle to shared memory.
+ virtual void DidStartPolling(base::SharedMemoryHandle handle) = 0;
+
+ private:
+ ConsumerType consumer_type_;
+ bool is_started_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceSensorMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_SENSOR_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android.cc b/chromium/content/browser/device_sensors/sensor_manager_android.cc
index e821fb445a4..5fffdd90720 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_android.cc
@@ -41,7 +41,6 @@ void SetOrientationBufferStatus(
bool ready, bool absolute) {
buffer->seqlock.WriteBegin();
buffer->data.absolute = absolute;
- buffer->data.hasAbsolute = ready;
buffer->data.allAvailableSensorsAreActive = ready;
buffer->seqlock.WriteEnd();
}
diff --git a/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc b/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc
index 97dc8fbcbc6..3544749d6e4 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_chromeos.cc
@@ -69,7 +69,6 @@ void SensorManagerChromeOS::StartFetchingDeviceOrientationData(
// No compass information, so we cannot provide absolute orientation.
orientation_buffer_->seqlock.WriteBegin();
orientation_buffer_->data.absolute = false;
- orientation_buffer_->data.hasAbsolute = true;
orientation_buffer_->seqlock.WriteEnd();
if (!motion_buffer_)
diff --git a/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc b/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
index 6d9f77644f7..7693e4d81b4 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
@@ -116,7 +116,6 @@ TEST_F(SensorManagerChromeOSTest, MotionBuffer) {
// buffer.
TEST_F(SensorManagerChromeOSTest, OrientationBuffer) {
DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
- EXPECT_TRUE(buffer->data.hasAbsolute);
EXPECT_FALSE(buffer->data.hasAlpha);
EXPECT_FALSE(buffer->data.hasBeta);
EXPECT_FALSE(buffer->data.hasGamma);
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.cc b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
index d7c342307db..dbc28a60092 100644
--- a/chromium/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
@@ -11,6 +11,7 @@
#include "content/browser/devtools/protocol/system_info_handler.h"
#include "content/browser/devtools/protocol/tethering_handler.h"
#include "content/browser/devtools/protocol/tracing_handler.h"
+#include "content/browser/frame_host/frame_tree_node.h"
namespace content {
@@ -30,7 +31,9 @@ BrowserDevToolsAgentHost::BrowserDevToolsAgentHost(
new devtools::tethering::TetheringHandler(socket_callback,
tethering_task_runner)),
tracing_handler_(new devtools::tracing::TracingHandler(
- devtools::tracing::TracingHandler::Browser, GetIOContext())),
+ devtools::tracing::TracingHandler::Browser,
+ FrameTreeNode::kFrameTreeNodeInvalidId,
+ GetIOContext())),
protocol_handler_(new DevToolsProtocolHandler(this)) {
DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
dispatcher->SetIOHandler(io_handler_.get());
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
index df27d124201..033f2f18bd9 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
@@ -235,10 +235,13 @@ void DevToolsAgentHostImpl::NotifyCallbacks(
(*it)->Run(agent_host, attached);
}
-void DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) {
+bool DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) {
DevToolsManager* manager = DevToolsManager::GetInstance();
- if (manager->delegate())
+ if (manager->delegate()) {
manager->delegate()->Inspect(browser_context, this);
+ return true;
+ }
+ return false;
}
// DevToolsMessageChunkProcessor -----------------------------------------------
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.h b/chromium/content/browser/devtools/devtools_agent_host_impl.h
index f3b06246816..f70ebc5fc97 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h
@@ -35,7 +35,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost,
virtual void Detach() = 0;
// Opens the inspector for this host.
- void Inspect(BrowserContext* browser_context);
+ bool Inspect(BrowserContext* browser_context);
// DevToolsAgentHost implementation.
void AttachClient(DevToolsAgentHostClient* client) override;
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
index 618bbf8517c..d5756385810 100644
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
@@ -78,7 +78,7 @@ void FrameCaptured(base::TimeTicks timestamp, const SkBitmap& bitmap,
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(
TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), "Screenshot", 1,
timestamp.ToInternalValue(),
- scoped_refptr<base::trace_event::ConvertableToTraceFormat>(
+ scoped_ptr<base::trace_event::ConvertableToTraceFormat>(
new TraceableDevToolsScreenshot(bitmap)));
}
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.h b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
index 1d026676cf8..79c6f16145c 100644
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
namespace cc {
diff --git a/chromium/content/browser/devtools/devtools_manager.h b/chromium/content/browser/devtools/devtools_manager.h
index 57b9ea022b3..f803c1331d7 100644
--- a/chromium/content/browser/devtools/devtools_manager.h
+++ b/chromium/content/browser/devtools/devtools_manager.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
#include "content/public/browser/devtools_manager_delegate.h"
diff --git a/chromium/content/browser/devtools/devtools_netlog_observer.cc b/chromium/content/browser/devtools/devtools_netlog_observer.cc
index 24448e330cf..6a2a3c45be0 100644
--- a/chromium/content/browser/devtools/devtools_netlog_observer.cc
+++ b/chromium/content/browser/devtools/devtools_netlog_observer.cc
@@ -138,8 +138,8 @@ void DevToolsNetLogObserver::OnAddURLRequestEntry(
// several http requests (e.g. see http://crbug.com/80157).
info->response_headers.clear();
- for (void* it = NULL;
- response_headers->EnumerateHeaderLines(&it, &name, &value); ) {
+ for (size_t it = 0;
+ response_headers->EnumerateHeaderLines(&it, &name, &value);) {
info->response_headers.push_back(std::make_pair(name, value));
}
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 62f7a35aade..3f471114c64 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -282,7 +282,7 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) {
ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_height) / new_height);
}
-IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeScrollGesture) {
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizeScrollGesture) {
GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
Attach();
@@ -306,7 +306,7 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeScrollGesture) {
ASSERT_EQ(100, scroll_top);
}
-IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeTapGesture) {
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizeTapGesture) {
GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
Attach();
@@ -344,7 +344,9 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
test_url = GetTestUrl("devtools", "navigation.html");
params->SetString("url", test_url.spec());
+ TestNavigationObserver navigation_observer(shell()->web_contents());
SendCommand("Page.navigate", std::move(params), true);
+ navigation_observer.Wait();
bool enough_results = result_ids_.size() >= 2u;
EXPECT_TRUE(enough_results);
@@ -486,4 +488,30 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReloadBlankPage) {
// Should not crash at this point.
}
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, EvaluateInBlankPage) {
+ NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+ Attach();
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetString("expression", "window");
+ SendCommand("Runtime.evaluate", std::move(params), true);
+ bool wasThrown = true;
+ EXPECT_TRUE(result_->GetBoolean("wasThrown", &wasThrown));
+ EXPECT_FALSE(wasThrown);
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest,
+ EvaluateInBlankPageAfterNavigation) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+ Attach();
+ NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+ scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+ params->SetString("expression", "window");
+ SendCommand("Runtime.evaluate", std::move(params), true);
+ bool wasThrown = true;
+ EXPECT_TRUE(result_->GetBoolean("wasThrown", &wasThrown));
+ EXPECT_FALSE(wasThrown);
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_client.h b/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
index fe17c995f77..ba1a0d79c53 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/values.h"
namespace content {
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index df56ffe8a5c..2f244625c3a 100755
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -568,6 +568,7 @@ def ResolveObject(json, mapping):
mapping["storage_type"] = "scoped_ptr<base::DictionaryValue>"
mapping["raw_type"] = "base::DictionaryValue*"
mapping["pass_template"] = tmpl_object_pass
+ mapping["init"] = " = nullptr"
if "properties" in json:
if not "declared_name" in mapping:
mapping["declared_name"] = ("%s%s" %
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.cc b/chromium/content/browser/devtools/protocol/emulation_handler.cc
index f5945d71321..6b124e37131 100644
--- a/chromium/content/browser/devtools/protocol/emulation_handler.cc
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.cc
@@ -23,6 +23,19 @@ using Response = DevToolsProtocolClient::Response;
namespace {
+blink::WebScreenOrientationType WebScreenOrientationTypeFromString(
+ const std::string& type) {
+ if (type == screen_orientation::kTypePortraitPrimary)
+ return blink::WebScreenOrientationPortraitPrimary;
+ if (type == screen_orientation::kTypePortraitSecondary)
+ return blink::WebScreenOrientationPortraitSecondary;
+ if (type == screen_orientation::kTypeLandscapePrimary)
+ return blink::WebScreenOrientationLandscapePrimary;
+ if (type == screen_orientation::kTypeLandscapeSecondary)
+ return blink::WebScreenOrientationLandscapeSecondary;
+ return blink::WebScreenOrientationUndefined;
+}
+
ui::GestureProviderConfigType TouchEmulationConfigurationToType(
const std::string& protocol_value) {
ui::GestureProviderConfigType result =
@@ -132,9 +145,11 @@ Response EmulationHandler::SetDeviceMetricsOverride(
const int* screen_width,
const int* screen_height,
const int* position_x,
- const int* position_y) {
+ const int* position_y,
+ const scoped_ptr<base::DictionaryValue>& screen_orientation) {
const static int max_size = 10000000;
const static double max_scale = 10;
+ const static int max_orientation_angle = 360;
if (!host_)
return Response::InternalError("Could not connect to view");
@@ -168,6 +183,30 @@ Response EmulationHandler::SetDeviceMetricsOverride(
base::DoubleToString(max_scale));
}
+ blink::WebScreenOrientationType orientationType =
+ blink::WebScreenOrientationUndefined;
+ int orientationAngle = 0;
+ if (screen_orientation) {
+ std::string orientationTypeString;
+ if (!screen_orientation->GetString("type", &orientationTypeString)) {
+ return Response::InvalidParams(
+ "Screen orientation type must be a string");
+ }
+ orientationType = WebScreenOrientationTypeFromString(orientationTypeString);
+ if (orientationType == blink::WebScreenOrientationUndefined)
+ return Response::InvalidParams("Invalid screen orientation type value");
+
+ if (!screen_orientation->GetInteger("angle", &orientationAngle)) {
+ return Response::InvalidParams(
+ "Screen orientation angle must be a number");
+ }
+ if (orientationAngle < 0 || orientationAngle >= max_orientation_angle) {
+ return Response::InvalidParams(
+ "Screen orientation angle must be non-negative, less than " +
+ base::IntToString(max_orientation_angle));
+ }
+ }
+
blink::WebDeviceEmulationParams params;
params.screenPosition = mobile ? blink::WebDeviceEmulationParams::Mobile :
blink::WebDeviceEmulationParams::Desktop;
@@ -182,6 +221,8 @@ Response EmulationHandler::SetDeviceMetricsOverride(
params.offset = blink::WebFloatPoint(
optional_offset_x ? *optional_offset_x : 0.f,
optional_offset_y ? *optional_offset_y : 0.f);
+ params.screenOrientationType = orientationType;
+ params.screenOrientationAngle = orientationAngle;
if (device_emulation_enabled_ && params == device_emulation_params_)
return Response::OK();
diff --git a/chromium/content/browser/devtools/protocol/emulation_handler.h b/chromium/content/browser/devtools/protocol/emulation_handler.h
index bcaeb0d0410..a5aec635500 100644
--- a/chromium/content/browser/devtools/protocol/emulation_handler.h
+++ b/chromium/content/browser/devtools/protocol/emulation_handler.h
@@ -39,18 +39,20 @@ class EmulationHandler {
const std::string* configuration);
Response CanEmulate(bool* result);
- Response SetDeviceMetricsOverride(int width,
- int height,
- double device_scale_factor,
- bool mobile,
- bool fit_window,
- const double* optional_scale,
- const double* optional_offset_x,
- const double* optional_offset_y,
- const int* screen_widget,
- const int* screen_height,
- const int* position_x,
- const int* position_y);
+ Response SetDeviceMetricsOverride(
+ int width,
+ int height,
+ double device_scale_factor,
+ bool mobile,
+ bool fit_window,
+ const double* optional_scale,
+ const double* optional_offset_x,
+ const double* optional_offset_y,
+ const int* screen_widget,
+ const int* screen_height,
+ const int* position_x,
+ const int* position_y,
+ const scoped_ptr<base::DictionaryValue>& screen_orientation);
Response ClearDeviceMetricsOverride();
private:
diff --git a/chromium/content/browser/devtools/protocol/input_handler.cc b/chromium/content/browser/devtools/protocol/input_handler.cc
index d9c17f3ee0e..08c3cf2cd36 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.cc
+++ b/chromium/content/browser/devtools/protocol/input_handler.cc
@@ -69,8 +69,13 @@ void SetEventModifiers(blink::WebInputEvent* event, const int* modifiers) {
}
void SetEventTimestamp(blink::WebInputEvent* event, const double* timestamp) {
- event->timeStampSeconds =
- timestamp ? *timestamp : base::Time::Now().ToDoubleT();
+ // Convert timestamp, in seconds since unix epoch, to an event timestamp
+ // which is time ticks since platform start time.
+ base::TimeTicks ticks = timestamp
+ ? base::TimeDelta::FromSecondsD(*timestamp) +
+ base::TimeTicks::UnixEpoch()
+ : base::TimeTicks::Now();
+ event->timeStampSeconds = (ticks - base::TimeTicks()).InSecondsF();
}
bool SetKeyboardEventText(blink::WebUChar* to, const std::string* from) {
@@ -248,6 +253,7 @@ Response InputHandler::DispatchMouseEvent(
event.globalX = x * page_scale_factor_;
event.globalY = y * page_scale_factor_;
event.clickCount = click_count ? *click_count : 0;
+ event.pointerType = blink::WebPointerProperties::PointerType::Mouse;
if (!host_)
return Response::ServerError("Could not connect to view");
@@ -296,6 +302,7 @@ Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
event->globalX = x;
event->globalY = y;
event->clickCount = click_count ? *click_count : 0;
+ event->pointerType = blink::WebPointerProperties::PointerType::Touch;
if (!host_)
return Response::ServerError("Could not connect to view");
diff --git a/chromium/content/browser/devtools/protocol/inspector_handler.cc b/chromium/content/browser/devtools/protocol/inspector_handler.cc
index 31e9d1bf9c6..8e018a8477e 100644
--- a/chromium/content/browser/devtools/protocol/inspector_handler.cc
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.cc
@@ -38,9 +38,12 @@ void InspectorHandler::TargetDetached(const std::string& reason) {
Response InspectorHandler::Enable() {
if (host_ && !host_->IsRenderFrameLive())
client_->TargetCrashed(TargetCrashedParams::Create());
- return Response::FallThrough();
+ return Response::OK();
}
+Response InspectorHandler::Disable() {
+ return Response::OK();
+}
} // namespace inspector
} // namespace devtools
diff --git a/chromium/content/browser/devtools/protocol/inspector_handler.h b/chromium/content/browser/devtools/protocol/inspector_handler.h
index 08c1e5e3efb..52325c48a69 100644
--- a/chromium/content/browser/devtools/protocol/inspector_handler.h
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.h
@@ -29,6 +29,7 @@ class InspectorHandler {
void TargetDetached(const std::string& reason);
Response Enable();
+ Response Disable();
private:
scoped_ptr<Client> client_;
diff --git a/chromium/content/browser/devtools/protocol/memory_handler.cc b/chromium/content/browser/devtools/protocol/memory_handler.cc
index ef5cda2703a..9107fa93a4f 100644
--- a/chromium/content/browser/devtools/protocol/memory_handler.cc
+++ b/chromium/content/browser/devtools/protocol/memory_handler.cc
@@ -6,7 +6,7 @@
#include "base/memory/memory_pressure_listener.h"
#include "base/strings/stringprintf.h"
-#include "content/browser/memory/memory_pressure_controller.h"
+#include "content/browser/memory/memory_pressure_controller_impl.h"
namespace content {
namespace devtools {
@@ -18,7 +18,7 @@ MemoryHandler::~MemoryHandler() {}
MemoryHandler::Response MemoryHandler::SetPressureNotificationsSuppressed(
bool suppressed) {
- content::MemoryPressureController::GetInstance()
+ content::MemoryPressureControllerImpl::GetInstance()
->SetPressureNotificationsSuppressedInAllProcesses(suppressed);
return Response::OK();
}
@@ -35,7 +35,7 @@ MemoryHandler::Response MemoryHandler::SimulatePressureNotification(
"Invalid memory pressure level '%s'", level.c_str()));
}
- MemoryPressureController::GetInstance()
+ MemoryPressureControllerImpl::GetInstance()
->SimulatePressureNotificationInAllProcesses(parsed_level);
return Response::OK();
}
diff --git a/chromium/content/browser/devtools/protocol/network_handler.cc b/chromium/content/browser/devtools/protocol/network_handler.cc
index d18d87a6b96..5163f19b853 100644
--- a/chromium/content/browser/devtools/protocol/network_handler.cc
+++ b/chromium/content/browser/devtools/protocol/network_handler.cc
@@ -15,8 +15,10 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cert_store.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_client.h"
@@ -133,8 +135,6 @@ class GetCookiesCommand {
request_count_(0) {
CookieListCallback got_cookies_callback = base::Bind(
&GetCookiesCommand::GotCookiesForURL, base::Unretained(this));
- BrowserContext* browser_context =
- frame_host->GetSiteInstance()->GetBrowserContext();
std::queue<FrameTreeNode*> queue;
queue.push(frame_host->frame_tree_node());
@@ -145,11 +145,12 @@ class GetCookiesCommand {
// Only traverse nodes with the same local root.
if (node->current_frame_host()->IsCrossProcessSubframe())
continue;
- int process_id = node->current_frame_host()->GetProcess()->GetID();
++request_count_;
GetCookiesForURLOnUI(
- browser_context->GetResourceContext(),
- browser_context->GetRequestContextForRenderProcess(process_id),
+ frame_host->GetSiteInstance()->GetBrowserContext()->
+ GetResourceContext(),
+ frame_host->GetProcess()->GetStoragePartition()->
+ GetURLRequestContext(),
node->current_url(),
got_cookies_callback);
@@ -233,7 +234,7 @@ void NetworkHandler::SendGetCookiesResponse(
std::vector<scoped_refptr<Cookie>> cookies;
for (size_t i = 0; i < cookie_list.size(); ++i) {
const net::CanonicalCookie& cookie = cookie_list[i];
- cookies.push_back(Cookie::Create()
+ scoped_refptr<Cookie> devtools_cookie = Cookie::Create()
->set_name(cookie.Name())
->set_value(cookie.Value())
->set_domain(cookie.Domain())
@@ -242,7 +243,19 @@ void NetworkHandler::SendGetCookiesResponse(
->set_size(cookie.Name().length() + cookie.Value().length())
->set_http_only(cookie.IsHttpOnly())
->set_secure(cookie.IsSecure())
- ->set_session(!cookie.IsPersistent()));
+ ->set_session(!cookie.IsPersistent());
+
+ switch (cookie.SameSite()) {
+ case net::CookieSameSite::STRICT_MODE:
+ devtools_cookie->set_same_site(cookie::kSameSiteStrict);
+ break;
+ case net::CookieSameSite::LAX_MODE:
+ devtools_cookie->set_same_site(cookie::kSameSiteLax);
+ break;
+ case net::CookieSameSite::NO_RESTRICTION:
+ break;
+ }
+ cookies.push_back(devtools_cookie);
}
client_->SendGetCookiesResponse(command_id,
GetCookiesResponse::Create()->set_cookies(cookies));
@@ -254,12 +267,9 @@ Response NetworkHandler::DeleteCookie(
const std::string& url) {
if (!host_)
return Response::InternalError("Could not connect to view");
- BrowserContext* browser_context =
- host_->GetSiteInstance()->GetBrowserContext();
- int process_id = host_->GetProcess()->GetID();
DeleteCookieOnUI(
- browser_context->GetResourceContext(),
- browser_context->GetRequestContextForRenderProcess(process_id),
+ host_->GetSiteInstance()->GetBrowserContext()->GetResourceContext(),
+ host_->GetProcess()->GetStoragePartition()->GetURLRequestContext(),
GURL(url),
cookie_name,
base::Bind(&NetworkHandler::SendDeleteCookieResponse,
diff --git a/chromium/content/browser/devtools/protocol/page_handler.cc b/chromium/content/browser/devtools/protocol/page_handler.cc
index 7e79a7200cf..d4f6c3976f4 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.cc
+++ b/chromium/content/browser/devtools/protocol/page_handler.cc
@@ -200,7 +200,7 @@ Response PageHandler::Disable() {
return Response::FallThrough();
}
-Response PageHandler::Reload(const bool* ignoreCache,
+Response PageHandler::Reload(const bool* bypassCache,
const std::string* script_to_evaluate_on_load,
const std::string* script_preprocessor) {
WebContentsImpl* web_contents = GetWebContents();
@@ -210,7 +210,10 @@ Response PageHandler::Reload(const bool* ignoreCache,
if (web_contents->IsCrashed() ||
(web_contents->GetController().GetVisibleEntry() &&
web_contents->GetController().GetVisibleEntry()->IsViewSourceMode())) {
- web_contents->GetController().Reload(false);
+ if (bypassCache && *bypassCache)
+ web_contents->GetController().ReloadBypassingCache(false);
+ else
+ web_contents->GetController().Reload(false);
return Response::OK();
} else {
// Handle reload in renderer except for crashed and view source mode.
@@ -357,6 +360,14 @@ Response PageHandler::SetColorPickerEnabled(bool enabled) {
return Response::OK();
}
+Response PageHandler::RequestAppBanner() {
+ WebContentsImpl* web_contents = GetWebContents();
+ if (!web_contents)
+ return Response::InternalError("Could not connect to view");
+ web_contents->GetDelegate()->RequestAppBannerFromDevTools(web_contents);
+ return Response::OK();
+}
+
WebContentsImpl* PageHandler::GetWebContents() {
return host_ ?
static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(host_)) :
diff --git a/chromium/content/browser/devtools/protocol/page_handler.h b/chromium/content/browser/devtools/protocol/page_handler.h
index 02b685a50d1..067d9587b32 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.h
+++ b/chromium/content/browser/devtools/protocol/page_handler.h
@@ -49,7 +49,7 @@ class PageHandler : public NotificationObserver {
Response Enable();
Response Disable();
- Response Reload(const bool* ignoreCache,
+ Response Reload(const bool* bypassCache,
const std::string* script_to_evaluate_on_load,
const std::string* script_preprocessor = NULL);
@@ -77,6 +77,7 @@ class PageHandler : public NotificationObserver {
const std::string& security_origin);
Response SetColorPickerEnabled(bool enabled);
+ Response RequestAppBanner();
private:
WebContentsImpl* GetWebContents();
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.cc b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
index a84091c276b..b2f5c2572b7 100644
--- a/chromium/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
@@ -16,6 +16,7 @@
#include "content/browser/service_worker/service_worker_context_watcher.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
@@ -23,6 +24,7 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/push_event_payload.h"
#include "content/public/common/push_messaging_status.h"
#include "url/gurl.h"
@@ -131,10 +133,7 @@ scoped_refptr<ServiceWorkerRegistration> CreateRegistrationDictionaryValue(
base::Int64ToString(registration_info.registration_id))
->set_scope_url(registration_info.pattern.spec())
->set_is_deleted(registration_info.delete_flag ==
- ServiceWorkerRegistrationInfo::IS_DELETED)
- ->set_force_update_on_page_load(
- registration_info.force_update_on_page_load ==
- ServiceWorkerRegistrationInfo::IS_FORCED));
+ ServiceWorkerRegistrationInfo::IS_DELETED));
return registration;
}
@@ -142,17 +141,27 @@ scoped_refptr<ServiceWorkerDevToolsAgentHost> GetMatchingServiceWorker(
const ServiceWorkerDevToolsAgentHost::List& agent_hosts,
const GURL& url) {
scoped_refptr<ServiceWorkerDevToolsAgentHost> best_host;
- std::string best_scope;
+ bool best_host_scope_matched = false;
+ int best_host_scope_length = 0;
+
for (auto host : agent_hosts) {
if (host->GetURL().host_piece() != url.host_piece())
continue;
- std::string path = host->GetURL().path();
- std::string file = host->GetURL().ExtractFileName();
- std::string scope = path.substr(0, path.length() - file.length());
- // Choose the latest, longest scope match worker.
- if (scope.length() >= best_scope.length()) {
+ const bool scope_matched =
+ ServiceWorkerUtils::ScopeMatches(host->scope(), url);
+ const int scope_length = host->scope().spec().length();
+ bool replace = false;
+ if (!best_host)
+ replace = true;
+ else if (best_host_scope_matched)
+ replace = scope_matched && scope_length >= best_host_scope_length;
+ else
+ replace = scope_matched || scope_length >= best_host_scope_length;
+
+ if (replace) {
best_host = host;
- best_scope = scope;
+ best_host_scope_matched = scope_matched;
+ best_host_scope_length = scope_length;
}
}
return best_host;
@@ -176,11 +185,6 @@ ServiceWorkerDevToolsAgentHost::Map GetMatchingServiceWorkers(
return result;
}
-bool CollectURLs(std::set<GURL>* urls, FrameTreeNode* tree_node) {
- urls->insert(tree_node->current_url());
- return false;
-}
-
void StopServiceWorkerOnIO(scoped_refptr<ServiceWorkerContextWrapper> context,
int64_t version_id) {
if (content::ServiceWorkerVersion* version =
@@ -246,6 +250,7 @@ void ServiceWorkerHandler::SetRenderFrameHost(
render_frame_host_ = render_frame_host;
// Do not call UpdateHosts yet, wait for load to commit.
if (!render_frame_host) {
+ ClearForceUpdate();
context_ = nullptr;
return;
}
@@ -268,8 +273,10 @@ void ServiceWorkerHandler::UpdateHosts() {
urls_.clear();
BrowserContext* browser_context = nullptr;
if (render_frame_host_) {
- render_frame_host_->frame_tree_node()->frame_tree()->ForEach(
- base::Bind(&CollectURLs, &urls_));
+ for (FrameTreeNode* node :
+ render_frame_host_->frame_tree_node()->frame_tree()->Nodes())
+ urls_.insert(node->current_url());
+
browser_context = render_frame_host_->GetProcess()->GetBrowserContext();
}
@@ -277,12 +284,12 @@ void ServiceWorkerHandler::UpdateHosts() {
ServiceWorkerDevToolsAgentHost::Map new_hosts =
GetMatchingServiceWorkers(browser_context, urls_);
- for (auto pair : old_hosts) {
+ for (const auto& pair : old_hosts) {
if (new_hosts.find(pair.first) == new_hosts.end())
ReportWorkerTerminated(pair.second.get());
}
- for (auto pair : new_hosts) {
+ for (const auto& pair : new_hosts) {
if (old_hosts.find(pair.first) == old_hosts.end())
ReportWorkerCreated(pair.second.get());
}
@@ -301,11 +308,6 @@ Response ServiceWorkerHandler::Enable() {
ServiceWorkerDevToolsManager::GetInstance()->AddObserver(this);
- client_->DebugOnStartUpdated(
- DebugOnStartUpdatedParams::Create()->set_debug_on_start(
- ServiceWorkerDevToolsManager::GetInstance()
- ->debug_service_worker_on_start()));
-
context_watcher_ = new ServiceWorkerContextWatcher(
context_, base::Bind(&ServiceWorkerHandler::OnWorkerRegistrationUpdated,
weak_factory_.GetWeakPtr()),
@@ -325,6 +327,7 @@ Response ServiceWorkerHandler::Disable() {
enabled_ = false;
ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this);
+ ClearForceUpdate();
for (const auto& pair : attached_hosts_)
pair.second->DetachClient();
attached_hosts_.clear();
@@ -411,21 +414,11 @@ Response ServiceWorkerHandler::InspectWorker(const std::string& version_id) {
return Response::OK();
}
-Response ServiceWorkerHandler::SetDebugOnStart(bool debug_on_start) {
- ServiceWorkerDevToolsManager::GetInstance()
- ->set_debug_service_worker_on_start(debug_on_start);
- return Response::OK();
-}
-
Response ServiceWorkerHandler::SetForceUpdateOnPageLoad(
- const std::string& registration_id,
bool force_update_on_page_load) {
if (!context_)
return CreateContextErrorResponse();
- int64_t id = kInvalidServiceWorkerRegistrationId;
- if (!base::StringToInt64(registration_id, &id))
- return CreateInvalidVersionIdErrorResponse();
- context_->SetForceUpdateOnPageLoad(id, force_update_on_page_load);
+ context_->SetForceUpdateOnPageLoad(force_update_on_page_load);
return Response::OK();
}
@@ -440,9 +433,12 @@ Response ServiceWorkerHandler::DeliverPushMessage(
int64_t id = 0;
if (!base::StringToInt64(registration_id, &id))
return CreateInvalidVersionIdErrorResponse();
+ PushEventPayload payload;
+ if (data.size() > 0)
+ payload.setData(data);
BrowserContext::DeliverPushMessage(
render_frame_host_->GetProcess()->GetBrowserContext(), GURL(origin), id,
- data, base::Bind(&PushDeliveryNoOp));
+ payload, base::Bind(&PushDeliveryNoOp));
return Response::OK();
}
@@ -568,11 +564,6 @@ void ServiceWorkerHandler::WorkerDestroyed(
UpdateHosts();
}
-void ServiceWorkerHandler::DebugOnStartUpdated(bool debug_on_start) {
- client_->DebugOnStartUpdated(
- DebugOnStartUpdatedParams::Create()->set_debug_on_start(debug_on_start));
-}
-
void ServiceWorkerHandler::ReportWorkerCreated(
ServiceWorkerDevToolsAgentHost* host) {
if (host->IsAttached())
@@ -597,6 +588,11 @@ void ServiceWorkerHandler::ReportWorkerTerminated(
attached_hosts_.erase(it);
}
+void ServiceWorkerHandler::ClearForceUpdate() {
+ if (context_)
+ context_->SetForceUpdateOnPageLoad(false);
+}
+
} // namespace service_worker
} // namespace devtools
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.h b/chromium/content/browser/devtools/protocol/service_worker_handler.h
index 1508f5d375f..02dcd8c43f5 100644
--- a/chromium/content/browser/devtools/protocol/service_worker_handler.h
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.h
@@ -57,9 +57,7 @@ class ServiceWorkerHandler : public DevToolsAgentHostClient,
Response StopWorker(const std::string& version_id);
Response UpdateRegistration(const std::string& scope_url);
Response InspectWorker(const std::string& version_id);
- Response SetDebugOnStart(bool debug_on_start);
- Response SetForceUpdateOnPageLoad(const std::string& registration_id,
- bool force_update_on_page_load);
+ Response SetForceUpdateOnPageLoad(bool force_update_on_page_load);
Response DeliverPushMessage(const std::string& origin,
const std::string& registration_id,
const std::string& data);
@@ -71,7 +69,6 @@ class ServiceWorkerHandler : public DevToolsAgentHostClient,
void WorkerCreated(ServiceWorkerDevToolsAgentHost* host) override;
void WorkerReadyForInspection(ServiceWorkerDevToolsAgentHost* host) override;
void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) override;
- void DebugOnStartUpdated(bool debug_on_start) override;
private:
// DevToolsAgentHostClient overrides.
@@ -92,6 +89,7 @@ class ServiceWorkerHandler : public DevToolsAgentHostClient,
const ServiceWorkerContextObserver::ErrorInfo& info);
void OpenNewDevToolsWindow(int process_id, int devtools_agent_route_id);
+ void ClearForceUpdate();
scoped_refptr<ServiceWorkerContextWrapper> context_;
scoped_ptr<Client> client_;
diff --git a/chromium/content/browser/devtools/protocol/system_info_handler.cc b/chromium/content/browser/devtools/protocol/system_info_handler.cc
index 27877b0bd98..5a9d53ad1e9 100644
--- a/chromium/content/browser/devtools/protocol/system_info_handler.cc
+++ b/chromium/content/browser/devtools/protocol/system_info_handler.cc
@@ -8,9 +8,12 @@
#include <utility>
#include "base/bind.h"
+#include "base/command_line.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/public/browser/gpu_data_manager.h"
+#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_switches.h"
namespace content {
namespace devtools {
@@ -149,7 +152,9 @@ void SystemInfoHandler::SetClient(scoped_ptr<Client> client) {
Response SystemInfoHandler::GetInfo(DevToolsCommandId command_id) {
std::string reason;
if (!GpuDataManager::GetInstance()->GpuAccessAllowed(&reason) ||
- GpuDataManager::GetInstance()->IsEssentialGpuInfoAvailable()) {
+ GpuDataManager::GetInstance()->IsEssentialGpuInfoAvailable() ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kGpuTestingNoCompleteInfoCollection)) {
// The GpuDataManager already has all of the information needed to make
// GPU-based blacklisting decisions. Post a task to give it to the
// client asynchronously.
diff --git a/chromium/content/browser/devtools/protocol/tethering_handler.cc b/chromium/content/browser/devtools/protocol/tethering_handler.cc
index a58b534c368..1718261c355 100644
--- a/chromium/content/browser/devtools/protocol/tethering_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tethering_handler.cc
@@ -7,6 +7,7 @@
#include "base/stl_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/socket/server_socket.h"
#include "net/socket/stream_socket.h"
@@ -18,8 +19,6 @@ namespace tethering {
namespace {
-const char kLocalhost[] = "127.0.0.1";
-
const int kListenBacklog = 5;
const int kBufferSize = 16 * 1024;
@@ -171,11 +170,7 @@ class BoundSocket {
bool Listen(uint16_t port) {
port_ = port;
- net::IPAddressNumber ip_number;
- if (!net::ParseIPLiteralToNumber(kLocalhost, &ip_number))
- return false;
-
- net::IPEndPoint end_point(ip_number, port);
+ net::IPEndPoint end_point(net::IPAddress::IPv4Localhost(), port);
int result = socket_->Listen(end_point, kListenBacklog);
if (result < 0)
return false;
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.cc b/chromium/content/browser/devtools/protocol/tracing_handler.cc
index 11cc18844ae..e7de4c753ce 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.cc
@@ -8,14 +8,18 @@
#include "base/bind.h"
#include "base/format_macros.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/tracing_agent.h"
#include "components/tracing/trace_config_file.h"
#include "content/browser/devtools/devtools_io_context.h"
+#include "content/browser/tracing/tracing_controller_impl.h"
namespace content {
namespace devtools {
@@ -27,6 +31,46 @@ namespace {
const double kMinimumReportingInterval = 250.0;
+const char kRecordModeParam[] = "record_mode";
+
+// Convert from camel case to separator + lowercase.
+std::string ConvertFromCamelCase(const std::string& in_str, char separator) {
+ std::string out_str;
+ out_str.reserve(in_str.size());
+ for (const char& c : in_str) {
+ if (isupper(c)) {
+ out_str.push_back(separator);
+ out_str.push_back(tolower(c));
+ } else {
+ out_str.push_back(c);
+ }
+ }
+ return out_str;
+}
+
+scoped_ptr<base::Value> ConvertDictKeyStyle(const base::Value& value) {
+ const base::DictionaryValue* dict = nullptr;
+ if (value.GetAsDictionary(&dict)) {
+ scoped_ptr<base::DictionaryValue> out_dict(new base::DictionaryValue());
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
+ it.Advance()) {
+ out_dict->Set(ConvertFromCamelCase(it.key(), '_'),
+ ConvertDictKeyStyle(it.value()));
+ }
+ return std::move(out_dict);
+ }
+
+ const base::ListValue* list = nullptr;
+ if (value.GetAsList(&list)) {
+ scoped_ptr<base::ListValue> out_list(new base::ListValue());
+ for (const auto& value : *list)
+ out_list->Append(ConvertDictKeyStyle(*value));
+ return std::move(out_list);
+ }
+
+ return value.CreateDeepCopy();
+}
+
class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
public:
explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler)
@@ -85,9 +129,11 @@ class DevToolsStreamTraceSink : public TracingController::TraceDataSink {
} // namespace
TracingHandler::TracingHandler(TracingHandler::Target target,
+ int frame_tree_node_id,
DevToolsIOContext* io_context)
: target_(target),
io_context_(io_context),
+ frame_tree_node_id_(frame_tree_node_id),
did_initiate_recording_(false),
return_as_stream_(false),
weak_factory_(this) {}
@@ -125,38 +171,46 @@ void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) {
TracingCompleteParams::Create()->set_stream(stream_handle));
}
-Response TracingHandler::Start(DevToolsCommandId command_id,
- const std::string* categories,
- const std::string* options,
- const double* buffer_usage_reporting_interval,
- const std::string* transfer_mode) {
+Response TracingHandler::Start(
+ DevToolsCommandId command_id,
+ const std::string* categories,
+ const std::string* options,
+ const double* buffer_usage_reporting_interval,
+ const std::string* transfer_mode,
+ const scoped_ptr<base::DictionaryValue>& config) {
if (IsTracing())
return Response::InternalError("Tracing is already started");
+ if (config && (categories || options)) {
+ return Response::InternalError(
+ "Either trace config (preferred), or categories+options should be "
+ "specified, but not both.");
+ }
+
did_initiate_recording_ = true;
return_as_stream_ =
transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream;
- base::trace_event::TraceConfig trace_config(
- categories ? *categories : std::string(),
- options ? *options : std::string());
if (buffer_usage_reporting_interval)
SetupTimer(*buffer_usage_reporting_interval);
- // If inspected target is a render process Tracing.start will be handled by
- // tracing agent in the renderer.
- if (target_ == Renderer) {
- TracingController::GetInstance()->StartTracing(
- trace_config,
- TracingController::StartTracingDoneCallback());
- return Response::FallThrough();
+ base::trace_event::TraceConfig trace_config;
+ if (config) {
+ trace_config = GetTraceConfigFromDevToolsConfig(*config);
+ } else if (categories || options) {
+ trace_config = base::trace_event::TraceConfig(
+ categories ? *categories : std::string(),
+ options ? *options : std::string());
}
+ // If inspected target is a render process Tracing.start will be handled by
+ // tracing agent in the renderer.
TracingController::GetInstance()->StartTracing(
trace_config,
base::Bind(&TracingHandler::OnRecordingEnabled,
weak_factory_.GetWeakPtr(),
command_id));
- return Response::OK();
+
+ return target_ == Renderer ? Response::FallThrough() : Response::OK();
}
Response TracingHandler::End(DevToolsCommandId command_id) {
@@ -188,7 +242,11 @@ Response TracingHandler::GetCategories(DevToolsCommandId command_id) {
}
void TracingHandler::OnRecordingEnabled(DevToolsCommandId command_id) {
- client_->SendStartResponse(command_id, StartResponse::Create());
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+ "TracingStartedInBrowser", TRACE_EVENT_SCOPE_THREAD,
+ "frameTreeNodeId", frame_tree_node_id_);
+ if (target_ != Renderer)
+ client_->SendStartResponse(command_id, StartResponse::Create());
}
void TracingHandler::OnBufferUsage(float percent_full,
@@ -233,6 +291,17 @@ void TracingHandler::OnMemoryDumpFinished(DevToolsCommandId command_id,
->set_success(success));
}
+Response TracingHandler::RecordClockSyncMarker(const std::string& sync_id) {
+ if (!IsTracing())
+ return Response::InternalError("Tracing is not started");
+
+ TracingControllerImpl::GetInstance()->RecordClockSyncMarker(
+ sync_id,
+ base::trace_event::TracingAgent::RecordClockSyncMarkerCallback());
+
+ return Response::OK();
+}
+
void TracingHandler::SetupTimer(double usage_reporting_interval) {
if (usage_reporting_interval == 0) return;
@@ -267,6 +336,21 @@ bool TracingHandler::IsStartupTracingActive() {
TracingController::GetInstance()->IsTracing();
}
+// static
+base::trace_event::TraceConfig TracingHandler::GetTraceConfigFromDevToolsConfig(
+ const base::DictionaryValue& devtools_config) {
+ scoped_ptr<base::Value> value = ConvertDictKeyStyle(devtools_config);
+ DCHECK(value && value->IsType(base::Value::TYPE_DICTIONARY));
+ scoped_ptr<base::DictionaryValue> tracing_dict(
+ static_cast<base::DictionaryValue*>(value.release()));
+
+ std::string mode;
+ if (tracing_dict->GetString(kRecordModeParam, &mode))
+ tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-'));
+
+ return base::trace_event::TraceConfig(*tracing_dict);
+}
+
} // namespace tracing
} // namespace devtools
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.h b/chromium/content/browser/devtools/protocol/tracing_handler.h
index f45d7e97c2e..be3e6e412ed 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.h
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.h
@@ -11,10 +11,12 @@
#include <set>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
+#include "content/common/content_export.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
@@ -34,7 +36,9 @@ class TracingHandler {
typedef DevToolsProtocolClient::Response Response;
enum Target { Browser, Renderer };
- TracingHandler(Target target, DevToolsIOContext* io_context);
+ TracingHandler(Target target,
+ int frame_tree_node_id,
+ DevToolsIOContext* io_context);
virtual ~TracingHandler();
void SetClient(scoped_ptr<Client> client);
@@ -49,10 +53,12 @@ class TracingHandler {
const std::string* categories,
const std::string* options,
const double* buffer_usage_reporting_interval,
- const std::string* transfer_mode);
+ const std::string* transfer_mode,
+ const scoped_ptr<base::DictionaryValue>& config);
Response End(DevToolsCommandId command_id);
Response GetCategories(DevToolsCommandId command);
Response RequestMemoryDump(DevToolsCommandId command_id);
+ Response RecordClockSyncMarker(const std::string& sync_id);
bool did_initiate_recording() { return did_initiate_recording_; }
@@ -70,16 +76,22 @@ class TracingHandler {
const scoped_refptr<TracingController::TraceDataSink>& trace_data_sink);
bool IsTracing() const;
static bool IsStartupTracingActive();
+ CONTENT_EXPORT static base::trace_event::TraceConfig
+ GetTraceConfigFromDevToolsConfig(
+ const base::DictionaryValue& devtools_config);
scoped_ptr<base::Timer> buffer_usage_poll_timer_;
Target target_;
scoped_ptr<Client> client_;
DevToolsIOContext* io_context_;
+ int frame_tree_node_id_;
bool did_initiate_recording_;
bool return_as_stream_;
base::WeakPtrFactory<TracingHandler> weak_factory_;
+ FRIEND_TEST_ALL_PREFIXES(TracingHandlerTest,
+ GetTraceConfigFromDevToolsConfig);
DISALLOW_COPY_AND_ASSIGN(TracingHandler);
};
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc b/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc
new file mode 100644
index 00000000000..8182f45826f
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/tracing_handler_unittest.cc
@@ -0,0 +1,73 @@
+// 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 "base/json/json_reader.h"
+#include "base/trace_event/trace_config.h"
+#include "base/values.h"
+#include "content/browser/devtools/protocol/tracing_handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace devtools {
+namespace tracing {
+
+namespace {
+
+const char kCustomTraceConfigString[] =
+ "{"
+ "\"enable_argument_filter\":true,"
+ "\"enable_sampling\":true,"
+ "\"enable_systrace\":true,"
+ "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
+ "\"included_categories\":[\"included\","
+ "\"inc_pattern*\","
+ "\"disabled-by-default-cc\","
+ "\"disabled-by-default-memory-infra\"],"
+ "\"memory_dump_config\":{"
+ "\"triggers\":["
+ "{\"mode\":\"light\",\"periodic_interval_ms\":50},"
+ "{\"mode\":\"detailed\",\"periodic_interval_ms\":1000}"
+ "]"
+ "},"
+ "\"record_mode\":\"record-continuously\","
+ "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+ "}";
+
+const char kCustomTraceConfigStringDevToolsStyle[] =
+ "{"
+ "\"enableArgumentFilter\":true,"
+ "\"enableSampling\":true,"
+ "\"enableSystrace\":true,"
+ "\"excludedCategories\":[\"excluded\",\"exc_pattern*\"],"
+ "\"includedCategories\":[\"included\","
+ "\"inc_pattern*\","
+ "\"disabled-by-default-cc\","
+ "\"disabled-by-default-memory-infra\"],"
+ "\"memoryDumpConfig\":{"
+ "\"triggers\":["
+ "{\"mode\":\"light\",\"periodicIntervalMs\":50},"
+ "{\"mode\":\"detailed\",\"periodicIntervalMs\":1000}"
+ "]"
+ "},"
+ "\"recordMode\":\"recordContinuously\","
+ "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+ "}";
+
+}
+
+TEST(TracingHandlerTest, GetTraceConfigFromDevToolsConfig) {
+ scoped_ptr<base::Value> value = base::JSONReader::Read(
+ kCustomTraceConfigStringDevToolsStyle);
+ scoped_ptr<base::DictionaryValue> devtools_style_dict(
+ static_cast<base::DictionaryValue*>(value.release()));
+
+ base::trace_event::TraceConfig trace_config =
+ TracingHandler::GetTraceConfigFromDevToolsConfig(*devtools_style_dict);
+
+ EXPECT_STREQ(kCustomTraceConfigString, trace_config.ToString().c_str());
+}
+
+} // namespace tracing
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
index cb1be38ea98..d9a1a1c0b0d 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -24,6 +24,7 @@
#include "content/browser/devtools/protocol/tracing_handler.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/input/input_router_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
@@ -47,8 +48,6 @@ typedef std::vector<RenderFrameDevToolsAgentHost*> Instances;
namespace {
base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
-bool browser_side_navigation = false;
-
static RenderFrameDevToolsAgentHost* FindAgentHost(RenderFrameHost* host) {
if (g_instances == NULL)
return NULL;
@@ -60,19 +59,24 @@ static RenderFrameDevToolsAgentHost* FindAgentHost(RenderFrameHost* host) {
return NULL;
}
-// Returns RenderFrameDevToolsAgentHost attached to any of RenderFrameHost
-// instances associated with |web_contents|
-static RenderFrameDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
+static RenderFrameDevToolsAgentHost* FindAgentHost(
+ FrameTreeNode* frame_tree_node) {
if (g_instances == NULL)
return NULL;
for (Instances::iterator it = g_instances.Get().begin();
it != g_instances.Get().end(); ++it) {
- if ((*it)->GetWebContents() == web_contents)
+ if ((*it)->frame_tree_node() == frame_tree_node)
return *it;
}
return NULL;
}
+static RenderFrameDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
+ if (!web_contents->GetMainFrame())
+ return nullptr;
+ return FindAgentHost(web_contents->GetMainFrame());
+}
+
bool ShouldCreateDevToolsFor(RenderFrameHost* rfh) {
return rfh->IsCrossProcessSubframe() || !rfh->GetParent();
}
@@ -254,16 +258,11 @@ DevToolsAgentHost::GetOrCreateFor(RenderFrameHost* frame_host) {
// static
scoped_refptr<DevToolsAgentHost>
DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
- RenderFrameDevToolsAgentHost* result = FindAgentHost(web_contents);
- if (!result) {
- // TODO(dgozman): this check should not be necessary. See
- // http://crbug.com/489664.
- if (!web_contents->GetMainFrame())
- return nullptr;
- result = new RenderFrameDevToolsAgentHost(
- static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()));
- }
- return result;
+ // TODO(dgozman): this check should not be necessary. See
+ // http://crbug.com/489664.
+ if (!web_contents->GetMainFrame())
+ return nullptr;
+ return DevToolsAgentHost::GetOrCreateFor(web_contents->GetMainFrame());
}
// static
@@ -311,7 +310,7 @@ void RenderFrameDevToolsAgentHost::AddAllAgentHosts(
void RenderFrameDevToolsAgentHost::OnCancelPendingNavigation(
RenderFrameHost* pending,
RenderFrameHost* current) {
- if (browser_side_navigation)
+ if (IsBrowserSideNavigationEnabled())
return;
RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(pending);
@@ -331,6 +330,16 @@ void RenderFrameDevToolsAgentHost::OnBeforeNavigation(
agent_host->AboutToNavigateRenderFrame(current, pending);
}
+// static
+void RenderFrameDevToolsAgentHost::OnBeforeNavigation(
+ NavigationHandle* navigation_handle) {
+ FrameTreeNode* frame_tree_node =
+ static_cast<NavigationHandleImpl*>(navigation_handle)->frame_tree_node();
+ RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
+ if (agent_host)
+ agent_host->AboutToNavigate(navigation_handle);
+}
+
RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
RenderFrameHostImpl* host)
: dom_handler_(new devtools::dom::DOMHandler()),
@@ -344,15 +353,14 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
new devtools::service_worker::ServiceWorkerHandler()),
tracing_handler_(new devtools::tracing::TracingHandler(
devtools::tracing::TracingHandler::Renderer,
+ host->GetFrameTreeNodeId(),
GetIOContext())),
emulation_handler_(nullptr),
frame_trace_recorder_(nullptr),
protocol_handler_(new DevToolsProtocolHandler(this)),
current_frame_crashed_(false),
pending_handle_(nullptr),
- in_navigation_(0),
frame_tree_node_(host->frame_tree_node()) {
- browser_side_navigation = IsBrowserSideNavigationEnabled();
DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
dispatcher->SetDOMHandler(dom_handler_.get());
dispatcher->SetInputHandler(input_handler_.get());
@@ -454,8 +462,8 @@ bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
if (protocol_handler_->HandleOptionalMessage(session_id(), message, &call_id))
return true;
- if (in_navigation_ > 0) {
- DCHECK(browser_side_navigation);
+ if (!navigating_handles_.empty()) {
+ DCHECK(IsBrowserSideNavigationEnabled());
in_navigation_protocol_message_buffer_[call_id] =
std::make_pair(session_id(), message);
return true;
@@ -480,8 +488,7 @@ void RenderFrameDevToolsAgentHost::OnClientAttached() {
return;
frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
-
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
@@ -520,54 +527,49 @@ RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
g_instances.Get().erase(it);
}
-void RenderFrameDevToolsAgentHost::DidStartNavigation(
- NavigationHandle* navigation_handle) {
- if (!browser_side_navigation)
- return;
- if (!MatchesMyTreeNode(navigation_handle))
- return;
- DCHECK(current_);
- DCHECK(in_navigation_ >= 0);
- ++in_navigation_;
-}
-
void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
NavigationHandle* navigation_handle) {
// ReadyToCommitNavigation should only be called in PlzNavigate.
- DCHECK(browser_side_navigation);
-
- if (MatchesMyTreeNode(navigation_handle) && in_navigation_ != 0) {
- RenderFrameHostImpl* render_frame_host_impl =
- static_cast<RenderFrameHostImpl*>(
- navigation_handle->GetRenderFrameHost());
- if (current_->host() != render_frame_host_impl || current_frame_crashed_) {
- SetPending(render_frame_host_impl);
- pending_handle_ = navigation_handle;
- }
+ DCHECK(IsBrowserSideNavigationEnabled());
+
+ // If the navigation is not tracked, return;
+ if (navigating_handles_.count(navigation_handle) == 0)
+ return;
+
+ RenderFrameHostImpl* render_frame_host_impl =
+ static_cast<RenderFrameHostImpl*>(
+ navigation_handle->GetRenderFrameHost());
+ if (current_->host() != render_frame_host_impl || current_frame_crashed_) {
+ SetPending(render_frame_host_impl);
+ pending_handle_ = navigation_handle;
}
}
void RenderFrameDevToolsAgentHost::DidFinishNavigation(
NavigationHandle* navigation_handle) {
- if (!browser_side_navigation)
+ if (!IsBrowserSideNavigationEnabled())
+ return;
+
+ // If the navigation is not tracked, return;
+ if (navigating_handles_.count(navigation_handle) == 0)
return;
- if (MatchesMyTreeNode(navigation_handle) && in_navigation_ != 0) {
- --in_navigation_;
- DCHECK(in_navigation_ >= 0);
- if (pending_handle_ == navigation_handle) {
- // This navigation handle did set the pending FrameHostHolder.
- DCHECK(pending_);
- if (navigation_handle->HasCommitted()) {
- DCHECK(pending_->host() == navigation_handle->GetRenderFrameHost());
- CommitPending();
- } else {
- DiscardPending();
- }
- pending_handle_ = nullptr;
+ // Now that the navigation is finished, remove the handle from the list of
+ // navigating handles.
+ navigating_handles_.erase(navigation_handle);
+
+ if (pending_handle_ == navigation_handle) {
+ // This navigation handle did set the pending FrameHostHolder.
+ DCHECK(pending_);
+ if (navigation_handle->HasCommitted()) {
+ DCHECK(pending_->host() == navigation_handle->GetRenderFrameHost());
+ CommitPending();
+ } else {
+ DiscardPending();
}
- DispatchBufferedProtocolMessagesIfNecessary();
+ pending_handle_ = nullptr;
}
+ DispatchBufferedProtocolMessagesIfNecessary();
if (navigation_handle->HasCommitted())
service_worker_handler_->UpdateHosts();
@@ -576,7 +578,7 @@ void RenderFrameDevToolsAgentHost::DidFinishNavigation(
void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
RenderFrameHost* old_host,
RenderFrameHost* new_host) {
- if (browser_side_navigation)
+ if (IsBrowserSideNavigationEnabled())
return;
DCHECK(!pending_ || pending_->host() != old_host);
@@ -588,10 +590,18 @@ void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
SetPending(static_cast<RenderFrameHostImpl*>(new_host));
}
+void RenderFrameDevToolsAgentHost::AboutToNavigate(
+ NavigationHandle* navigation_handle) {
+ if (!IsBrowserSideNavigationEnabled())
+ return;
+ DCHECK(current_);
+ navigating_handles_.insert(navigation_handle);
+}
+
void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
RenderFrameHost* old_host,
RenderFrameHost* new_host) {
- if (browser_side_navigation)
+ if (IsBrowserSideNavigationEnabled())
return;
DCHECK(!pending_ || pending_->host() != old_host);
@@ -608,7 +618,7 @@ void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
if (pending_ && pending_->host() == rfh) {
- if (!browser_side_navigation)
+ if (!IsBrowserSideNavigationEnabled())
DiscardPending();
return;
}
@@ -671,24 +681,22 @@ bool RenderFrameDevToolsAgentHost::OnMessageReceived(
bool RenderFrameDevToolsAgentHost::OnMessageReceived(
const IPC::Message& message,
RenderFrameHost* render_frame_host) {
- if (message.type() != DevToolsClientMsg_DispatchOnInspectorFrontend::ID)
+ bool is_current = current_ && current_->host() == render_frame_host;
+ bool is_pending = pending_ && pending_->host() == render_frame_host;
+ if (!is_current && !is_pending)
return false;
if (!IsAttached())
return false;
-
- FrameHostHolder* holder = nullptr;
- if (current_ && current_->host() == render_frame_host)
- holder = current_.get();
- if (pending_ && pending_->host() == render_frame_host)
- holder = pending_.get();
- if (!holder)
- return false;
-
- DevToolsClientMsg_DispatchOnInspectorFrontend::Param param;
- if (!DevToolsClientMsg_DispatchOnInspectorFrontend::Read(&message, &param))
- return false;
- holder->ProcessChunkedMessageFromAgent(base::get<0>(param));
- return true;
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderFrameDevToolsAgentHost, message,
+ render_frame_host)
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ OnDispatchOnInspectorFrontend)
+ IPC_MESSAGE_HANDLER(DevToolsAgentHostMsg_RequestNewWindow,
+ OnRequestNewWindow)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
}
void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
@@ -713,7 +721,7 @@ void RenderFrameDevToolsAgentHost::DidCommitProvisionalLoadForFrame(
RenderFrameHost* render_frame_host,
const GURL& url,
ui::PageTransition transition_type) {
- if (browser_side_navigation)
+ if (IsBrowserSideNavigationEnabled())
return;
if (pending_ && pending_->host() == render_frame_host)
CommitPending();
@@ -726,7 +734,7 @@ void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad(
int error_code,
const base::string16& error_description,
bool was_ignored_by_handler) {
- if (browser_side_navigation)
+ if (IsBrowserSideNavigationEnabled())
return;
if (pending_ && pending_->host() == render_frame_host)
DiscardPending();
@@ -734,7 +742,8 @@ void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad(
void RenderFrameDevToolsAgentHost::
DispatchBufferedProtocolMessagesIfNecessary() {
- if (in_navigation_ == 0 && in_navigation_protocol_message_buffer_.size()) {
+ if (navigating_handles_.empty() &&
+ in_navigation_protocol_message_buffer_.size()) {
DCHECK(current_);
for (const auto& pair : in_navigation_protocol_message_buffer_) {
current_->DispatchProtocolMessage(pair.second.first, pair.first,
@@ -768,7 +777,7 @@ void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
disconnected_->Detach();
frame_tree_node_ = nullptr;
in_navigation_protocol_message_buffer_.clear();
- in_navigation_ = 0;
+ navigating_handles_.clear();
pending_handle_ = nullptr;
WebContentsObserver::Observe(nullptr);
}
@@ -856,6 +865,33 @@ void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
}
}
+void RenderFrameDevToolsAgentHost::OnDispatchOnInspectorFrontend(
+ RenderFrameHost* sender,
+ const DevToolsMessageChunk& message) {
+ if (current_ && current_->host() == sender)
+ current_->ProcessChunkedMessageFromAgent(message);
+ else if (pending_ && pending_->host() == sender)
+ pending_->ProcessChunkedMessageFromAgent(message);
+}
+
+void RenderFrameDevToolsAgentHost::OnRequestNewWindow(
+ RenderFrameHost* sender,
+ int new_routing_id) {
+ RenderFrameHostImpl* frame_host = RenderFrameHostImpl::FromID(
+ sender->GetProcess()->GetID(), new_routing_id);
+
+ bool success = false;
+ if (IsAttached() && sender->GetRoutingID() != new_routing_id && frame_host) {
+ scoped_refptr<DevToolsAgentHost> agent =
+ DevToolsAgentHost::GetOrCreateFor(frame_host);
+ success = static_cast<DevToolsAgentHostImpl*>(agent.get())->
+ Inspect(agent->GetBrowserContext());
+ }
+
+ sender->Send(new DevToolsAgentMsg_RequestNewWindow_ACK(
+ sender->GetRoutingID(), success));
+}
+
bool RenderFrameDevToolsAgentHost::HasRenderFrameHost(
RenderFrameHost* host) {
return (current_ && current_->host() == host) ||
@@ -866,11 +902,4 @@ bool RenderFrameDevToolsAgentHost::IsChildFrame() {
return current_ && current_->host()->GetParent();
}
-bool RenderFrameDevToolsAgentHost::MatchesMyTreeNode(
- NavigationHandle* navigation_handle) {
- return frame_tree_node_ ==
- static_cast<NavigationHandleImpl*>(navigation_handle)
- ->frame_tree_node();
-}
-
} // namespace content
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
index 68409344de8..24d05358ad9 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -55,12 +55,15 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
RenderFrameHost* current);
static void OnBeforeNavigation(RenderFrameHost* current,
RenderFrameHost* pending);
+ static void OnBeforeNavigation(NavigationHandle* navigation_handle);
void SynchronousSwapCompositorFrame(
const cc::CompositorFrameMetadata& frame_metadata);
bool HasRenderFrameHost(RenderFrameHost* host);
+ FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
+
// DevTooolsAgentHost overrides.
void DisconnectWebContents() override;
void ConnectWebContents(WebContents* web_contents) override;
@@ -90,7 +93,6 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void InspectElement(int x, int y) override;
// WebContentsObserver overrides.
- void DidStartNavigation(NavigationHandle* navigation_handle) override;
void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override;
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void RenderFrameHostChanged(RenderFrameHost* old_host,
@@ -116,6 +118,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void AboutToNavigateRenderFrame(RenderFrameHost* old_host,
RenderFrameHost* new_host);
+ void AboutToNavigate(NavigationHandle* navigation_handle);
void DispatchBufferedProtocolMessagesIfNecessary();
@@ -131,10 +134,12 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void RenderFrameCrashed();
void OnSwapCompositorFrame(const IPC::Message& message);
+ void OnDispatchOnInspectorFrontend(
+ RenderFrameHost* sender,
+ const DevToolsMessageChunk& message);
+ void OnRequestNewWindow(RenderFrameHost* sender, int new_routing_id);
void DestroyOnRenderFrameGone();
- bool MatchesMyTreeNode(NavigationHandle* navigation_handle);
-
class FrameHostHolder;
scoped_ptr<FrameHostHolder> current_;
@@ -166,9 +171,8 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
// Handle that caused the setting of pending_.
NavigationHandle* pending_handle_;
- // Navigation counter and queue for buffering protocol messages during a
- // navigation.
- int in_navigation_;
+ // List of handles currently navigating.
+ std::set<NavigationHandle*> navigating_handles_;
// <call_id> -> <session_id, message>
std::map<int, std::pair<int, std::string>>
diff --git a/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
index 3755d15c51e..33293d52e5b 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -109,6 +109,10 @@ int64_t ServiceWorkerDevToolsAgentHost::service_worker_version_id() const {
return service_worker_->version_id();
}
+GURL ServiceWorkerDevToolsAgentHost::scope() const {
+ return service_worker_->scope();
+}
+
bool ServiceWorkerDevToolsAgentHost::Matches(
const ServiceWorkerIdentifier& other) {
return service_worker_->Matches(other);
diff --git a/chromium/content/browser/devtools/service_worker_devtools_agent_host.h b/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
index 89b48b13b1f..a5f15ee7dc8 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/service_worker_devtools_agent_host.h
@@ -40,6 +40,7 @@ class ServiceWorkerDevToolsAgentHost : public WorkerDevToolsAgentHost {
void OnAttachedStateChanged(bool attached) override;
int64_t service_worker_version_id() const;
+ GURL scope() const;
bool Matches(const ServiceWorkerIdentifier& other);
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.cc b/chromium/content/browser/devtools/service_worker_devtools_manager.cc
index b94f1a9e3c2..6796b71db69 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_manager.cc
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.cc
@@ -16,19 +16,21 @@ ServiceWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
const ServiceWorkerContextCore* context,
base::WeakPtr<ServiceWorkerContextCore> context_weak,
int64_t version_id,
- const GURL& url)
+ const GURL& url,
+ const GURL& scope)
: context_(context),
context_weak_(context_weak),
version_id_(version_id),
- url_(url) {}
+ url_(url),
+ scope_(scope) {}
ServiceWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
const ServiceWorkerIdentifier& other)
: context_(other.context_),
context_weak_(other.context_weak_),
version_id_(other.version_id_),
- url_(other.url_) {
-}
+ url_(other.url_),
+ scope_(other.scope_) {}
ServiceWorkerDevToolsManager::
ServiceWorkerIdentifier::~ServiceWorkerIdentifier() {
@@ -155,8 +157,6 @@ void ServiceWorkerDevToolsManager::RemoveObserver(Observer* observer) {
void ServiceWorkerDevToolsManager::set_debug_service_worker_on_start(
bool debug_on_start) {
debug_service_worker_on_start_ = debug_on_start;
- FOR_EACH_OBSERVER(Observer, observer_list_,
- DebugOnStartUpdated(debug_on_start));
}
ServiceWorkerDevToolsManager::ServiceWorkerDevToolsManager()
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.h b/chromium/content/browser/devtools/service_worker_devtools_manager.h
index 306edd7d3f5..c2cd08e11cc 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_manager.h
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.h
@@ -35,7 +35,6 @@ class CONTENT_EXPORT ServiceWorkerDevToolsManager {
virtual void WorkerReadyForInspection(
ServiceWorkerDevToolsAgentHost* host) {}
virtual void WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) {}
- virtual void DebugOnStartUpdated(bool debug_on_start) {}
protected:
virtual ~Observer() {}
@@ -47,7 +46,8 @@ class CONTENT_EXPORT ServiceWorkerDevToolsManager {
const ServiceWorkerContextCore* context,
base::WeakPtr<ServiceWorkerContextCore> context_weak,
int64_t version_id,
- const GURL& url);
+ const GURL& url,
+ const GURL& scope);
ServiceWorkerIdentifier(const ServiceWorkerIdentifier& other);
~ServiceWorkerIdentifier();
@@ -59,12 +59,14 @@ class CONTENT_EXPORT ServiceWorkerDevToolsManager {
}
int64_t version_id() const { return version_id_; }
GURL url() const { return url_; }
+ GURL scope() const { return scope_; }
private:
const ServiceWorkerContextCore* const context_;
const base::WeakPtr<ServiceWorkerContextCore> context_weak_;
const int64_t version_id_;
const GURL url_;
+ const GURL scope_;
};
// Returns the ServiceWorkerDevToolsManager singleton.
diff --git a/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc b/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
index 98a715220b0..c6f86d5fc23 100644
--- a/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
+++ b/chromium/content/browser/devtools/shared_worker_devtools_manager_unittest.cc
@@ -102,7 +102,7 @@ TEST_F(SharedWorkerDevToolsManagerTest, BasicTest) {
SharedWorkerInstance instance1(
GURL("http://example.com/w.js"), base::string16(), base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
+ blink::WebContentSecurityPolicyTypeReport, blink::WebAddressSpacePublic,
browser_context_->GetResourceContext(), partition_id_,
blink::WebSharedWorkerCreationContextTypeNonsecure);
@@ -184,12 +184,12 @@ TEST_F(SharedWorkerDevToolsManagerTest, AttachTest) {
SharedWorkerInstance instance1(
GURL("http://example.com/w1.js"), base::string16(), base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
+ blink::WebContentSecurityPolicyTypeReport, blink::WebAddressSpacePublic,
browser_context_->GetResourceContext(), partition_id_,
blink::WebSharedWorkerCreationContextTypeNonsecure);
SharedWorkerInstance instance2(
GURL("http://example.com/w2.js"), base::string16(), base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
+ blink::WebContentSecurityPolicyTypeReport, blink::WebAddressSpacePublic,
browser_context_->GetResourceContext(), partition_id_,
blink::WebSharedWorkerCreationContextTypeNonsecure);
@@ -267,7 +267,7 @@ TEST_F(SharedWorkerDevToolsManagerTest, AttachTest) {
TEST_F(SharedWorkerDevToolsManagerTest, ReattachTest) {
SharedWorkerInstance instance(
GURL("http://example.com/w3.js"), base::string16(), base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
+ blink::WebContentSecurityPolicyTypeReport, blink::WebAddressSpacePublic,
browser_context_->GetResourceContext(), partition_id_,
blink::WebSharedWorkerCreationContextTypeNonsecure);
scoped_ptr<TestDevToolsClientHost> client_host(new TestDevToolsClientHost());
diff --git a/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc b/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc
index cfa2b4a1042..e3c3cf222bc 100644
--- a/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc
+++ b/chromium/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -23,7 +23,7 @@ class SitePerProcessDevToolsBrowserTest
class TestClient: public DevToolsAgentHostClient {
public:
- TestClient() : closed_(false) {}
+ TestClient() : closed_(false), waiting_for_reply_(false) {}
~TestClient() override {}
bool closed() { return closed_; }
@@ -31,6 +31,10 @@ class TestClient: public DevToolsAgentHostClient {
void DispatchProtocolMessage(
DevToolsAgentHost* agent_host,
const std::string& message) override {
+ if (waiting_for_reply_) {
+ waiting_for_reply_ = false;
+ base::MessageLoop::current()->QuitNow();
+ }
}
void AgentHostClosed(
@@ -39,8 +43,14 @@ class TestClient: public DevToolsAgentHostClient {
closed_ = true;
}
+ void WaitForReply() {
+ waiting_for_reply_ = true;
+ base::MessageLoop::current()->Run();
+ }
+
private:
bool closed_;
+ bool waiting_for_reply_;
};
// Fails on Android, http://crbug.com/464993.
@@ -90,10 +100,20 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest,
EXPECT_EQ(DevToolsAgentHost::TYPE_FRAME, list[1]->GetType());
EXPECT_EQ(cross_site_url.spec(), list[1]->GetURL().spec());
- // Attaching to child frame.
+ // Attaching to both agent hosts.
scoped_refptr<DevToolsAgentHost> child_host = list[1];
- TestClient client;
- child_host->AttachClient(&client);
+ TestClient child_client;
+ child_host->AttachClient(&child_client);
+ scoped_refptr<DevToolsAgentHost> parent_host = list[0];
+ TestClient parent_client;
+ parent_host->AttachClient(&parent_client);
+
+ // Send message to parent and child frames and get result back.
+ char message[] = "{\"id\": 0, \"method\": \"incorrect.method\"}";
+ child_host->DispatchProtocolMessage(message);
+ child_client.WaitForReply();
+ parent_host->DispatchProtocolMessage(message);
+ parent_client.WaitForReply();
// Load back same-site page into iframe.
NavigateFrameToURL(root->child_at(0), http_url);
@@ -102,9 +122,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest,
EXPECT_EQ(1U, list.size());
EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
- EXPECT_TRUE(client.closed());
+ EXPECT_TRUE(child_client.closed());
child_host->DetachClient();
child_host = nullptr;
+ EXPECT_FALSE(parent_client.closed());
+ parent_host->DetachClient();
+ parent_host = nullptr;
}
IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest, AgentHostForFrames) {
@@ -145,4 +168,36 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest, AgentHostForFrames) {
EXPECT_NE(page_agent.get(), child_frame_agent.get());
}
+IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest,
+ AgentHostForPageEqualsOneForMainFrame) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(shell()->web_contents())->
+ GetFrameTree()->root();
+ FrameTreeNode* child = root->child_at(0);
+
+ // Load cross-site page into iframe.
+ GURL::Replacements replace_host;
+ GURL cross_site_url(embedded_test_server()->GetURL("/title2.html"));
+ replace_host.SetHostStr("foo.com");
+ cross_site_url = cross_site_url.ReplaceComponents(replace_host);
+ NavigateFrameToURL(child, cross_site_url);
+
+ // First ask for child frame, then for main frame.
+ scoped_refptr<DevToolsAgentHost> child_frame_agent =
+ DevToolsAgentHost::GetOrCreateFor(child->current_frame_host());
+ scoped_refptr<DevToolsAgentHost> main_frame_agent =
+ DevToolsAgentHost::GetOrCreateFor(root->current_frame_host());
+ EXPECT_NE(main_frame_agent.get(), child_frame_agent.get());
+
+ // Agent for web contents should be the the main frame's one.
+ scoped_refptr<DevToolsAgentHost> page_agent =
+ DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
+ EXPECT_EQ(page_agent.get(), main_frame_agent.get());
+}
+
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_browsertest.cc b/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
index b0c1c63d65f..9fc8c417dc9 100644
--- a/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -9,7 +9,6 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
-#include "net/base/net_util.h"
namespace content {
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
index db486f35e36..b0ec4d5ab65 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -11,15 +11,23 @@
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
+#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
+#include "components/filesystem/public/interfaces/directory.mojom.h"
+#include "components/leveldb/public/interfaces/leveldb.mojom.h"
+#include "components/profile_service/public/interfaces/profile.mojom.h"
#include "content/browser/dom_storage/dom_storage_area.h"
#include "content/browser/dom_storage/dom_storage_context_impl.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/leveldb_wrapper_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/mojo_app_connection.h"
#include "content/public/browser/session_storage_usage_info.h"
+#include "mojo/common/common_type_converters.h"
namespace content {
namespace {
@@ -65,9 +73,175 @@ void GetSessionStorageUsageHelper(
} // namespace
+// Used for mojo-based LocalStorage implementation (behind --mojo-local-storage
+// for now).
+class DOMStorageContextWrapper::MojoState {
+ public:
+ MojoState(const std::string& mojo_user_id, const base::FilePath& subdirectory)
+ : mojo_user_id_(mojo_user_id),
+ subdirectory_(subdirectory),
+ connection_state_(NO_CONNECTION),
+ weak_ptr_factory_(this) {}
+
+ void OpenLocalStorage(const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request);
+
+ private:
+ void OnLevelDDWrapperHasNoBindings(const url::Origin& origin) {
+ DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end());
+ level_db_wrappers_.erase(origin);
+ }
+
+ // Part of our asynchronous directory opening called from OpenLocalStorage().
+ void OnDirectoryOpened(filesystem::FileError err);
+ void OnDatabaseOpened(leveldb::DatabaseError status);
+
+ // The (possibly delayed) implementation of OpenLocalStorage(). Can be called
+ // directly from that function, or through |on_database_open_callbacks_|.
+ void BindLocalStorage(const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request);
+
+ // Maps between an origin and its prefixed LevelDB view.
+ std::map<url::Origin, scoped_ptr<LevelDBWrapperImpl>> level_db_wrappers_;
+
+ std::string mojo_user_id_;
+ base::FilePath subdirectory_;
+
+ enum ConnectionState {
+ NO_CONNECTION,
+ CONNECTION_IN_PROGRESS,
+ CONNECTION_FINISHED
+ } connection_state_;
+
+ scoped_ptr<MojoAppConnection> profile_app_connection_;
+ profile::ProfileServicePtr profile_service_;
+ filesystem::DirectoryPtr directory_;
+
+ leveldb::LevelDBServicePtr leveldb_service_;
+ leveldb::LevelDBDatabasePtr database_;
+
+ std::vector<base::Closure> on_database_opened_callbacks_;
+
+ base::WeakPtrFactory<MojoState> weak_ptr_factory_;
+};
+
+void DOMStorageContextWrapper::MojoState::OpenLocalStorage(
+ const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request) {
+ // If we don't have a filesystem_connection_, we'll need to establish one.
+ if (connection_state_ == NO_CONNECTION) {
+ profile_app_connection_ = MojoAppConnection::Create(
+ mojo_user_id_, "mojo:profile", kBrowserMojoAppUrl);
+
+ connection_state_ = CONNECTION_IN_PROGRESS;
+
+ if (!subdirectory_.empty()) {
+ // We were given a subdirectory to write to. Get it and use a disk backed
+ // database.
+ profile_app_connection_->GetInterface(&profile_service_);
+ profile_service_->GetSubDirectory(
+ mojo::String::From(subdirectory_.AsUTF8Unsafe()),
+ GetProxy(&directory_),
+ base::Bind(&MojoState::OnDirectoryOpened,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ // We were not given a subdirectory. Use a memory backed database.
+ profile_app_connection_->GetInterface(&leveldb_service_);
+ leveldb_service_->OpenInMemory(
+ GetProxy(&database_),
+ base::Bind(&MojoState::OnDatabaseOpened,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ }
+
+ if (connection_state_ == CONNECTION_IN_PROGRESS) {
+ // Queue this OpenLocalStorage call for when we have a level db pointer.
+ on_database_opened_callbacks_.push_back(
+ base::Bind(&MojoState::BindLocalStorage, weak_ptr_factory_.GetWeakPtr(),
+ origin, base::Passed(&observer), base::Passed(&request)));
+ return;
+ }
+
+ BindLocalStorage(origin, std::move(observer), std::move(request));
+}
+
+void DOMStorageContextWrapper::MojoState::OnDirectoryOpened(
+ filesystem::FileError err) {
+ if (err != filesystem::FileError::OK) {
+ // We failed to open the directory; continue with startup so that we create
+ // the |level_db_wrappers_|.
+ OnDatabaseOpened(leveldb::DatabaseError::IO_ERROR);
+ return;
+ }
+
+ // Now that we have a directory, connect to the LevelDB service and get our
+ // database.
+ profile_app_connection_->GetInterface(&leveldb_service_);
+
+ leveldb_service_->Open(
+ std::move(directory_), "leveldb", GetProxy(&database_),
+ base::Bind(&MojoState::OnDatabaseOpened, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DOMStorageContextWrapper::MojoState::OnDatabaseOpened(
+ leveldb::DatabaseError status) {
+ if (status != leveldb::DatabaseError::OK) {
+ // If we failed to open the database, reset the service object so we pass
+ // null pointers to our wrappers.
+ database_.reset();
+ leveldb_service_.reset();
+ }
+
+ // We no longer need the profile service; we've either transferred
+ // |directory_| to the leveldb service, or we got a file error and no more is
+ // possible.
+ directory_.reset();
+ profile_service_.reset();
+
+ // |leveldb_| should be known to either be valid or invalid by now. Run our
+ // delayed bindings.
+ connection_state_ = CONNECTION_FINISHED;
+ for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i)
+ on_database_opened_callbacks_[i].Run();
+ on_database_opened_callbacks_.clear();
+}
+
+void DOMStorageContextWrapper::MojoState::BindLocalStorage(
+ const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request) {
+ auto found = level_db_wrappers_.find(origin);
+ if (found == level_db_wrappers_.end()) {
+ level_db_wrappers_[origin] = make_scoped_ptr(new LevelDBWrapperImpl(
+ database_.get(),
+ origin.Serialize(),
+ kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+ base::Bind(&MojoState::OnLevelDDWrapperHasNoBindings,
+ base::Unretained(this),
+ origin)));
+ found = level_db_wrappers_.find(origin);
+ }
+
+ found->second->Bind(std::move(request));
+ found->second->AddObserver(std::move(observer));
+}
+
DOMStorageContextWrapper::DOMStorageContextWrapper(
- const base::FilePath& data_path,
+ const std::string& mojo_user_id,
+ const base::FilePath& profile_path,
+ const base::FilePath& local_partition_path,
storage::SpecialStoragePolicy* special_storage_policy) {
+ base::FilePath storage_dir;
+ if (!profile_path.empty())
+ storage_dir = local_partition_path.AppendASCII(kLocalStorageDirectory);
+ mojo_state_.reset(new MojoState(mojo_user_id, storage_dir));
+
+ base::FilePath data_path;
+ if (!profile_path.empty())
+ data_path = profile_path.Append(local_partition_path);
base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
context_ = new DOMStorageContextImpl(
data_path.empty() ? data_path
@@ -83,8 +257,7 @@ DOMStorageContextWrapper::DOMStorageContextWrapper(
.get()));
}
-DOMStorageContextWrapper::~DOMStorageContextWrapper() {
-}
+DOMStorageContextWrapper::~DOMStorageContextWrapper() {}
void DOMStorageContextWrapper::GetLocalStorageUsage(
const GetLocalStorageUsageCallback& callback) {
@@ -92,7 +265,8 @@ void DOMStorageContextWrapper::GetLocalStorageUsage(
context_->task_runner()->PostShutdownBlockingTask(
FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
base::Bind(&GetLocalStorageUsageHelper,
- base::ThreadTaskRunnerHandle::Get(), context_, callback));
+ base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
+ base::RetainedRef(context_), callback));
}
void DOMStorageContextWrapper::GetSessionStorageUsage(
@@ -101,7 +275,8 @@ void DOMStorageContextWrapper::GetSessionStorageUsage(
context_->task_runner()->PostShutdownBlockingTask(
FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
base::Bind(&GetSessionStorageUsageHelper,
- base::ThreadTaskRunnerHandle::Get(), context_, callback));
+ base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
+ base::RetainedRef(context_), callback));
}
void DOMStorageContextWrapper::DeleteLocalStorage(const GURL& origin) {
@@ -153,6 +328,7 @@ void DOMStorageContextWrapper::SetForceKeepSessionState() {
void DOMStorageContextWrapper::Shutdown() {
DCHECK(context_.get());
+ mojo_state_.reset();
context_->task_runner()->PostShutdownBlockingTask(
FROM_HERE,
DOMStorageTaskRunner::PRIMARY_SEQUENCE,
@@ -166,4 +342,12 @@ void DOMStorageContextWrapper::Flush() {
base::Bind(&DOMStorageContextImpl::Flush, context_));
}
+void DOMStorageContextWrapper::OpenLocalStorage(
+ const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request) {
+ mojo_state_->OpenLocalStorage(
+ origin, std::move(observer), std::move(request));
+}
+
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
index 53033447ca1..56196a1f997 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -5,12 +5,15 @@
#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
+#include <map>
#include <string>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
+#include "content/common/storage_partition_service.mojom.h"
#include "content/public/browser/dom_storage_context.h"
+#include "url/origin.h"
namespace base {
class FilePath;
@@ -23,16 +26,19 @@ class SpecialStoragePolicy;
namespace content {
class DOMStorageContextImpl;
+class LevelDBWrapperImpl;
-// This is owned by BrowserContext (aka Profile) and encapsulates all
-// per-profile dom storage state.
+// This is owned by Storage Partition and encapsulates all its dom storage
+// state.
class CONTENT_EXPORT DOMStorageContextWrapper :
NON_EXPORTED_BASE(public DOMStorageContext),
public base::RefCountedThreadSafe<DOMStorageContextWrapper> {
public:
// If |data_path| is empty, nothing will be saved to disk.
DOMStorageContextWrapper(
+ const std::string& mojo_user_id,
const base::FilePath& data_path,
+ const base::FilePath& local_partition_path,
storage::SpecialStoragePolicy* special_storage_policy);
// DOMStorageContext implementation.
@@ -58,6 +64,11 @@ class CONTENT_EXPORT DOMStorageContextWrapper :
void Flush();
+ // See mojom::StoragePartitionService interface.
+ void OpenLocalStorage(const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojom::LevelDBWrapperRequest request);
+
private:
friend class DOMStorageMessageFilter; // for access to context()
friend class SessionStorageNamespaceImpl; // ditto
@@ -66,6 +77,11 @@ class CONTENT_EXPORT DOMStorageContextWrapper :
~DOMStorageContextWrapper() override;
DOMStorageContextImpl* context() const { return context_.get(); }
+ // An inner class to keep all mojo-ish details together and not bleed them
+ // through the public interface.
+ class MojoState;
+ scoped_ptr<MojoState> mojo_state_;
+
scoped_refptr<DOMStorageContextImpl> context_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContextWrapper);
diff --git a/chromium/content/browser/dom_storage/dom_storage_host.cc b/chromium/content/browser/dom_storage/dom_storage_host.cc
index 14d288d8653..3db7d5a15ec 100644
--- a/chromium/content/browser/dom_storage/dom_storage_host.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_host.cc
@@ -153,6 +153,8 @@ DOMStorageNamespace* DOMStorageHost::GetNamespace(int connection_id) {
// NamespaceAndArea
DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {}
+DOMStorageHost::NamespaceAndArea::NamespaceAndArea(
+ const NamespaceAndArea& other) = default;
DOMStorageHost::NamespaceAndArea::~NamespaceAndArea() {}
} // namespace content
diff --git a/chromium/content/browser/dom_storage/dom_storage_host.h b/chromium/content/browser/dom_storage/dom_storage_host.h
index 9b79406cbd2..d53bd154eec 100644
--- a/chromium/content/browser/dom_storage/dom_storage_host.h
+++ b/chromium/content/browser/dom_storage/dom_storage_host.h
@@ -57,6 +57,7 @@ class CONTENT_EXPORT DOMStorageHost {
scoped_refptr<DOMStorageNamespace> namespace_;
scoped_refptr<DOMStorageArea> area_;
NamespaceAndArea();
+ NamespaceAndArea(const NamespaceAndArea& other);
~NamespaceAndArea();
};
typedef std::map<int, NamespaceAndArea > AreaMap;
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.cc b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
index 25e44e53e3f..a8681b6e6c2 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
@@ -195,6 +195,8 @@ DOMStorageNamespace::AreaHolder::AreaHolder(
: area_(area), open_count_(count) {
}
+DOMStorageNamespace::AreaHolder::AreaHolder(const AreaHolder& other) = default;
+
DOMStorageNamespace::AreaHolder::~AreaHolder() {
}
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.h b/chromium/content/browser/dom_storage/dom_storage_namespace.h
index a9f65693fe8..238b7ca554e 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.h
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.h
@@ -86,6 +86,7 @@ class CONTENT_EXPORT DOMStorageNamespace
int open_count_;
AreaHolder();
AreaHolder(DOMStorageArea* area, int count);
+ AreaHolder(const AreaHolder& other);
~AreaHolder();
};
typedef std::map<GURL, AreaHolder> AreaMap;
diff --git a/chromium/content/browser/dom_storage/session_storage_database.cc b/chromium/content/browser/dom_storage/session_storage_database.cc
index ec246164e34..0aea7c7cc34 100644
--- a/chromium/content/browser/dom_storage/session_storage_database.cc
+++ b/chromium/content/browser/dom_storage/session_storage_database.cc
@@ -383,6 +383,9 @@ leveldb::Status SessionStorageDatabase::TryToOpen(leveldb::DB** db) {
options.max_open_files = 0; // Use minimum.
options.create_if_missing = true;
options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
+ // Default write_buffer_size is 4 MB but that might leave a 3.999
+ // memory allocation in RAM from a log file recovery.
+ options.write_buffer_size = 64 * 1024;
return leveldb::DB::Open(options, file_path_.AsUTF8Unsafe(), db);
}
diff --git a/chromium/content/browser/download/OWNERS b/chromium/content/browser/download/OWNERS
index 9e1fc0676f3..27f3217e697 100644
--- a/chromium/content/browser/download/OWNERS
+++ b/chromium/content/browser/download/OWNERS
@@ -1,4 +1,2 @@
-ahendrickson@chromium.org
asanka@chromium.org
-phajdan.jr@chromium.org
rdsmith@chromium.org
diff --git a/chromium/content/browser/download/base_file.cc b/chromium/content/browser/download/base_file.cc
index 8fda8de6a5c..74072bb1f72 100644
--- a/chromium/content/browser/download/base_file.cc
+++ b/chromium/content/browser/download/base_file.cc
@@ -25,38 +25,8 @@
namespace content {
-// This will initialize the entire array to zero.
-const unsigned char BaseFile::kEmptySha256Hash[] = { 0 };
-
-BaseFile::BaseFile(const base::FilePath& full_path,
- const GURL& source_url,
- const GURL& referrer_url,
- int64_t received_bytes,
- bool calculate_hash,
- const std::string& hash_state_bytes,
- base::File file,
- const net::BoundNetLog& bound_net_log)
- : full_path_(full_path),
- source_url_(source_url),
- referrer_url_(referrer_url),
- file_(std::move(file)),
- bytes_so_far_(received_bytes),
- start_tick_(base::TimeTicks::Now()),
- calculate_hash_(calculate_hash),
- detached_(false),
- bound_net_log_(bound_net_log) {
- memcpy(sha256_hash_, kEmptySha256Hash, crypto::kSHA256Length);
- if (calculate_hash_) {
- secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- if ((bytes_so_far_ > 0) && // Not starting at the beginning.
- (!IsEmptyHash(hash_state_bytes))) {
- base::Pickle hash_state(hash_state_bytes.c_str(),
- hash_state_bytes.size());
- base::PickleIterator data_iterator(hash_state);
- secure_hash_->Deserialize(&data_iterator);
- }
- }
-}
+BaseFile::BaseFile(const net::BoundNetLog& bound_net_log)
+ : bound_net_log_(bound_net_log) {}
BaseFile::~BaseFile() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
@@ -67,11 +37,16 @@ BaseFile::~BaseFile() {
}
DownloadInterruptReason BaseFile::Initialize(
- const base::FilePath& default_directory) {
+ const base::FilePath& full_path,
+ const base::FilePath& default_directory,
+ base::File file,
+ int64_t bytes_so_far,
+ const std::string& hash_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
- if (full_path_.empty()) {
+ if (full_path.empty()) {
base::FilePath initial_directory(default_directory);
base::FilePath temp_file;
if (initial_directory.empty()) {
@@ -87,9 +62,15 @@ DownloadInterruptReason BaseFile::Initialize(
DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
}
full_path_ = temp_file;
+ } else {
+ full_path_ = full_path;
}
- return Open();
+ bytes_so_far_ = bytes_so_far;
+ secure_hash_ = std::move(hash_state);
+ file_ = std::move(file);
+
+ return Open(hash_so_far);
}
DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
@@ -134,7 +115,7 @@ DownloadInterruptReason BaseFile::AppendDataToFile(const char* data,
RecordDownloadWriteSize(data_len);
RecordDownloadWriteLoopCount(write_count);
- if (calculate_hash_)
+ if (secure_hash_)
secure_hash_->Update(data, data_len);
return DOWNLOAD_INTERRUPT_REASON_NONE;
@@ -170,7 +151,7 @@ DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) {
// reason.
DownloadInterruptReason open_result = DOWNLOAD_INTERRUPT_REASON_NONE;
if (was_in_progress)
- open_result = Open();
+ open_result = Open(std::string());
bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_RENAMED);
return rename_result == DOWNLOAD_INTERRUPT_REASON_NONE ? open_result
@@ -198,92 +179,127 @@ void BaseFile::Cancel() {
Detach();
}
-void BaseFile::Finish() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
- if (calculate_hash_)
- secure_hash_->Finish(sha256_hash_, crypto::kSHA256Length);
- Close();
-}
-
-void BaseFile::FinishWithError() {
+scoped_ptr<crypto::SecureHash> BaseFile::Finish() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
Close();
-}
-
-void BaseFile::SetClientGuid(const std::string& guid) {
- client_guid_ = guid;
+ return std::move(secure_hash_);
}
// OS_WIN, OS_MACOSX and OS_LINUX have specialized implementations.
#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_LINUX)
-DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
+DownloadInterruptReason BaseFile::AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url) {
return DOWNLOAD_INTERRUPT_REASON_NONE;
}
#endif
-bool BaseFile::GetHash(std::string* hash) {
- DCHECK(!detached_);
- hash->assign(reinterpret_cast<const char*>(sha256_hash_),
- sizeof(sha256_hash_));
- return (calculate_hash_ && !in_progress());
+std::string BaseFile::DebugString() const {
+ return base::StringPrintf(
+ "{ "
+ " full_path_ = \"%" PRFilePath
+ "\""
+ " bytes_so_far_ = %" PRId64 " detached_ = %c }",
+ full_path_.value().c_str(),
+ bytes_so_far_,
+ detached_ ? 'T' : 'F');
}
-std::string BaseFile::GetHashState() {
- if (!calculate_hash_)
- return std::string();
+DownloadInterruptReason BaseFile::CalculatePartialHash(
+ const std::string& hash_to_expect) {
+ secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- base::Pickle hash_state;
- if (!secure_hash_->Serialize(&hash_state))
- return std::string();
+ if (bytes_so_far_ == 0)
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
- return std::string(reinterpret_cast<const char*>(hash_state.data()),
- hash_state.size());
-}
+ if (file_.Seek(base::File::FROM_BEGIN, 0) != 0)
+ return LogSystemError("Seek partial file",
+ logging::GetLastSystemErrorCode());
+
+ const size_t kMinBufferSize = secure_hash_->GetHashLength();
+ const size_t kMaxBufferSize = 1024 * 512;
+
+ // The size of the buffer is:
+ // - at least kMinBufferSize so that we can use it to hold the hash as well.
+ // - at most kMaxBufferSize so that there's a reasonable bound.
+ // - not larger than |bytes_so_far_| unless bytes_so_far_ is less than the
+ // hash size.
+ std::vector<char> buffer(std::max(
+ kMinBufferSize, std::min<size_t>(kMaxBufferSize, bytes_so_far_)));
+
+ int64_t current_position = 0;
+ while (current_position < bytes_so_far_) {
+ int length = file_.ReadAtCurrentPos(&buffer.front(), buffer.size());
+ if (length == -1) {
+ return LogInterruptReason("Reading partial file",
+ logging::GetLastSystemErrorCode(),
+ DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT);
+ }
-// static
-bool BaseFile::IsEmptyHash(const std::string& hash) {
- return (hash.size() == crypto::kSHA256Length &&
- 0 == memcmp(hash.data(), kEmptySha256Hash, crypto::kSHA256Length));
-}
+ if (length == 0)
+ break;
-std::string BaseFile::DebugString() const {
- return base::StringPrintf("{ source_url_ = \"%s\""
- " full_path_ = \"%" PRFilePath "\""
- " bytes_so_far_ = %" PRId64
- " detached_ = %c }",
- source_url_.spec().c_str(),
- full_path_.value().c_str(),
- bytes_so_far_,
- detached_ ? 'T' : 'F');
+ secure_hash_->Update(&buffer.front(), length);
+ current_position += length;
+ }
+
+ if (current_position != bytes_so_far_) {
+ return LogInterruptReason(
+ "Verifying prefix hash", 0, DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT);
+ }
+
+ if (!hash_to_expect.empty()) {
+ DCHECK_EQ(secure_hash_->GetHashLength(), hash_to_expect.size());
+ DCHECK(buffer.size() >= secure_hash_->GetHashLength());
+ scoped_ptr<crypto::SecureHash> partial_hash(secure_hash_->Clone());
+ partial_hash->Finish(&buffer.front(), buffer.size());
+
+ if (memcmp(&buffer.front(),
+ hash_to_expect.c_str(),
+ partial_hash->GetHashLength())) {
+ return LogInterruptReason("Verifying prefix hash",
+ 0,
+ DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH);
+ }
+ }
+
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
}
-DownloadInterruptReason BaseFile::Open() {
+DownloadInterruptReason BaseFile::Open(const std::string& hash_so_far) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
DCHECK(!full_path_.empty());
- bound_net_log_.BeginEvent(
- net::NetLog::TYPE_DOWNLOAD_FILE_OPENED,
- base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_));
-
// Create a new file if it is not provided.
if (!file_.IsValid()) {
- file_.Initialize(
- full_path_, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE);
+ file_.Initialize(full_path_,
+ base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
+ base::File::FLAG_READ);
if (!file_.IsValid()) {
- return LogNetError("Open",
+ return LogNetError("Open/Initialize File",
net::FileErrorToNetError(file_.error_details()));
}
}
- // We may be re-opening the file after rename. Always make sure we're
- // writing at the end of the file.
+ bound_net_log_.BeginEvent(
+ net::NetLog::TYPE_DOWNLOAD_FILE_OPENED,
+ base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_));
+
+ if (!secure_hash_) {
+ DownloadInterruptReason reason = CalculatePartialHash(hash_so_far);
+ if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
+ ClearFile();
+ return reason;
+ }
+ }
+
int64_t file_size = file_.Seek(base::File::FROM_END, 0);
if (file_size < 0) {
logging::SystemErrorCode error = logging::GetLastSystemErrorCode();
ClearFile();
- return LogSystemError("Seek", error);
+ return LogSystemError("Seeking to end", error);
} else if (file_size > bytes_so_far_) {
// The file is larger than we expected.
// This is OK, as long as we don't use the extra.
@@ -292,7 +308,7 @@ DownloadInterruptReason BaseFile::Open() {
file_.Seek(base::File::FROM_BEGIN, bytes_so_far_) != bytes_so_far_) {
logging::SystemErrorCode error = logging::GetLastSystemErrorCode();
ClearFile();
- return LogSystemError("Truncate", error);
+ return LogSystemError("Truncating to last known offset", error);
}
} else if (file_size < bytes_so_far_) {
// The file is shorter than we expected. Our hashes won't be valid.
@@ -347,6 +363,9 @@ DownloadInterruptReason BaseFile::LogInterruptReason(
const char* operation,
int os_error,
DownloadInterruptReason reason) {
+ DVLOG(1) << __FUNCTION__ << "() operation:" << operation
+ << " os_error:" << os_error
+ << " reason:" << DownloadInterruptReasonToString(reason);
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_FILE_ERROR,
base::Bind(&FileInterruptedNetLogCallback, operation, os_error, reason));
diff --git a/chromium/content/browser/download/base_file.h b/chromium/content/browser/download/base_file.h
index cc87ae6ce67..139d43b9bb5 100644
--- a/chromium/content/browser/download/base_file.h
+++ b/chromium/content/browser/download/base_file.h
@@ -20,40 +20,72 @@
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/browser/download_interrupt_reasons.h"
-#include "crypto/sha2.h"
+#include "crypto/secure_hash.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
#include "url/gurl.h"
-namespace crypto {
-class SecureHash;
-}
-
namespace content {
// File being downloaded and saved to disk. This is a base class
-// for DownloadFile and SaveFile, which keep more state information.
+// for DownloadFile and SaveFile, which keep more state information. BaseFile
+// considers itself the owner of the physical file and will delete it when the
+// BaseFile object is destroyed unless the ownership is revoked via a call to
+// Detach().
class CONTENT_EXPORT BaseFile {
public:
// May be constructed on any thread. All other routines (including
// destruction) must occur on the FILE thread.
- BaseFile(const base::FilePath& full_path,
- const GURL& source_url,
- const GURL& referrer_url,
- int64_t received_bytes,
- bool calculate_hash,
- const std::string& hash_state,
- base::File file,
- const net::BoundNetLog& bound_net_log);
- virtual ~BaseFile();
+ BaseFile(const net::BoundNetLog& bound_net_log);
+ ~BaseFile();
// Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a
- // DownloadInterruptReason on failure. |default_directory| specifies the
- // directory to create the temporary file in if |full_path()| is empty. If
- // |default_directory| and |full_path()| are empty, then a temporary file will
- // be created in the default download location as determined by
- // ContentBrowserClient.
- DownloadInterruptReason Initialize(const base::FilePath& default_directory);
+ // DownloadInterruptReason on failure. Upon success, the file at |full_path()|
+ // is assumed to be owned by the BaseFile. It will be deleted when the
+ // BaseFile object is destroyed unless Detach() is called before destroying
+ // the BaseFile instance.
+ //
+ // |full_path|: Full path to the download file. Can be empty, in which case
+ // the rules described in |default_directory| will be used to generate a
+ // temporary filename.
+ //
+ // |default_directory|: specifies the directory to create the temporary file
+ // in if |full_path| is empty. If |default_directory| and |full_path| are
+ // empty, then a temporary file will be created in the default download
+ // location as determined by ContentBrowserClient.
+ //
+ // |file|: The base::File handle to use. If specified, BaseFile will not open
+ // a file and will use this handle. The file should be opened for both
+ // read and write. Only makes sense if |full_path| is non-empty since it
+ // implies that the caller already knows the path to the file. There's no
+ // perfect way to come up with a canonical path for a file. So BaseFile
+ // will not attempt to determine the |full_path|.
+ //
+ // |bytes_so_far|: If a file is provided (via |full_path| or |file|), then
+ // this argument specifies the size of the file to expect. It is legal for
+ // the file to be larger, in which case the file will be truncated down to
+ // this size. However, if the file is shorter, then the operation will
+ // fail with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT.
+ //
+ // |hash_so_far|: If |bytes_so_far| is non-zero, this specifies the SHA-256
+ // hash of the first |bytes_so_far| bytes of the target file. If
+ // specified, BaseFile will read the first |bytes_so_far| of the target
+ // file in order to calculate the hash and verify that the file matches.
+ // If there's a mismatch, then the operation fails with
+ // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. Not used if |hash_state|
+ // is also specified.
+ //
+ // |hash_state|: The partial hash object to use. Only meaningful if there's a
+ // preexisting target file and it is non-empty (i.e. bytes_so_far is
+ // non-zero). If specified, BaseFile will assume that the bytes up to
+ // |bytes_so_far| has been accurately hashed into |hash_state| and will
+ // ignore |hash_so_far|.
+ DownloadInterruptReason Initialize(const base::FilePath& full_path,
+ const base::FilePath& default_directory,
+ base::File file,
+ int64_t bytes_so_far,
+ const std::string& hash_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state);
// Write a new chunk of data to the file. Returns a DownloadInterruptReason
// indicating the result of the operation.
@@ -63,33 +95,39 @@ class CONTENT_EXPORT BaseFile {
// result of the operation. A return code of NONE indicates that the rename
// was successful. After a failure, the full_path() and in_progress() can be
// used to determine the last known filename and whether the file is available
- // for writing or retrying the rename.
- virtual DownloadInterruptReason Rename(const base::FilePath& full_path);
-
- // Detach the file so it is not deleted on destruction.
- virtual void Detach();
-
- // Abort the download and automatically close the file.
+ // for writing or retrying the rename. Call Finish() to obtain the last known
+ // hash state.
+ DownloadInterruptReason Rename(const base::FilePath& full_path);
+
+ // Mark the file as detached. Up until this method is called, BaseFile assumes
+ // ownership of the file and hence will delete the file if the BaseFile object
+ // is destroyed. Calling Detach() causes BaseFile to assume that it no longer
+ // owns the file. Detach() can be called at any time. Close() must still be
+ // called to close the file if it is open.
+ void Detach();
+
+ // Abort the download and automatically close and delete the file.
void Cancel();
// Indicate that the download has finished. No new data will be received.
- void Finish();
-
- // Indicate that the download is being aborted due to an error. This is
- // identical to Finish() with the exception that the hash state will not be
- // finalized.
- void FinishWithError();
-
- // Set the client guid which will be used to identify the app to the
- // system AV scanning function. Should be called before
- // AnnotateWithSourceInformation() to take effect.
- void SetClientGuid(const std::string& guid);
+ // Returns the SecureHash object representing the state of the hash function
+ // at the end of the operation.
+ scoped_ptr<crypto::SecureHash> Finish();
// Informs the OS that this file came from the internet. Returns a
// DownloadInterruptReason indicating the result of the operation.
- // Note: SetClientGuid() should be called before this function on
- // Windows to ensure the correct app client ID is available.
- DownloadInterruptReason AnnotateWithSourceInformation();
+ //
+ // |client_guid|: The client GUID which will be used to identify the caller to
+ // the system AV scanning function.
+ //
+ // |source_url| / |referrer_url|: Source and referrer for the network request
+ // that originated this download. Will be used to annotate source
+ // information and also to determine the relative danger level of the
+ // file.
+ DownloadInterruptReason AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url);
// Returns the last known path to the download file. Can be empty if there's
// no file.
@@ -102,26 +140,27 @@ class CONTENT_EXPORT BaseFile {
// Returns the number of bytes in the file pointed to by full_path().
int64_t bytes_so_far() const { return bytes_so_far_; }
- // Fills |hash| with the hash digest for the file.
- // Returns true if digest is successfully calculated.
- virtual bool GetHash(std::string* hash);
-
- // Returns the current (intermediate) state of the hash as a byte string.
- virtual std::string GetHashState();
-
- // Returns true if the given hash is considered empty. An empty hash is
- // a string of size crypto::kSHA256Length that contains only zeros (initial
- // value for the hash).
- static bool IsEmptyHash(const std::string& hash);
-
- virtual std::string DebugString() const;
+ std::string DebugString() const;
private:
friend class BaseFileTest;
FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash);
- // Creates and opens the file_ if it is NULL.
- DownloadInterruptReason Open();
+ // Creates and opens the file_ if it is invalid.
+ //
+ // If |hash_so_far| is not empty, then it must match the SHA-256 hash of the
+ // first |bytes_so_far_| bytes of |file_|. If there's a hash mismatch, Open()
+ // fails with DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH.
+ //
+ // If the opened file is shorter than |bytes_so_far_| bytes, then Open() fails
+ // with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If the opened file is
+ // longer, then the file is truncated to |bytes_so_far_|.
+ //
+ // Open() can fail for other reasons as well. In that case, it returns a
+ // relevant interrupt reason. Unless Open() return
+ // DOWNLOAD_INTERRUPT_REASON_NONE, it should be assumed that |file_| is not
+ // valid.
+ DownloadInterruptReason Open(const std::string& hash_so_far);
// Closes and resets file_.
void Close();
@@ -138,6 +177,17 @@ class CONTENT_EXPORT BaseFile {
// Split out from CurrentSpeed to enable testing.
int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const;
+ // Verifies that:
+ // * Size of the file represented by |file_| is at least |bytes_so_far_|.
+ //
+ // * If |hash_to_expect| is not empty, then the result of hashing the first
+ // |bytes_so_far_| bytes of |file_| matches |hash_to_expect|.
+ //
+ // If the result is REASON_NONE, then on return |secure_hash_| is valid and
+ // is ready to hash bytes from offset |bytes_so_far_| + 1.
+ DownloadInterruptReason CalculatePartialHash(
+ const std::string& hash_to_expect);
+
// Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error
// on through, converting to a |DownloadInterruptReason|.
DownloadInterruptReason LogNetError(const char* operation, net::Error error);
@@ -153,40 +203,24 @@ class CONTENT_EXPORT BaseFile {
const char* operation, int os_error,
DownloadInterruptReason reason);
- static const unsigned char kEmptySha256Hash[crypto::kSHA256Length];
-
// Full path to the file including the file name.
base::FilePath full_path_;
- // Source URL for the file being downloaded.
- GURL source_url_;
-
- // The URL where the download was initiated.
- GURL referrer_url_;
-
- std::string client_guid_;
-
// OS file for writing
base::File file_;
// Amount of data received up so far, in bytes.
- int64_t bytes_so_far_;
+ int64_t bytes_so_far_ = 0;
- // Start time for calculating speed.
- base::TimeTicks start_tick_;
-
- // Indicates if hash should be calculated for the file.
- bool calculate_hash_;
-
- // Used to calculate hash for the file when calculate_hash_
- // is set.
+ // Used to calculate hash for the file when calculate_hash_ is set.
scoped_ptr<crypto::SecureHash> secure_hash_;
- unsigned char sha256_hash_[crypto::kSHA256Length];
+ // Start time for calculating speed.
+ base::TimeTicks start_tick_;
// Indicates that this class no longer owns the associated file, and so
// won't delete it on destruction.
- bool detached_;
+ bool detached_ = false;
net::BoundNetLog bound_net_log_;
diff --git a/chromium/content/browser/download/base_file_linux.cc b/chromium/content/browser/download/base_file_linux.cc
index 721cd602694..6c62be32302 100644
--- a/chromium/content/browser/download/base_file_linux.cc
+++ b/chromium/content/browser/download/base_file_linux.cc
@@ -9,11 +9,14 @@
namespace content {
-DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
+DownloadInterruptReason BaseFile::AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
- AddOriginMetadataToFile(full_path_, source_url_, referrer_url_);
+ AddOriginMetadataToFile(full_path_, source_url, referrer_url);
return DOWNLOAD_INTERRUPT_REASON_NONE;
}
diff --git a/chromium/content/browser/download/base_file_mac.cc b/chromium/content/browser/download/base_file_mac.cc
index f3edf12d094..4ece61b90d7 100644
--- a/chromium/content/browser/download/base_file_mac.cc
+++ b/chromium/content/browser/download/base_file_mac.cc
@@ -9,12 +9,15 @@
namespace content {
-DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
+DownloadInterruptReason BaseFile::AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
- AddQuarantineMetadataToFile(full_path_, source_url_, referrer_url_);
- AddOriginMetadataToFile(full_path_, source_url_, referrer_url_);
+ AddQuarantineMetadataToFile(full_path_, source_url, referrer_url);
+ AddOriginMetadataToFile(full_path_, source_url, referrer_url);
return DOWNLOAD_INTERRUPT_REASON_NONE;
}
diff --git a/chromium/content/browser/download/base_file_unittest.cc b/chromium/content/browser/download/base_file_unittest.cc
index a6ce347c189..8f2412b17d9 100644
--- a/chromium/content/browser/download/base_file_unittest.cc
+++ b/chromium/content/browser/download/base_file_unittest.cc
@@ -32,12 +32,24 @@ const char kTestData3[] = "Final line.";
const char kTestData4[] = "supercalifragilisticexpialidocious";
const int kTestDataLength1 = arraysize(kTestData1) - 1;
const int kTestDataLength2 = arraysize(kTestData2) - 1;
-const int kTestDataLength3 = arraysize(kTestData3) - 1;
const int kTestDataLength4 = arraysize(kTestData4) - 1;
const int kElapsedTimeSeconds = 5;
const base::TimeDelta kElapsedTimeDelta = base::TimeDelta::FromSeconds(
kElapsedTimeSeconds);
+// SHA-256 hash of kTestData1 (excluding terminating NUL).
+const uint8_t kHashOfTestData1[] = {
+ 0x0b, 0x2d, 0x3f, 0x3f, 0x79, 0x43, 0xad, 0x64, 0xb8, 0x60, 0xdf,
+ 0x94, 0xd0, 0x5c, 0xb5, 0x6a, 0x8a, 0x97, 0xc6, 0xec, 0x57, 0x68,
+ 0xb5, 0xb7, 0x0b, 0x93, 0x0c, 0x5a, 0xa7, 0xfa, 0x9a, 0xde};
+
+// SHA-256 hash of kTestData1 ++ kTestData2 ++ kTestData3 (excluding terminating
+// NUL).
+const uint8_t kHashOfTestData1To3[] = {
+ 0xcb, 0xf6, 0x8b, 0xf1, 0x0f, 0x80, 0x03, 0xdb, 0x86, 0xb3, 0x13,
+ 0x43, 0xaf, 0xac, 0x8c, 0x71, 0x75, 0xbd, 0x03, 0xfb, 0x5f, 0xc9,
+ 0x05, 0x65, 0x0f, 0x8c, 0x80, 0xaf, 0x08, 0x74, 0x43, 0xa8};
+
} // namespace
class BaseFileTest : public testing::Test {
@@ -52,16 +64,8 @@ class BaseFileTest : public testing::Test {
}
void SetUp() override {
- ResetHash();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base_file_.reset(new BaseFile(base::FilePath(),
- GURL(),
- GURL(),
- 0,
- false,
- std::string(),
- base::File(),
- net::BoundNetLog()));
+ base_file_.reset(new BaseFile(net::BoundNetLog()));
}
void TearDown() override {
@@ -87,36 +91,14 @@ class BaseFileTest : public testing::Test {
EXPECT_EQ(expect_file_survives_, base::PathExists(full_path));
}
- void ResetHash() {
- secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- memcpy(sha256_hash_, kEmptySha256Hash, crypto::kSHA256Length);
- }
-
- void UpdateHash(const char* data, size_t length) {
- secure_hash_->Update(data, length);
- }
-
- std::string GetFinalHash() {
- std::string hash;
- secure_hash_->Finish(sha256_hash_, crypto::kSHA256Length);
- hash.assign(reinterpret_cast<const char*>(sha256_hash_),
- sizeof(sha256_hash_));
- return hash;
- }
-
- void MakeFileWithHash() {
- base_file_.reset(new BaseFile(base::FilePath(),
- GURL(),
- GURL(),
- 0,
- true,
- std::string(),
- base::File(),
- net::BoundNetLog()));
- }
-
bool InitializeFile() {
- DownloadInterruptReason result = base_file_->Initialize(temp_dir_.path());
+ DownloadInterruptReason result =
+ base_file_->Initialize(base::FilePath(),
+ temp_dir_.path(),
+ base::File(),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>());
EXPECT_EQ(expected_error_, result);
return result == DOWNLOAD_INTERRUPT_REASON_NONE;
}
@@ -145,17 +127,15 @@ class BaseFileTest : public testing::Test {
// Create a file. Returns the complete file path.
base::FilePath CreateTestFile() {
base::FilePath file_name;
- BaseFile file(base::FilePath(),
- GURL(),
- GURL(),
- 0,
- false,
- std::string(),
- base::File(),
- net::BoundNetLog());
+ BaseFile file((net::BoundNetLog()));
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- file.Initialize(temp_dir_.path()));
+ file.Initialize(base::FilePath(),
+ temp_dir_.path(),
+ base::File(),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
file_name = file.full_path();
EXPECT_NE(base::FilePath::StringType(), file_name.value());
@@ -171,16 +151,14 @@ class BaseFileTest : public testing::Test {
// Create a file with the specified file name.
void CreateFileWithName(const base::FilePath& file_name) {
EXPECT_NE(base::FilePath::StringType(), file_name.value());
- BaseFile duplicate_file(file_name,
- GURL(),
- GURL(),
- 0,
- false,
- std::string(),
- base::File(),
- net::BoundNetLog());
+ BaseFile duplicate_file((net::BoundNetLog()));
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- duplicate_file.Initialize(temp_dir_.path()));
+ duplicate_file.Initialize(file_name,
+ temp_dir_.path(),
+ base::File(),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
// Write something into it.
duplicate_file.AppendDataToFile(kTestData4, kTestDataLength4);
// Detach the file so it isn't deleted on destruction of |duplicate_file|.
@@ -207,6 +185,15 @@ class BaseFileTest : public testing::Test {
<< "Interrupt reason = " << err;
}
+ template <size_t SZ>
+ static void ExpectHashValue(const uint8_t (&expected_hash)[SZ],
+ scoped_ptr<crypto::SecureHash> hash_state) {
+ std::vector<uint8_t> hash_value(hash_state->GetHashLength());
+ hash_state->Finish(&hash_value.front(), hash_value.size());
+ ASSERT_EQ(SZ, hash_value.size());
+ EXPECT_EQ(0, memcmp(expected_hash, &hash_value.front(), hash_value.size()));
+ }
+
protected:
// BaseClass instance we are testing.
scoped_ptr<BaseFile> base_file_;
@@ -220,11 +207,6 @@ class BaseFileTest : public testing::Test {
// Expect the file to be in progress.
bool expect_in_progress_;
- // Hash calculator.
- scoped_ptr<crypto::SecureHash> secure_hash_;
-
- unsigned char sha256_hash_[crypto::kSHA256Length];
-
private:
// Keep track of what data should be saved to the disk file.
std::string expected_data_;
@@ -266,24 +248,9 @@ TEST_F(BaseFileTest, WriteAndDetach) {
// Write data to the file and detach it, and calculate its sha256 hash.
TEST_F(BaseFileTest, WriteWithHashAndDetach) {
- // Calculate the final hash.
- ResetHash();
- UpdateHash(kTestData1, kTestDataLength1);
- std::string expected_hash = GetFinalHash();
- std::string expected_hash_hex =
- base::HexEncode(expected_hash.data(), expected_hash.size());
-
- MakeFileWithHash();
ASSERT_TRUE(InitializeFile());
ASSERT_TRUE(AppendDataToFile(kTestData1));
- base_file_->Finish();
-
- std::string hash;
- base_file_->GetHash(&hash);
- EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE",
- expected_hash_hex);
- EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
-
+ ExpectHashValue(kHashOfTestData1, base_file_->Finish());
base_file_->Detach();
expect_file_survives_ = true;
}
@@ -303,7 +270,7 @@ TEST_F(BaseFileTest, WriteThenRenameAndDetach) {
EXPECT_FALSE(base::PathExists(initial_path));
EXPECT_TRUE(base::PathExists(new_path));
- base_file_->Finish();
+ ExpectHashValue(kHashOfTestData1, base_file_->Finish());
base_file_->Detach();
expect_file_survives_ = true;
}
@@ -312,7 +279,7 @@ TEST_F(BaseFileTest, WriteThenRenameAndDetach) {
TEST_F(BaseFileTest, SingleWrite) {
ASSERT_TRUE(InitializeFile());
ASSERT_TRUE(AppendDataToFile(kTestData1));
- base_file_->Finish();
+ ExpectHashValue(kHashOfTestData1, base_file_->Finish());
}
// Write data to the file multiple times.
@@ -321,82 +288,18 @@ TEST_F(BaseFileTest, MultipleWrites) {
ASSERT_TRUE(AppendDataToFile(kTestData1));
ASSERT_TRUE(AppendDataToFile(kTestData2));
ASSERT_TRUE(AppendDataToFile(kTestData3));
- std::string hash;
- EXPECT_FALSE(base_file_->GetHash(&hash));
- base_file_->Finish();
-}
-
-// Write data to the file once and calculate its sha256 hash.
-TEST_F(BaseFileTest, SingleWriteWithHash) {
- // Calculate the final hash.
- ResetHash();
- UpdateHash(kTestData1, kTestDataLength1);
- std::string expected_hash = GetFinalHash();
- std::string expected_hash_hex =
- base::HexEncode(expected_hash.data(), expected_hash.size());
-
- MakeFileWithHash();
- ASSERT_TRUE(InitializeFile());
- // Can get partial hash states before Finish() is called.
- EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
- ASSERT_TRUE(AppendDataToFile(kTestData1));
- EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str());
- base_file_->Finish();
-
- std::string hash;
- base_file_->GetHash(&hash);
- EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
-}
-
-// Write data to the file multiple times and calculate its sha256 hash.
-TEST_F(BaseFileTest, MultipleWritesWithHash) {
- // Calculate the final hash.
- ResetHash();
- UpdateHash(kTestData1, kTestDataLength1);
- UpdateHash(kTestData2, kTestDataLength2);
- UpdateHash(kTestData3, kTestDataLength3);
- std::string expected_hash = GetFinalHash();
- std::string expected_hash_hex =
- base::HexEncode(expected_hash.data(), expected_hash.size());
-
- std::string hash;
- MakeFileWithHash();
- ASSERT_TRUE(InitializeFile());
- ASSERT_TRUE(AppendDataToFile(kTestData1));
- ASSERT_TRUE(AppendDataToFile(kTestData2));
- ASSERT_TRUE(AppendDataToFile(kTestData3));
- // No hash before Finish() is called.
- EXPECT_FALSE(base_file_->GetHash(&hash));
- base_file_->Finish();
-
- EXPECT_TRUE(base_file_->GetHash(&hash));
- EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8",
- expected_hash_hex);
- EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size()));
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
}
// Write data to the file multiple times, interrupt it, and continue using
// another file. Calculate the resulting combined sha256 hash.
TEST_F(BaseFileTest, MultipleWritesInterruptedWithHash) {
- // Calculate the final hash.
- ResetHash();
- UpdateHash(kTestData1, kTestDataLength1);
- UpdateHash(kTestData2, kTestDataLength2);
- UpdateHash(kTestData3, kTestDataLength3);
- std::string expected_hash = GetFinalHash();
- std::string expected_hash_hex =
- base::HexEncode(expected_hash.data(), expected_hash.size());
-
- MakeFileWithHash();
ASSERT_TRUE(InitializeFile());
// Write some data
ASSERT_TRUE(AppendDataToFile(kTestData1));
ASSERT_TRUE(AppendDataToFile(kTestData2));
// Get the hash state and file name.
- std::string hash_state;
- hash_state = base_file_->GetHashState();
- // Finish the file.
- base_file_->Finish();
+ scoped_ptr<crypto::SecureHash> hash_state = base_file_->Finish();
base::FilePath new_file_path(temp_dir_.path().Append(
base::FilePath(FILE_PATH_LITERAL("second_file"))));
@@ -404,26 +307,18 @@ TEST_F(BaseFileTest, MultipleWritesInterruptedWithHash) {
ASSERT_TRUE(base::CopyFile(base_file_->full_path(), new_file_path));
// Create another file
- BaseFile second_file(new_file_path,
- GURL(),
- GURL(),
- base_file_->bytes_so_far(),
- true,
- hash_state,
- base::File(),
- net::BoundNetLog());
+ BaseFile second_file((net::BoundNetLog()));
ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- second_file.Initialize(base::FilePath()));
+ second_file.Initialize(new_file_path,
+ base::FilePath(),
+ base::File(),
+ base_file_->bytes_so_far(),
+ std::string(),
+ std::move(hash_state)));
std::string data(kTestData3);
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
second_file.AppendDataToFile(data.data(), data.size()));
- second_file.Finish();
-
- std::string hash;
- EXPECT_TRUE(second_file.GetHash(&hash));
- // This will fail until getting the hash state is supported in SecureHash.
- EXPECT_STREQ(expected_hash_hex.c_str(),
- base::HexEncode(hash.data(), hash.size()).c_str());
+ ExpectHashValue(kHashOfTestData1To3, second_file.Finish());
}
// Rename the file after all writes to it.
@@ -442,7 +337,7 @@ TEST_F(BaseFileTest, WriteThenRename) {
EXPECT_FALSE(base::PathExists(initial_path));
EXPECT_TRUE(base::PathExists(new_path));
- base_file_->Finish();
+ ExpectHashValue(kHashOfTestData1, base_file_->Finish());
}
// Rename the file while the download is still in progress.
@@ -462,8 +357,9 @@ TEST_F(BaseFileTest, RenameWhileInProgress) {
EXPECT_TRUE(base::PathExists(new_path));
ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_TRUE(AppendDataToFile(kTestData3));
- base_file_->Finish();
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
}
// Test that a failed rename reports the correct error.
@@ -525,15 +421,7 @@ TEST_F(BaseFileTest, RenameWithErrorInProgress) {
ASSERT_EQ(new_path.value(), base_file_->full_path().value());
ASSERT_TRUE(AppendDataToFile(kTestData3));
- base_file_->Finish();
-
- // The contents of the file should be intact.
- std::string file_contents;
- std::string expected_contents(kTestData1);
- expected_contents += kTestData2;
- expected_contents += kTestData3;
- ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
- EXPECT_EQ(expected_contents, file_contents);
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
}
// Test that a failed write reports an error.
@@ -544,9 +432,14 @@ TEST_F(BaseFileTest, WriteWithError) {
// Pass a file handle which was opened without the WRITE flag.
// This should result in an error when writing.
base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
- base_file_.reset(new BaseFile(path, GURL(), GURL(), 0, false, std::string(),
- std::move(file), net::BoundNetLog()));
- ASSERT_TRUE(InitializeFile());
+ base_file_.reset(new BaseFile(net::BoundNetLog()));
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(path,
+ base::FilePath(),
+ std::move(file),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
#if defined(OS_WIN)
set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
#elif defined (OS_POSIX)
@@ -580,20 +473,17 @@ TEST_F(BaseFileTest, DuplicateBaseFile) {
TEST_F(BaseFileTest, AppendToBaseFile) {
// Create a new file.
base::FilePath existing_file_name = CreateTestFile();
-
set_expected_data(kTestData4);
// Use the file we've just created.
- base_file_.reset(new BaseFile(existing_file_name,
- GURL(),
- GURL(),
- kTestDataLength4,
- false,
- std::string(),
- base::File(),
- net::BoundNetLog()));
-
- ASSERT_TRUE(InitializeFile());
+ base_file_.reset(new BaseFile(net::BoundNetLog()));
+ ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(existing_file_name,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength4,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
const base::FilePath file_name = base_file_->full_path();
EXPECT_NE(base::FilePath::StringType(), file_name.value());
@@ -618,18 +508,16 @@ TEST_F(BaseFileTest, ReadonlyBaseFile) {
EXPECT_TRUE(base::MakeFileUnwritable(readonly_file_name));
// Try to overwrite it.
- base_file_.reset(new BaseFile(readonly_file_name,
- GURL(),
- GURL(),
- 0,
- false,
- std::string(),
- base::File(),
- net::BoundNetLog()));
+ base_file_.reset(new BaseFile(net::BoundNetLog()));
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
+ base_file_->Initialize(readonly_file_name,
+ base::FilePath(),
+ base::File(),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
expect_in_progress_ = false;
- set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
- EXPECT_FALSE(InitializeFile());
const base::FilePath file_name = base_file_->full_path();
EXPECT_NE(base::FilePath::StringType(), file_name.value());
@@ -643,16 +531,175 @@ TEST_F(BaseFileTest, ReadonlyBaseFile) {
expect_file_survives_ = true;
}
-TEST_F(BaseFileTest, IsEmptyHash) {
- std::string empty(crypto::kSHA256Length, '\x00');
- EXPECT_TRUE(BaseFile::IsEmptyHash(empty));
- std::string not_empty(crypto::kSHA256Length, '\x01');
- EXPECT_FALSE(BaseFile::IsEmptyHash(not_empty));
- EXPECT_FALSE(BaseFile::IsEmptyHash(std::string()));
+// Open an existing file and continue writing to it. The hash of the partial
+// file is known and matches the existing contents.
+TEST_F(BaseFileTest, ExistingBaseFileKnownHash) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ ASSERT_TRUE(base::WriteFile(file_path, kTestData1, kTestDataLength1));
+
+ std::string hash_so_far(std::begin(kHashOfTestData1),
+ std::end(kHashOfTestData1));
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength1,
+ hash_so_far,
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_data(kTestData1);
+ ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_TRUE(AppendDataToFile(kTestData3));
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
+}
+
+// Open an existing file and continue writing to it. The hash of the partial
+// file is unknown.
+TEST_F(BaseFileTest, ExistingBaseFileUnknownHash) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ ASSERT_TRUE(base::WriteFile(file_path, kTestData1, kTestDataLength1));
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength1,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_data(kTestData1);
+ ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_TRUE(AppendDataToFile(kTestData3));
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
+}
+
+// Open an existing file. The contentsof the file doesn't match the known hash.
+TEST_F(BaseFileTest, ExistingBaseFileIncorrectHash) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ ASSERT_TRUE(base::WriteFile(file_path, kTestData2, kTestDataLength2));
+
+ std::string hash_so_far(std::begin(kHashOfTestData1),
+ std::end(kHashOfTestData1));
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength2,
+ hash_so_far,
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH);
+}
- std::string also_not_empty = empty;
- also_not_empty[crypto::kSHA256Length - 1] = '\x01';
- EXPECT_FALSE(BaseFile::IsEmptyHash(also_not_empty));
+// Open a large existing file with a known hash and continue writing to it.
+TEST_F(BaseFileTest, ExistingBaseFileLargeSizeKnownHash) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ std::string big_buffer(1024 * 200, 'a');
+ ASSERT_TRUE(base::WriteFile(file_path, big_buffer.data(), big_buffer.size()));
+
+ // Hash of partial file (1024*200 * 'a')
+ const uint8_t kExpectedPartialHash[] = {
+ 0x4b, 0x4f, 0x0f, 0x46, 0xac, 0x02, 0xd1, 0x77, 0xde, 0xa0, 0xab,
+ 0x36, 0xa6, 0x6a, 0x65, 0x78, 0x40, 0xe2, 0xfb, 0x98, 0xb2, 0x0b,
+ 0xb2, 0x7a, 0x68, 0x8d, 0xb4, 0xd8, 0xea, 0x9c, 0xd2, 0x2c};
+
+ // Hash of entire file (1024*400 * 'a')
+ const uint8_t kExpectedFullHash[] = {
+ 0x0c, 0xe9, 0xf6, 0x78, 0x6b, 0x0f, 0x58, 0x49, 0x36, 0xe8, 0x83,
+ 0xc5, 0x09, 0x16, 0xbc, 0x5e, 0x2d, 0x07, 0x95, 0xb9, 0x42, 0x20,
+ 0x41, 0x7c, 0xb3, 0x38, 0xd3, 0xf4, 0xe0, 0x78, 0x89, 0x46};
+
+ ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ big_buffer.size(),
+ std::string(std::begin(kExpectedPartialHash),
+ std::end(kExpectedPartialHash)),
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_data(big_buffer); // Contents of the file on Open.
+ ASSERT_TRUE(AppendDataToFile(big_buffer));
+ ExpectHashValue(kExpectedFullHash, base_file_->Finish());
+}
+
+// Open a large existing file. The contents doesn't match the known hash.
+TEST_F(BaseFileTest, ExistingBaseFileLargeSizeIncorrectHash) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ std::string big_buffer(1024 * 200, 'a');
+ ASSERT_TRUE(base::WriteFile(file_path, big_buffer.data(), big_buffer.size()));
+
+ // Incorrect hash of partial file (1024*200 * 'a')
+ const uint8_t kExpectedPartialHash[] = {
+ 0xc2, 0xa9, 0x08, 0xd9, 0x8f, 0x5d, 0xf9, 0x87, 0xad, 0xe4, 0x1b,
+ 0x5f, 0xce, 0x21, 0x30, 0x67, 0xef, 0x6c, 0xc2, 0x1e, 0xf2, 0x24,
+ 0x02, 0x12, 0xa4, 0x1e, 0x54, 0xb5, 0xe7, 0xc2, 0x8a, 0xe5};
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ big_buffer.size(),
+ std::string(std::begin(kExpectedPartialHash),
+ std::end(kExpectedPartialHash)),
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH);
+}
+
+// Open an existing file. The size of the file is too short.
+TEST_F(BaseFileTest, ExistingBaseFileTooShort) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ ASSERT_TRUE(base::WriteFile(file_path, kTestData1, kTestDataLength1));
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength1 + 1,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT);
+}
+
+// Open an existing file. The size is larger than expected.
+TEST_F(BaseFileTest, ExistingBaseFileKnownHashTooLong) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ std::string contents;
+ contents.append(kTestData1);
+ contents.append("Something extra");
+ ASSERT_TRUE(base::WriteFile(file_path, contents.data(), contents.size()));
+
+ std::string hash_so_far(std::begin(kHashOfTestData1),
+ std::end(kHashOfTestData1));
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength1,
+ hash_so_far,
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_data(kTestData1); // Our starting position.
+ ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_TRUE(AppendDataToFile(kTestData3));
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
+}
+
+// Open an existing file. The size is large than expected and the hash is
+// unknown.
+TEST_F(BaseFileTest, ExistingBaseFileUnknownHashTooLong) {
+ base::FilePath file_path = temp_dir_.path().AppendASCII("existing");
+ std::string contents;
+ contents.append(kTestData1);
+ contents.append("Something extra");
+ ASSERT_TRUE(base::WriteFile(file_path, contents.data(), contents.size()));
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base_file_->Initialize(file_path,
+ base::FilePath(),
+ base::File(),
+ kTestDataLength1,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>()));
+ set_expected_data(kTestData1);
+ ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_TRUE(AppendDataToFile(kTestData3));
+ ExpectHashValue(kHashOfTestData1To3, base_file_->Finish());
}
// Test that a temporary file is created in the default download directory.
diff --git a/chromium/content/browser/download/base_file_win.cc b/chromium/content/browser/download/base_file_win.cc
index bfdf3aa9da6..5fa373a43ec 100644
--- a/chromium/content/browser/download/base_file_win.cc
+++ b/chromium/content/browser/download/base_file_win.cc
@@ -352,22 +352,25 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
return interrupt_reason;
}
-DownloadInterruptReason BaseFile::AnnotateWithSourceInformation() {
+DownloadInterruptReason BaseFile::AnnotateWithSourceInformation(
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(!detached_);
bound_net_log_.BeginEvent(net::NetLog::TYPE_DOWNLOAD_FILE_ANNOTATED);
DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE;
- std::string braces_guid = "{" + client_guid_ + "}";
+ std::string braces_guid = "{" + client_guid + "}";
GUID guid = GUID_NULL;
- if (base::IsValidGUID(client_guid_)) {
+ if (base::IsValidGUID(client_guid)) {
HRESULT hr = CLSIDFromString(
base::UTF8ToUTF16(braces_guid).c_str(), &guid);
if (FAILED(hr))
guid = GUID_NULL;
}
- HRESULT hr = AVScanFile(full_path_, source_url_.spec(), guid);
+ HRESULT hr = AVScanFile(full_path_, source_url.spec(), guid);
// If the download file is missing after the call, then treat this as an
// interrupted download.
diff --git a/chromium/content/browser/download/docs/save-page-as.md b/chromium/content/browser/download/docs/save-page-as.md
new file mode 100644
index 00000000000..2661289b375
--- /dev/null
+++ b/chromium/content/browser/download/docs/save-page-as.md
@@ -0,0 +1,137 @@
+# High-level overview of Save-Page-As code
+
+This document describes code under `//content/browser/downloads`
+restricting the scope only to code handling Save-Page-As functionality
+(i.e. leaving out other downloads-related code).
+This document focuses on high-level overview and aspects of the code that
+span multiple compilation units (hoping that individual compilation units
+are described by their code comments or by their code structure).
+
+## Classes overview
+
+* SavePackage class
+ * coordinates overall save-page-as request
+ * created and owned by `WebContents`
+ (ref-counted today, but it is unnecessary - see https://crbug.com/596953)
+ * UI-thread object
+
+* SaveFileCreateInfo::SaveFileSource enum
+ * classifies `SaveItem` and `SaveFile` processing into 3 flavours:
+ * `SAVE_FILE_FROM_NET` (see `SaveFileResourceHandler`)
+ * `SAVE_FILE_FROM_DOM` (see "Complete HTML" section below)
+ * `SAVE_FILE_FROM_FILE` (see `SaveFileManager::SaveLocalFile`)
+
+* SaveItem class
+ * tracks saving a single file
+ * created and owned by `SavePackage`
+ * UI-thread object
+
+* SaveFileManager class
+ * coordinates between FILE and UI threads
+ * Gets requests from `SavePackage` and communicates results back to
+ `SavePackage` on the UI thread.
+ * Shephards data (received from the network OR from DOM) into
+ FILE thread - via `SaveFileManager::UpdateSaveProgress`
+ * created and owned by `ResourceDispatchedHostImpl`
+ (ref-counted today, but it is unnecessary - see https://crbug.com/596953)
+
+* SaveFile class
+ * tracks saving a single file
+ * created and owned by `SaveFileManager`
+ * FILE-thread object
+
+* SaveFileResourceHandler class
+ * tracks network downloads + forwards their status into `SaveFileManager`
+ (onto FILE-thread)
+ * created by `ResourceDispatcherHostImpl::BeginSaveFile`
+ * IO-thread object
+
+* SaveFileCreateInfo POD struct
+ * short-lived object holding data passed to callbacks handling start of
+ saving a file.
+
+* MHTMLGenerationManager class
+ * singleton that manages progress of jobs responsible for saving individual
+ MHTML files (represented by `MHTMLGenerationManager::Job`).
+
+
+## Overview of the processing flow
+
+Save-Page-As flow starts with `WebContents::OnSavePage`.
+The flow is different depending on the save format chosen by the user
+(each flow is described in a separate section below).
+
+### Complete HTML
+
+Very high-level flow of saving a page as "Complete HTML":
+
+* Step 1: `SavePackage` asks all frames for "savable resources"
+ and creates `SaveItem` for each of files that need to be saved
+
+* Step 2: `SavePackage` first processes `SAVE_FILE_FROM_NET` and
+ `SAVE_FILE_FROM_FILE` `SaveItem`s and asks `SaveFileManager` to save
+ them.
+
+* Step 3: `SavePackage` handles remaining `SAVE_FILE_FROM_DOM` `SaveItem`s and
+ asks each frame to serialize its DOM/HTML (each frame gets from
+ `SavePackage` a map covering local paths that need to be referenced by
+ the frame). Responses from frames get forwarded to `SaveFileManager`
+ to be written to disk.
+
+
+### MHTML
+
+Very high-level flow of saving a page as MHTML:
+
+* Step 1: `WebContents::GenerateMHTML` is called by either `SavePackage` (for
+ Save-Page-As UI) or Extensions (via `chrome.pageCapture` extensions
+ API) or by an embedder of `WebContents` (since this is public API of
+ //content).
+
+* Step 2: `MHTMLGenerationManager` coordinates generation of the MHTML file
+ by sequentially (one-at-a-time) asking each frame to write its portion
+ of MHTML to a file handle. Other classes (i.e. `SavePackage` and/or
+ `SaveFileManager`) are not used at this step at all.
+
+* Step 3: When done `MHTMLGenerationManager` calls a completion callback
+ which in case of Save-Page-As will end up in
+ `SavePackage::OnMHTMLGenerated`.
+
+Note: MHTML format is by default disabled in Save-Page-As UI on Windows, MacOS
+and Linux (it is the default on ChromeOS), but for testing this can be easily
+changed using `--save-page-as-mhtml` command line switch.
+
+
+### HTML Only
+
+Very high-level flow of saving a page as "HTML Only":
+
+* `SavePackage` creates only a single `SaveItem` (either `SAVE_FILE_FROM_NET` or
+ `SAVE_FILE_FROM_FILE`) and asks `SaveFileManager` to process it
+ (as in the Complete HTML individual SaveItem handling above.).
+
+
+## Other relevant code
+
+Pointers to related code outside of `//content/browser/download`:
+
+* End-to-end tests:
+ * `//chrome/browser/downloads/save_page_browsertest.cc`
+ * `//chrome/test/data/save_page/...`
+
+* Other tests:
+ * `//content/browser/downloads/*test*.cc`
+ * `//content/renderer/dom_serializer_browsertest.cc` - single process... :-/
+
+* Elsewhere in `//content`:
+ * `//content/renderer/savable_resources...`
+
+* Blink:
+ * `//third_party/WebKit/public/web/WebFrameSerializer...`
+ * `//third_party/WebKit/Source/web/WebFrameSerializerImpl...`
+ (used for Complete HTML today; should use `FrameSerializer` instead in
+ the long-term - see https://crbug.com/328354).
+ * `//third_party/WebKit/Source/core/frame/FrameSerializer...`
+ (used for MHTML today)
+ * `//third_party/WebKit/Source/platform/mhtml/MHTMLArchive...`
+
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index dc965d41646..19a05a2d6a0 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -29,8 +29,12 @@
#include "content/browser/download/download_item_impl.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/download/download_resource_handler.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/download_danger_type.h"
#include "content/public/browser/power_save_blocker.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/resource_throttle.h"
#include "content/public/common/content_features.h"
#include "content/public/common/webplugininfo.h"
#include "content/public/test/browser_test_utils.h"
@@ -118,17 +122,13 @@ static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) {
class DownloadFileWithDelay : public DownloadFileImpl {
public:
- DownloadFileWithDelay(
- scoped_ptr<DownloadSaveInfo> save_info,
- const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
- scoped_ptr<ByteStreamReader> stream,
- const net::BoundNetLog& bound_net_log,
- scoped_ptr<PowerSaveBlocker> power_save_blocker,
- base::WeakPtr<DownloadDestinationObserver> observer,
- base::WeakPtr<DownloadFileWithDelayFactory> owner);
+ DownloadFileWithDelay(scoped_ptr<DownloadSaveInfo> save_info,
+ const base::FilePath& default_download_directory,
+ scoped_ptr<ByteStreamReader> stream,
+ const net::BoundNetLog& bound_net_log,
+ scoped_ptr<PowerSaveBlocker> power_save_blocker,
+ base::WeakPtr<DownloadDestinationObserver> observer,
+ base::WeakPtr<DownloadFileWithDelayFactory> owner);
~DownloadFileWithDelay() override;
@@ -138,6 +138,9 @@ class DownloadFileWithDelay : public DownloadFileImpl {
void RenameAndUniquify(const base::FilePath& full_path,
const RenameCompletionCallback& callback) override;
void RenameAndAnnotate(const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
const RenameCompletionCallback& callback) override;
private:
@@ -167,9 +170,6 @@ class DownloadFileWithDelayFactory : public DownloadFileFactory {
DownloadFile* CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) override;
@@ -191,9 +191,6 @@ class DownloadFileWithDelayFactory : public DownloadFileFactory {
DownloadFileWithDelay::DownloadFileWithDelay(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
scoped_ptr<PowerSaveBlocker> power_save_blocker,
@@ -201,9 +198,6 @@ DownloadFileWithDelay::DownloadFileWithDelay(
base::WeakPtr<DownloadFileWithDelayFactory> owner)
: DownloadFileImpl(std::move(save_info),
default_download_directory,
- url,
- referrer_url,
- calculate_hash,
std::move(stream),
bound_net_log,
observer),
@@ -221,11 +215,19 @@ void DownloadFileWithDelay::RenameAndUniquify(
}
void DownloadFileWithDelay::RenameAndAnnotate(
- const base::FilePath& full_path, const RenameCompletionCallback& callback) {
+ const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
+ const RenameCompletionCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DownloadFileImpl::RenameAndAnnotate(
- full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
- owner_, callback));
+ full_path,
+ client_guid,
+ source_url,
+ referrer_url,
+ base::Bind(
+ DownloadFileWithDelay::RenameCallbackWrapper, owner_, callback));
}
// static
@@ -249,19 +251,19 @@ DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {}
DownloadFile* DownloadFileWithDelayFactory::CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) {
scoped_ptr<PowerSaveBlocker> psb(PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
PowerSaveBlocker::kReasonOther, "Download in progress"));
- return new DownloadFileWithDelay(
- std::move(save_info), default_download_directory, url, referrer_url,
- calculate_hash, std::move(stream), bound_net_log, std::move(psb),
- observer, weak_ptr_factory_.GetWeakPtr());
+ return new DownloadFileWithDelay(std::move(save_info),
+ default_download_directory,
+ std::move(stream),
+ bound_net_log,
+ std::move(psb),
+ observer,
+ weak_ptr_factory_.GetWeakPtr());
}
void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
@@ -291,18 +293,12 @@ class CountingDownloadFile : public DownloadFileImpl {
public:
CountingDownloadFile(scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
scoped_ptr<PowerSaveBlocker> power_save_blocker,
base::WeakPtr<DownloadDestinationObserver> observer)
: DownloadFileImpl(std::move(save_info),
default_downloads_directory,
- url,
- referrer_url,
- calculate_hash,
std::move(stream),
bound_net_log,
observer) {}
@@ -351,19 +347,18 @@ class CountingDownloadFileFactory : public DownloadFileFactory {
DownloadFile* CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) override {
scoped_ptr<PowerSaveBlocker> psb(PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
PowerSaveBlocker::kReasonOther, "Download in progress"));
- return new CountingDownloadFile(
- std::move(save_info), default_downloads_directory, url, referrer_url,
- calculate_hash, std::move(stream), bound_net_log, std::move(psb),
- observer);
+ return new CountingDownloadFile(std::move(save_info),
+ default_downloads_directory,
+ std::move(stream),
+ bound_net_log,
+ std::move(psb),
+ observer);
}
};
@@ -551,6 +546,13 @@ class TestRequestStartHandler {
class DownloadContentTest : public ContentBrowserTest {
protected:
void SetUpOnMainThread() override {
+ // Enable downloads resumption.
+ base::FeatureList::ClearInstanceForTesting();
+ scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(features::kDownloadResumption.name,
+ std::string());
+ base::FeatureList::SetInstance(std::move(feature_list));
+
ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
test_delegate_.reset(new TestShellDownloadManagerDelegate());
@@ -575,6 +577,10 @@ class DownloadContentTest : public ContentBrowserTest {
return test_delegate_.get();
}
+ const base::FilePath& GetDownloadDirectory() const {
+ return downloads_directory_.path();
+ }
+
// Create a DownloadTestObserverTerminal that will wait for the
// specified number of downloads to finish.
DownloadTestObserver* CreateWaiter(
@@ -602,6 +608,12 @@ class DownloadContentTest : public ContentBrowserTest {
.WaitForEvent();
}
+ void WaitForCancel(DownloadItem* download) {
+ DownloadUpdatedObserver(
+ download, base::Bind(&IsDownloadInState, DownloadItem::CANCELLED))
+ .WaitForEvent();
+ }
+
// Note: Cannot be used with other alternative DownloadFileFactorys
void SetupEnsureNoPendingDownloads() {
DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting(
@@ -705,71 +717,6 @@ class DownloadContentTest : public ContentBrowserTest {
scoped_ptr<TestShellDownloadManagerDelegate> test_delegate_;
};
-// Parameters for DownloadResumptionContentTest.
-enum class DownloadResumptionTestType {
- RESUME_WITH_RENDERER, // Resume() is called while the originating WebContents
- // is still alive.
- RESUME_WITHOUT_RENDERER // Resume() is called after the originating
- // WebContents has been deleted.
-};
-
-// Parameterized test for download resumption. Tests using this fixure will be
-// run once with RESUME_WITH_RENDERER and once with RESUME_WITHOUT_RENDERER.
-// Use initiator_shell_for_resumption() to retrieve the Shell object that should
-// be used as the originator for the initial download. Prior to calling
-// Resume(), call PrepareToResume() which will cause the originating Shell to be
-// deleted if the test parameter is RESUME_WITHOUT_RENDERER.
-class DownloadResumptionContentTest
- : public DownloadContentTest,
- public ::testing::WithParamInterface<DownloadResumptionTestType> {
- public:
- void SetUpOnMainThread() override {
- base::FeatureList::ClearInstanceForTesting();
- scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- features::kDownloadResumption.name, std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
-
- DownloadContentTest::SetUpOnMainThread();
-
- if (GetParam() == DownloadResumptionTestType::RESUME_WITHOUT_RENDERER)
- initiator_shell_for_resumption_ = CreateBrowser();
- else
- initiator_shell_for_resumption_ = shell();
-
- ASSERT_EQ(DownloadManagerForShell(shell()),
- DownloadManagerForShell(initiator_shell_for_resumption()));
- }
-
- // Shell to use for initiating a download. Only valid *before*
- // PrepareToResume() is called.
- Shell* initiator_shell_for_resumption() const {
- DCHECK(initiator_shell_for_resumption_);
- return initiator_shell_for_resumption_;
- }
-
- // Should be called once before calling DownloadItem::Resume() on an
- // interrupted download. This may cause initiator_shell_for_resumption() to
- // become invalidated.
- void PrepareToResume() {
- if (GetParam() == DownloadResumptionTestType::RESUME_WITH_RENDERER)
- return;
- DCHECK_NE(initiator_shell_for_resumption(), shell());
- DCHECK(initiator_shell_for_resumption());
- initiator_shell_for_resumption_->Close();
- initiator_shell_for_resumption_ = nullptr;
- }
-
- private:
- Shell* initiator_shell_for_resumption_ = nullptr;
-};
-
-INSTANTIATE_TEST_CASE_P(
- _,
- DownloadResumptionContentTest,
- ::testing::Values(DownloadResumptionTestType::RESUME_WITH_RENDERER,
- DownloadResumptionTestType::RESUME_WITHOUT_RENDERER));
-
} // namespace
IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
@@ -1070,7 +1017,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) {
}
// Test resumption with a response that contains strong validators.
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, StrongValidators) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, StrongValidators) {
TestDownloadRequestHandler request_handler;
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
@@ -1078,14 +1025,13 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, StrongValidators) {
parameters.injected_errors.front();
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
ASSERT_EQ(interruption.offset, download->GetReceivedBytes());
ASSERT_EQ(parameters.size, download->GetTotalBytes());
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
@@ -1123,13 +1069,200 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, StrongValidators) {
value);
}
+// Resumption should only attempt to contact the final URL if the download has a
+// URL chain.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RedirectBeforeResume) {
+ TestDownloadRequestHandler request_handler_1(
+ GURL("http://example.com/first-url"));
+ request_handler_1.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/second-url\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler request_handler_2(
+ GURL("http://example.com/second-url"));
+ request_handler_2.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/third-url\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler request_handler_3(
+ GURL("http://example.com/third-url"));
+ request_handler_3.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/download\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler resumable_request_handler(
+ GURL("http://example.com/download"));
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ resumable_request_handler.StartServing(parameters);
+
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler_1.url());
+ WaitForInterrupt(download);
+
+ EXPECT_EQ(4u, download->GetUrlChain().size());
+ EXPECT_EQ(request_handler_1.url(), download->GetOriginalUrl());
+ EXPECT_EQ(resumable_request_handler.url(), download->GetURL());
+
+ // Now that the download is interrupted, make all intermediate servers return
+ // a 404. The only way a resumption request would succeed if the resumption
+ // request is sent to the final server in the chain.
+ const char k404Response[] = "HTTP/1.1 404 Not found\r\n\r\n";
+ request_handler_1.StartServingStaticResponse(k404Response);
+ request_handler_2.StartServingStaticResponse(k404Response);
+ request_handler_3.StartServingStaticResponse(k404Response);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+}
+
+// If a resumption request results in a redirect, the response should be ignored
+// and the download should be marked as interrupted again.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RedirectWhileResume) {
+ TestDownloadRequestHandler request_handler(
+ GURL("http://example.com/first-url"));
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ ++parameters.pattern_generator_seed;
+ request_handler.StartServing(parameters);
+
+ // We should never send a request to the decoy. If we do, the request will
+ // always succeed, which results in behavior that diverges from what we want,
+ // which is for the download to return to being interrupted.
+ TestDownloadRequestHandler decoy_request_handler(
+ GURL("http://example.com/decoy"));
+ decoy_request_handler.StartServing(TestDownloadRequestHandler::Parameters());
+
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
+ WaitForInterrupt(download);
+
+ // Upon resumption, the server starts responding with a redirect. This
+ // response should not be accepted.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/decoy\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE,
+ download->GetLastReason());
+
+ // Back to the original request handler. Resumption should now succeed, and
+ // use the partial data it had prior to the first interruption.
+ request_handler.StartServing(parameters);
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+ ASSERT_EQ(parameters.size, download->GetTotalBytes());
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+
+ // Characterization risk: The next portion of the test examines the requests
+ // that were sent out while downloading our resource. These requests
+ // correspond to the requests that were generated by the browser and the
+ // downloads system and may change as implementation details change.
+ TestDownloadRequestHandler::CompletedRequests requests;
+ request_handler.GetCompletedRequestInfo(&requests);
+
+ ASSERT_EQ(3u, requests.size());
+
+ // None of the request should have transferred the entire resource. The
+ // redirect response shows up as a response with 0 bytes transferred.
+ EXPECT_GT(parameters.size, requests[0].transferred_byte_count);
+ EXPECT_EQ(0, requests[1].transferred_byte_count);
+ EXPECT_GT(parameters.size, requests[2].transferred_byte_count);
+}
+
+// If the server response for the resumption request specifies a bad range (i.e.
+// not the range that was requested or an invalid or missing Content-Range
+// header), then the download should be marked as interrupted again without
+// discarding the partial state.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, BadRangeHeader) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ request_handler.StartServing(parameters);
+
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
+ WaitForInterrupt(download);
+
+ // Upon resumption, the server starts responding with a bad range header.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 1000000-2000000/3000000\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Or this time, the server sends a response with an invalid Content-Range
+ // header.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: ooga-booga-booga-booga\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Or no Content-Range header at all.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Some-Headers: ooga-booga-booga-booga\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Back to the original request handler. Resumption should now succeed, and
+ // use the partial data it had prior to the first interruption.
+ request_handler.StartServing(parameters);
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+ ASSERT_EQ(parameters.size, download->GetTotalBytes());
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+
+ // Characterization risk: The next portion of the test examines the requests
+ // that were sent out while downloading our resource. These requests
+ // correspond to the requests that were generated by the browser and the
+ // downloads system and may change as implementation details change.
+ TestDownloadRequestHandler::CompletedRequests requests;
+ request_handler.GetCompletedRequestInfo(&requests);
+
+ ASSERT_EQ(5u, requests.size());
+
+ // None of the request should have transferred the entire resource.
+ EXPECT_GT(parameters.size, requests[0].transferred_byte_count);
+ EXPECT_EQ(0, requests[1].transferred_byte_count);
+ EXPECT_EQ(0, requests[2].transferred_byte_count);
+ EXPECT_EQ(0, requests[3].transferred_byte_count);
+ EXPECT_GT(parameters.size, requests[4].transferred_byte_count);
+}
+
// A partial resumption results in an HTTP 200 response. I.e. the server ignored
// the range request and sent the entire resource instead. For If-Range requests
// (as opposed to If-Match), the behavior for a precondition failure is also to
// respond with a 200. So this test case covers both validation failure and
// ignoring the range request.
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
- RestartIfNotPartialResponse) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RestartIfNotPartialResponse) {
const int kOriginalPatternGeneratorSeed = 1;
const int kNewPatternGeneratorSeed = 2;
@@ -1142,8 +1275,8 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
ASSERT_EQ(interruption.offset, download->GetReceivedBytes());
@@ -1154,7 +1287,6 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
parameters.pattern_generator_seed = kNewPatternGeneratorSeed;
request_handler.StartServing(parameters);
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
@@ -1192,7 +1324,7 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
}
// Confirm we restart if we don't have a verifier.
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoETag) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RestartIfNoETag) {
const int kOriginalPatternGeneratorSeed = 1;
const int kNewPatternGeneratorSeed = 2;
@@ -1204,15 +1336,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoETag) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
parameters.pattern_generator_seed = kNewPatternGeneratorSeed;
parameters.ClearInjectedErrors();
request_handler.StartServing(parameters);
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
@@ -1236,14 +1367,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoETag) {
// Partial file goes missing before the download is resumed. The download should
// restart.
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoPartialFile) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RestartIfNoPartialFile) {
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
// Delete the intermediate file.
@@ -1253,7 +1384,6 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoPartialFile) {
parameters.ClearInjectedErrors();
request_handler.StartServing(parameters);
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
@@ -1264,32 +1394,29 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RestartIfNoPartialFile) {
download->GetTargetFilePath()));
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
- RecoverFromInitFileError) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RecoverFromInitFileError) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(TestDownloadRequestHandler::Parameters());
// Setup the error injector.
- scoped_refptr<TestFileErrorInjector> injector(TestFileErrorInjector::Create(
- DownloadManagerForShell(initiator_shell_for_resumption())));
+ scoped_refptr<TestFileErrorInjector> injector(
+ TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
const TestFileErrorInjector::FileErrorInfo err = {
- request_handler.url().spec(),
TestFileErrorInjector::FILE_OPERATION_INITIALIZE, 0,
DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
- injector->AddError(err);
- injector->InjectErrors();
+ injector->InjectError(err);
// Start and watch for interrupt.
- DownloadItem* download(StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url()));
+ DownloadItem* download(
+ StartDownloadAndReturnItem(shell(), request_handler.url()));
WaitForInterrupt(download);
ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
download->GetLastReason());
EXPECT_EQ(0, download->GetReceivedBytes());
EXPECT_TRUE(download->GetFullPath().empty());
- EXPECT_TRUE(download->GetTargetFilePath().empty());
+ EXPECT_FALSE(download->GetTargetFilePath().empty());
// We need to make sure that any cross-thread downloads communication has
// quiesced before clearing and injecting the new errors, as the
@@ -1299,35 +1426,31 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
RunAllPendingInMessageLoop();
// Clear the old errors list.
- injector->ClearErrors();
- injector->InjectErrors();
+ injector->ClearError();
// Resume and watch completion.
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
RecoverFromIntermediateFileRenameError) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(TestDownloadRequestHandler::Parameters());
// Setup the error injector.
- scoped_refptr<TestFileErrorInjector> injector(TestFileErrorInjector::Create(
- DownloadManagerForShell(initiator_shell_for_resumption())));
+ scoped_refptr<TestFileErrorInjector> injector(
+ TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
const TestFileErrorInjector::FileErrorInfo err = {
- request_handler.url().spec(),
TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY, 0,
DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
- injector->AddError(err);
- injector->InjectErrors();
+ injector->InjectError(err);
// Start and watch for interrupt.
- DownloadItem* download(StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url()));
+ DownloadItem* download(
+ StartDownloadAndReturnItem(shell(), request_handler.url()));
WaitForInterrupt(download);
ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
@@ -1346,40 +1469,33 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
RunAllPendingInMessageLoop();
// Clear the old errors list.
- injector->ClearErrors();
- injector->InjectErrors();
+ injector->ClearError();
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
- RecoverFromFinalRenameError) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RecoverFromFinalRenameError) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(TestDownloadRequestHandler::Parameters());
// Setup the error injector.
- scoped_refptr<TestFileErrorInjector> injector(TestFileErrorInjector::Create(
- DownloadManagerForShell(initiator_shell_for_resumption())));
+ scoped_refptr<TestFileErrorInjector> injector(
+ TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
- DownloadManagerForShell(initiator_shell_for_resumption())
- ->RemoveAllDownloads();
+ DownloadManagerForShell(shell())->RemoveAllDownloads();
TestFileErrorInjector::FileErrorInfo err = {
- request_handler.url().spec(),
TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE, 0,
- DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
- injector->AddError(err);
- injector->InjectErrors();
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED};
+ injector->InjectError(err);
// Start and watch for interrupt.
- DownloadItem* download(StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url()));
+ DownloadItem* download(
+ StartDownloadAndReturnItem(shell(), request_handler.url()));
WaitForInterrupt(download);
ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
- download->GetLastReason());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, download->GetLastReason());
EXPECT_TRUE(download->GetFullPath().empty());
// Target path should still be intact.
EXPECT_FALSE(download->GetTargetFilePath().empty());
@@ -1392,16 +1508,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
RunAllPendingInMessageLoop();
// Clear the old errors list.
- injector->ClearErrors();
- injector->InjectErrors();
+ injector->ClearError();
- PrepareToResume();
download->Resume();
WaitForCompletion(download);
EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, Resume_Hash) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, Resume_Hash) {
using InjectedError = TestDownloadRequestHandler::InjectedError;
const char kExpectedHash[] =
"\xa7\x44\x49\x86\x24\xc6\x84\x6c\x89\xdf\xd8\xec\xa0\xe0\x61\x12\xdc\x80"
@@ -1412,8 +1526,8 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, Resume_Hash) {
// As a control, let's try GetHash() on an uninterrupted download.
request_handler.StartServing(parameters);
- DownloadItem* uninterrupted_download(StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url()));
+ DownloadItem* uninterrupted_download(
+ StartDownloadAndReturnItem(shell(), request_handler.url()));
WaitForCompletion(uninterrupted_download);
EXPECT_EQ(expected_hash, uninterrupted_download->GetHash());
@@ -1431,11 +1545,10 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, Resume_Hash) {
request_handler.StartServing(parameters);
// Start and watch for interrupt.
- DownloadItem* download(StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url()));
+ DownloadItem* download(
+ StartDownloadAndReturnItem(shell(), request_handler.url()));
WaitForInterrupt(download);
- PrepareToResume();
download->Resume();
WaitForInterrupt(download);
@@ -1456,14 +1569,13 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, Resume_Hash) {
// An interrupted download should remove the intermediate file when it is
// cancelled.
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
- CancelInterruptedDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(
TestDownloadRequestHandler::Parameters::WithSingleInterruption());
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path = download->GetFullPath();
@@ -1479,14 +1591,13 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
EXPECT_TRUE(download->GetFullPath().empty());
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest,
- RemoveInterruptedDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveInterruptedDownload) {
TestDownloadRequestHandler request_handler;
request_handler.StartServing(
TestDownloadRequestHandler::Parameters::WithSingleInterruption());
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path = download->GetFullPath();
@@ -1523,14 +1634,14 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveCompletedDownload) {
EXPECT_TRUE(base::PathExists(target_path));
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumingDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path(download->GetFullPath());
@@ -1539,15 +1650,13 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumingDownload) {
// Resume and remove download. We expect only a single OnDownloadCreated()
// call, and that's for the second download created below.
- MockDownloadManagerObserver dm_observer(
- DownloadManagerForShell(initiator_shell_for_resumption()));
+ MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
TestRequestStartHandler request_start_handler;
parameters.on_start_handler = request_start_handler.GetOnStartHandler();
request_handler.StartServing(parameters);
- PrepareToResume();
download->Resume();
request_start_handler.WaitForCallback();
@@ -1575,14 +1684,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumingDownload) {
EXPECT_TRUE(EnsureNoPendingDownloads());
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumingDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path(download->GetFullPath());
@@ -1591,15 +1700,13 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumingDownload) {
// Resume and cancel download. We expect only a single OnDownloadCreated()
// call, and that's for the second download created below.
- MockDownloadManagerObserver dm_observer(
- DownloadManagerForShell(initiator_shell_for_resumption()));
+ MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
TestRequestStartHandler request_start_handler;
parameters.on_start_handler = request_start_handler.GetOnStartHandler();
request_handler.StartServing(parameters);
- PrepareToResume();
download->Resume();
request_start_handler.WaitForCallback();
@@ -1628,14 +1735,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumingDownload) {
EXPECT_TRUE(EnsureNoPendingDownloads());
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumedDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumedDownload) {
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path(download->GetFullPath());
@@ -1645,11 +1752,9 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumedDownload) {
EXPECT_FALSE(base::PathExists(target_path));
// Resume and remove download. We don't expect OnDownloadCreated() calls.
- MockDownloadManagerObserver dm_observer(
- DownloadManagerForShell(initiator_shell_for_resumption()));
+ MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
EXPECT_CALL(dm_observer, OnDownloadCreated(_, _)).Times(0);
- PrepareToResume();
download->Resume();
WaitForInProgress(download);
@@ -1663,14 +1768,14 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RemoveResumedDownload) {
EXPECT_TRUE(EnsureNoPendingDownloads());
}
-IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumedDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumedDownload) {
TestDownloadRequestHandler::Parameters parameters =
TestDownloadRequestHandler::Parameters::WithSingleInterruption();
TestDownloadRequestHandler request_handler;
request_handler.StartServing(parameters);
- DownloadItem* download = StartDownloadAndReturnItem(
- initiator_shell_for_resumption(), request_handler.url());
+ DownloadItem* download =
+ StartDownloadAndReturnItem(shell(), request_handler.url());
WaitForInterrupt(download);
base::FilePath intermediate_path(download->GetFullPath());
@@ -1680,11 +1785,9 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumedDownload) {
EXPECT_FALSE(base::PathExists(target_path));
// Resume and remove download. We don't expect OnDownloadCreated() calls.
- MockDownloadManagerObserver dm_observer(
- DownloadManagerForShell(initiator_shell_for_resumption()));
+ MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
EXPECT_CALL(dm_observer, OnDownloadCreated(_, _)).Times(0);
- PrepareToResume();
download->Resume();
WaitForInProgress(download);
@@ -1698,6 +1801,415 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, CancelResumedDownload) {
EXPECT_TRUE(EnsureNoPendingDownloads());
}
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_NoFile) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ parameters.etag,
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There will be two requests. The first one is issued optimistically assuming
+ // that the intermediate file exists and matches the size expectations set
+ // forth in the download metadata (i.e. assuming that a 1331 byte file exists
+ // at |intermediate_file_path|.
+ //
+ // However, once the response is received, DownloadFile will report that the
+ // intermediate file doesn't exist and hence the download is marked
+ // interrupted again.
+ //
+ // The second request reads the entire entity.
+ //
+ // N.b. we can't make any assumptions about how many bytes are transferred by
+ // the first request since response data will be bufferred until DownloadFile
+ // is done initializing.
+ //
+ // TODO(asanka): Ideally we'll check that the intermediate file matches
+ // expectations prior to issuing the first resumption request.
+ ASSERT_EQ(2u, completed_requests.size());
+ EXPECT_EQ(parameters.size, completed_requests[1].transferred_byte_count);
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_NoHash) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ std::vector<char> buffer(kIntermediateSize);
+ request_handler.GetPatternBytes(
+ parameters.pattern_generator_seed, 0, buffer.size(), buffer.data());
+ ASSERT_EQ(
+ kIntermediateSize,
+ base::WriteFile(intermediate_file_path, buffer.data(), buffer.size()));
+
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ parameters.etag,
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There's only one network request issued, and that is for the remainder of
+ // the file.
+ ASSERT_EQ(1u, completed_requests.size());
+ EXPECT_EQ(parameters.size - kIntermediateSize,
+ completed_requests[0].transferred_byte_count);
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+ ResumeRestoredDownload_EtagMismatch) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ std::vector<char> buffer(kIntermediateSize);
+ request_handler.GetPatternBytes(
+ parameters.pattern_generator_seed + 1, 0, buffer.size(), buffer.data());
+ ASSERT_EQ(
+ kIntermediateSize,
+ base::WriteFile(intermediate_file_path, buffer.data(), buffer.size()));
+
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ "fake-etag",
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There's only one network request issued. The If-Range header allows the
+ // server to respond with the entire entity in one go. The existing contents
+ // of the file should be discarded, and overwritten by the new contents.
+ ASSERT_EQ(1u, completed_requests.size());
+ EXPECT_EQ(parameters.size, completed_requests[0].transferred_byte_count);
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+ ResumeRestoredDownload_CorrectHash) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ std::vector<char> buffer(kIntermediateSize);
+ request_handler.GetPatternBytes(
+ parameters.pattern_generator_seed, 0, buffer.size(), buffer.data());
+ ASSERT_EQ(
+ kIntermediateSize,
+ base::WriteFile(intermediate_file_path, buffer.data(), buffer.size()));
+ // SHA-256 hash of the pattern bytes in buffer.
+ static const uint8_t kPartialHash[] = {
+ 0x77, 0x14, 0xfd, 0x83, 0x06, 0x15, 0x10, 0x7a, 0x47, 0x15, 0xd3,
+ 0xcf, 0xdd, 0x46, 0xa2, 0x61, 0x96, 0xff, 0xc3, 0xbb, 0x49, 0x30,
+ 0xaf, 0x31, 0x3a, 0x64, 0x0b, 0xd5, 0xfa, 0xb1, 0xe3, 0x81};
+
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ parameters.etag,
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(std::begin(kPartialHash), std::end(kPartialHash)),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There's only one network request issued, and that is for the remainder of
+ // the file.
+ ASSERT_EQ(1u, completed_requests.size());
+ EXPECT_EQ(parameters.size - kIntermediateSize,
+ completed_requests[0].transferred_byte_count);
+
+ // SHA-256 hash of the entire 102400 bytes in the target file.
+ static const uint8_t kFullHash[] = {
+ 0xa7, 0x44, 0x49, 0x86, 0x24, 0xc6, 0x84, 0x6c, 0x89, 0xdf, 0xd8,
+ 0xec, 0xa0, 0xe0, 0x61, 0x12, 0xdc, 0x80, 0x13, 0xf2, 0x83, 0x49,
+ 0xa9, 0x14, 0x52, 0x32, 0xf0, 0x95, 0x20, 0xca, 0x5b, 0x30};
+ EXPECT_EQ(std::string(std::begin(kFullHash), std::end(kFullHash)),
+ download->GetHash());
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_WrongHash) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ std::vector<char> buffer(kIntermediateSize);
+ ASSERT_EQ(
+ kIntermediateSize,
+ base::WriteFile(intermediate_file_path, buffer.data(), buffer.size()));
+ // SHA-256 hash of the expected pattern bytes in buffer. This doesn't match
+ // the current contents of the intermediate file which should all be 0.
+ static const uint8_t kPartialHash[] = {
+ 0x77, 0x14, 0xfd, 0x83, 0x06, 0x15, 0x10, 0x7a, 0x47, 0x15, 0xd3,
+ 0xcf, 0xdd, 0x46, 0xa2, 0x61, 0x96, 0xff, 0xc3, 0xbb, 0x49, 0x30,
+ 0xaf, 0x31, 0x3a, 0x64, 0x0b, 0xd5, 0xfa, 0xb1, 0xe3, 0x81};
+
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ parameters.etag,
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(std::begin(kPartialHash), std::end(kPartialHash)),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There will be two requests. The first one is issued optimistically assuming
+ // that the intermediate file exists and matches the size expectations set
+ // forth in the download metadata (i.e. assuming that a 1331 byte file exists
+ // at |intermediate_file_path|.
+ //
+ // However, once the response is received, DownloadFile will report that the
+ // intermediate file doesn't match the expected hash.
+ //
+ // The second request reads the entire entity.
+ //
+ // N.b. we can't make any assumptions about how many bytes are transferred by
+ // the first request since response data will be bufferred until DownloadFile
+ // is done initializing.
+ //
+ // TODO(asanka): Ideally we'll check that the intermediate file matches
+ // expectations prior to issuing the first resumption request.
+ ASSERT_EQ(2u, completed_requests.size());
+ EXPECT_EQ(parameters.size, completed_requests[1].transferred_byte_count);
+
+ // SHA-256 hash of the entire 102400 bytes in the target file.
+ static const uint8_t kFullHash[] = {
+ 0xa7, 0x44, 0x49, 0x86, 0x24, 0xc6, 0x84, 0x6c, 0x89, 0xdf, 0xd8,
+ 0xec, 0xa0, 0xe0, 0x61, 0x12, 0xdc, 0x80, 0x13, 0xf2, 0x83, 0x49,
+ 0xa9, 0x14, 0x52, 0x32, 0xf0, 0x95, 0x20, 0xca, 0x5b, 0x30};
+ EXPECT_EQ(std::string(std::begin(kFullHash), std::end(kFullHash)),
+ download->GetHash());
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_ShortFile) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+ request_handler.StartServing(parameters);
+
+ base::FilePath intermediate_file_path =
+ GetDownloadDirectory().AppendASCII("intermediate");
+ std::vector<GURL> url_chain;
+
+ const int kIntermediateSize = 1331;
+ // Size of file is slightly shorter than the size known to DownloadItem.
+ std::vector<char> buffer(kIntermediateSize - 100);
+ request_handler.GetPatternBytes(
+ parameters.pattern_generator_seed, 0, buffer.size(), buffer.data());
+ ASSERT_EQ(
+ kIntermediateSize - 100,
+ base::WriteFile(intermediate_file_path, buffer.data(), buffer.size()));
+ url_chain.push_back(request_handler.url());
+
+ DownloadItem* download = DownloadManagerForShell(shell())->CreateDownloadItem(
+ "F7FB1F59-7DE1-4845-AFDB-8A688F70F583",
+ 1,
+ intermediate_file_path,
+ base::FilePath(),
+ url_chain,
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time(),
+ parameters.etag,
+ std::string(),
+ kIntermediateSize,
+ parameters.size,
+ std::string(),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ false);
+
+ download->Resume();
+ WaitForCompletion(download);
+
+ EXPECT_FALSE(base::PathExists(intermediate_file_path));
+ ReadAndVerifyFileContents(parameters.pattern_generator_seed,
+ parameters.size,
+ download->GetTargetFilePath());
+
+ TestDownloadRequestHandler::CompletedRequests completed_requests;
+ request_handler.GetCompletedRequestInfo(&completed_requests);
+
+ // There will be two requests. The first one is issued optimistically assuming
+ // that the intermediate file exists and matches the size expectations set
+ // forth in the download metadata (i.e. assuming that a 1331 byte file exists
+ // at |intermediate_file_path|.
+ //
+ // However, once the response is received, DownloadFile will report that the
+ // intermediate file is too short and hence the download is marked interrupted
+ // again.
+ //
+ // The second request reads the entire entity.
+ //
+ // N.b. we can't make any assumptions about how many bytes are transferred by
+ // the first request since response data will be bufferred until DownloadFile
+ // is done initializing.
+ //
+ // TODO(asanka): Ideally we'll check that the intermediate file matches
+ // expectations prior to issuing the first resumption request.
+ ASSERT_EQ(2u, completed_requests.size());
+ EXPECT_EQ(parameters.size, completed_requests[1].transferred_byte_count);
+}
+
// Check that the cookie policy is correctly updated when downloading a file
// that redirects cross origin.
IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
@@ -1834,6 +2346,81 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
}
+// A request for a non-existent resource should still result in a DownloadItem
+// that's created in an interrupted state.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeServerError) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL download_url =
+ embedded_test_server()->GetURL("/download/does-not-exist");
+ GURL document_url = embedded_test_server()->GetURL(
+ std::string("/download/download-attribute.html?target=") +
+ download_url.spec());
+
+ DownloadItem* download = StartDownloadAndReturnItem(shell(), document_url);
+ WaitForInterrupt(download);
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+}
+
+namespace {
+
+void ErrorReturningRequestHandler(
+ const net::HttpRequestHeaders& headers,
+ const TestDownloadRequestHandler::OnStartResponseCallback& callback) {
+ callback.Run(std::string(), net::ERR_INTERNET_DISCONNECTED);
+}
+
+} // namespace
+
+// A request that fails before it gets a response from the server should also
+// result in a DownloadItem that's created in an interrupted state.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeNetworkError) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters;
+
+ parameters.on_start_handler = base::Bind(&ErrorReturningRequestHandler);
+ request_handler.StartServing(parameters);
+
+ GURL document_url = embedded_test_server()->GetURL(
+ std::string("/download/download-attribute.html?target=") +
+ request_handler.url().spec());
+ DownloadItem* download = StartDownloadAndReturnItem(shell(), document_url);
+ WaitForInterrupt(download);
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED,
+ download->GetLastReason());
+}
+
+// A request that fails due to it being rejected by policy should result in a
+// DownloadItem that's marked as interrupted.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeInvalidURL) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL document_url = embedded_test_server()->GetURL(
+ "/download/download-attribute.html?target=about:version");
+ DownloadItem* download = StartDownloadAndReturnItem(shell(), document_url);
+ WaitForInterrupt(download);
+
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
+ download->GetLastReason());
+ EXPECT_FALSE(download->CanResume());
+}
+
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeBlobURL) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL document_url =
+ embedded_test_server()->GetURL("/download/download-attribute-blob.html");
+ DownloadItem* download = StartDownloadAndReturnItem(shell(), document_url);
+ WaitForCompletion(download);
+
+ EXPECT_STREQ(FILE_PATH_LITERAL("suggested-filename.txt"),
+ download->GetTargetFilePath().BaseName().value().c_str());
+}
+
// The file empty.bin is served with a MIME type of application/octet-stream.
// The content body is empty. Make sure this case is handled properly and we
// don't regress on http://crbug.com/320394.
@@ -1854,9 +2441,11 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, SniffedMimeType) {
EXPECT_TRUE(item->GetOriginalMimeType().empty());
}
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, Spam) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, DuplicateContentDisposition) {
ASSERT_TRUE(embedded_test_server()->Start());
+ // double-content-disposition.txt is served with two Content-Disposition
+ // headers, both of which are identical.
NavigateToURLAndWaitForDownload(
shell(),
embedded_test_server()->GetURL(
diff --git a/chromium/content/browser/download/download_create_info.cc b/chromium/content/browser/download/download_create_info.cc
index c09d713aa97..92b15849b37 100644
--- a/chromium/content/browser/download/download_create_info.cc
+++ b/chromium/content/browser/download/download_create_info.cc
@@ -5,7 +5,6 @@
#include "content/browser/download/download_create_info.h"
#include <string>
-#include <utility>
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
@@ -13,36 +12,24 @@
namespace content {
DownloadCreateInfo::DownloadCreateInfo(const base::Time& start_time,
- int64_t total_bytes,
const net::BoundNetLog& bound_net_log,
scoped_ptr<DownloadSaveInfo> save_info)
- : start_time(start_time),
- total_bytes(total_bytes),
- download_id(DownloadItem::kInvalidId),
+ : download_id(DownloadItem::kInvalidId),
+ start_time(start_time),
+ total_bytes(0),
has_user_gesture(false),
transition_type(ui::PAGE_TRANSITION_LINK),
+ result(DOWNLOAD_INTERRUPT_REASON_NONE),
save_info(std::move(save_info)),
request_bound_net_log(bound_net_log) {}
DownloadCreateInfo::DownloadCreateInfo()
: DownloadCreateInfo(base::Time(),
- 0,
net::BoundNetLog(),
make_scoped_ptr(new DownloadSaveInfo)) {}
DownloadCreateInfo::~DownloadCreateInfo() {}
-std::string DownloadCreateInfo::DebugString() const {
- return base::StringPrintf(
- "{"
- " download_id = %u"
- " url = \"%s\""
- " request_handle = %s"
- " total_bytes = %" PRId64 " }",
- download_id, url().spec().c_str(), request_handle->DebugString().c_str(),
- total_bytes);
-}
-
const GURL& DownloadCreateInfo::url() const {
return url_chain.empty() ? GURL::EmptyGURL() : url_chain.back();
}
diff --git a/chromium/content/browser/download/download_create_info.h b/chromium/content/browser/download/download_create_info.h
index 1767e45eebc..01e1ad5f014 100644
--- a/chromium/content/browser/download/download_create_info.h
+++ b/chromium/content/browser/download/download_create_info.h
@@ -16,6 +16,7 @@
#include "content/browser/download/download_file.h"
#include "content/browser/download/download_request_handle.h"
#include "content/common/content_export.h"
+#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_save_info.h"
#include "net/log/net_log.h"
#include "ui/base/page_transition_types.h"
@@ -27,18 +28,18 @@ namespace content {
// want to pass |DownloadItem|s between threads.
struct CONTENT_EXPORT DownloadCreateInfo {
DownloadCreateInfo(const base::Time& start_time,
- int64_t total_bytes,
const net::BoundNetLog& bound_net_log,
scoped_ptr<DownloadSaveInfo> save_info);
DownloadCreateInfo();
~DownloadCreateInfo();
- std::string DebugString() const;
-
// The URL from which we are downloading. This is the final URL after any
// redirection by the server for |url_chain|.
const GURL& url() const;
+ // The ID of the download.
+ uint32_t download_id;
+
// The chain of redirects that leading up to and including the final URL.
std::vector<GURL> url_chain;
@@ -57,14 +58,35 @@ struct CONTENT_EXPORT DownloadCreateInfo {
// The total download size.
int64_t total_bytes;
- // The ID of the download.
- uint32_t download_id;
-
// True if the download was initiated by user action.
bool has_user_gesture;
ui::PageTransition transition_type;
+ // The remote IP address where the download was fetched from. Copied from
+ // UrlRequest::GetSocketAddress().
+ std::string remote_address;
+
+ // If the download is initially created in an interrupted state (because the
+ // response was in error), then |result| would be something other than
+ // INTERRUPT_REASON_NONE.
+ DownloadInterruptReason result;
+
+ // The download file save info.
+ scoped_ptr<DownloadSaveInfo> save_info;
+
+ // The handle to the URLRequest sourcing this download.
+ scoped_ptr<DownloadRequestHandleInterface> request_handle;
+
+ // The request's |BoundNetLog|, for "source_dependency" linking with the
+ // download item's.
+ const net::BoundNetLog request_bound_net_log;
+
+ // ---------------------------------------------------------------------------
+ // The remaining fields are Entity-body properties. These are only set if
+ // |result| is DOWNLOAD_INTERRUPT_REASON_NONE.
+ // ---------------------------------------------------------------------------
+
// The content-disposition string from the response header.
std::string content_disposition;
@@ -81,23 +103,9 @@ struct CONTENT_EXPORT DownloadCreateInfo {
// "If-Unmodified-Since" comparison.
std::string last_modified;
- // For continuing a download, the ETAG of the file.
+ // For continuing a download, the ETag of the file.
std::string etag;
- // The download file save info.
- scoped_ptr<DownloadSaveInfo> save_info;
-
- // The remote IP address where the download was fetched from. Copied from
- // UrlRequest::GetSocketAddress().
- std::string remote_address;
-
- // The handle to the URLRequest sourcing this download.
- scoped_ptr<DownloadRequestHandleInterface> request_handle;
-
- // The request's |BoundNetLog|, for "source_dependency" linking with the
- // download item's.
- const net::BoundNetLog request_bound_net_log;
-
private:
DISALLOW_COPY_AND_ASSIGN(DownloadCreateInfo);
};
diff --git a/chromium/content/browser/download/download_destination_observer.h b/chromium/content/browser/download/download_destination_observer.h
new file mode 100644
index 00000000000..6f76391ecf9
--- /dev/null
+++ b/chromium/content/browser/download/download_destination_observer.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_DESTINATION_OBSERVER_H_
+#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_DESTINATION_OBSERVER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/download_interrupt_reasons.h"
+#include "crypto/secure_hash.h"
+
+namespace content {
+
+// Class that receives asynchronous events from a DownloadDestination about
+// downloading progress and completion. These should report status when the
+// data arrives at its final location; i.e. DestinationUpdate should be
+// called after the destination is finished with whatever operation it
+// is doing on the data described by |bytes_so_far| and DestinationCompleted
+// should only be called once that is true for all data.
+//
+// All methods are invoked on the UI thread.
+//
+// Note that this interface does not deal with cross-thread lifetime issues.
+class DownloadDestinationObserver {
+ public:
+ virtual void DestinationUpdate(int64_t bytes_so_far,
+ int64_t bytes_per_sec) = 0;
+
+ virtual void DestinationError(DownloadInterruptReason reason,
+ int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state) = 0;
+
+ virtual void DestinationCompleted(
+ int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> hash_state) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_DESTINATION_OBSERVER_H_
diff --git a/chromium/content/browser/download/download_file.h b/chromium/content/browser/download/download_file.h
index 2514df15519..c30cab9fe30 100644
--- a/chromium/content/browser/download/download_file.h
+++ b/chromium/content/browser/download/download_file.h
@@ -14,6 +14,8 @@
#include "content/common/content_export.h"
#include "content/public/browser/download_interrupt_reasons.h"
+class GURL;
+
namespace content {
class DownloadManager;
@@ -55,6 +57,9 @@ class CONTENT_EXPORT DownloadFile {
// "Mark of the Web" information about its source. No uniquification
// will be performed.
virtual void RenameAndAnnotate(const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
const RenameCompletionCallback& callback) = 0;
// Detach the file so it is not deleted on destruction.
@@ -63,30 +68,8 @@ class CONTENT_EXPORT DownloadFile {
// Abort the download and automatically close the file.
virtual void Cancel() = 0;
- virtual base::FilePath FullPath() const = 0;
+ virtual const base::FilePath& FullPath() const = 0;
virtual bool InProgress() const = 0;
- virtual int64_t CurrentSpeed() const = 0;
-
- // Set |hash| with sha256 digest for the file.
- // Returns true if digest is successfully calculated.
- virtual bool GetHash(std::string* hash) = 0;
-
- // Returns the current (intermediate) state of the hash as a byte string.
- virtual std::string GetHashState() = 0;
-
- // Set the application GUID to be used to identify the app to the
- // system AV function when scanning downloaded files. Should be called
- // before RenameAndAnnotate() to take effect.
- virtual void SetClientGuid(const std::string& guid) = 0;
-
- // For testing. Must be called on FILE thread.
- // TODO(rdsmith): Replace use of EnsureNoPendingDownloads()
- // on the DownloadManager with a test-specific DownloadFileFactory
- // which keeps track of the number of DownloadFiles.
- static int GetNumberOfDownloadFiles();
-
- protected:
- static int number_active_objects_;
};
} // namespace content
diff --git a/chromium/content/browser/download/download_file_factory.cc b/chromium/content/browser/download/download_file_factory.cc
index bae88bef34e..55e03469c89 100644
--- a/chromium/content/browser/download/download_file_factory.cc
+++ b/chromium/content/browser/download/download_file_factory.cc
@@ -15,15 +15,14 @@ DownloadFileFactory::~DownloadFileFactory() {}
DownloadFile* DownloadFileFactory::CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
- scoped_ptr<ByteStreamReader> stream,
+ scoped_ptr<ByteStreamReader> byte_stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer) {
- return new DownloadFileImpl(std::move(save_info), default_downloads_directory,
- url, referrer_url, calculate_hash,
- std::move(stream), bound_net_log, observer);
+ return new DownloadFileImpl(std::move(save_info),
+ default_downloads_directory,
+ std::move(byte_stream),
+ bound_net_log,
+ observer);
}
} // namespace content
diff --git a/chromium/content/browser/download/download_file_factory.h b/chromium/content/browser/download/download_file_factory.h
index 2600e3f8455..d29384dde08 100644
--- a/chromium/content/browser/download/download_file_factory.h
+++ b/chromium/content/browser/download/download_file_factory.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_FACTORY_H_
#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_FILE_FACTORY_H_
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -12,6 +13,10 @@
#include "content/common/content_export.h"
#include "url/gurl.h"
+namespace crypto {
+class SecureHash;
+}
+
namespace net {
class BoundNetLog;
}
@@ -31,10 +36,7 @@ class CONTENT_EXPORT DownloadFileFactory {
virtual DownloadFile* CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
- scoped_ptr<ByteStreamReader> stream,
+ scoped_ptr<ByteStreamReader> byte_stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer);
};
diff --git a/chromium/content/browser/download/download_file_impl.cc b/chromium/content/browser/download/download_file_impl.cc
index e8e31cee7be..6378b9c8d3b 100644
--- a/chromium/content/browser/download/download_file_impl.cc
+++ b/chromium/content/browser/download/download_file_impl.cc
@@ -14,11 +14,13 @@
#include "base/values.h"
#include "content/browser/byte_stream.h"
#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_destination_observer.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
#include "content/browser/download/download_net_log_parameters.h"
#include "content/browser/download/download_stats.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/download_destination_observer.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
#include "net/base/io_buffer.h"
namespace content {
@@ -29,28 +31,19 @@ const int kMaxTimeBlockingFileThreadMs = 1000;
// These constants control the default retry behavior for failing renames. Each
// retry is performed after a delay that is twice the previous delay. The
// initial delay is specified by kInitialRenameRetryDelayMs.
-const int kMaxRenameRetries = 3;
const int kInitialRenameRetryDelayMs = 200;
-int DownloadFile::number_active_objects_ = 0;
+// Number of times a failing rename is retried before giving up.
+const int kMaxRenameRetries = 3;
DownloadFileImpl::DownloadFileImpl(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer)
- : file_(save_info->file_path,
- url,
- referrer_url,
- save_info->offset,
- calculate_hash,
- save_info->hash_state,
- std::move(save_info->file),
- bound_net_log),
+ : file_(bound_net_log),
+ save_info_(std::move(save_info)),
default_download_directory_(default_download_directory),
stream_reader_(std::move(stream)),
bytes_seen_(0),
@@ -60,7 +53,6 @@ DownloadFileImpl::DownloadFileImpl(
DownloadFileImpl::~DownloadFileImpl() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- --number_active_objects_;
}
void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
@@ -68,7 +60,12 @@ void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
update_timer_.reset(new base::RepeatingTimer());
DownloadInterruptReason result =
- file_.Initialize(default_download_directory_);
+ file_.Initialize(save_info_->file_path,
+ default_download_directory_,
+ std::move(save_info_->file),
+ save_info_->offset,
+ save_info_->hash_of_partial_file,
+ std::move(save_info_->hash_state));
if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
@@ -89,8 +86,6 @@ void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(
callback, DOWNLOAD_INTERRUPT_REASON_NONE));
-
- ++number_active_objects_;
}
DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
@@ -109,18 +104,23 @@ DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
void DownloadFileImpl::RenameAndUniquify(
const base::FilePath& full_path,
const RenameCompletionCallback& callback) {
- RenameWithRetryInternal(
- full_path, UNIQUIFY, kMaxRenameRetries, base::TimeTicks(), callback);
+ scoped_ptr<RenameParameters> parameters(
+ new RenameParameters(UNIQUIFY, full_path, callback));
+ RenameWithRetryInternal(std::move(parameters));
}
void DownloadFileImpl::RenameAndAnnotate(
const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
const RenameCompletionCallback& callback) {
- RenameWithRetryInternal(full_path,
- ANNOTATE_WITH_SOURCE_INFORMATION,
- kMaxRenameRetries,
- base::TimeTicks(),
- callback);
+ scoped_ptr<RenameParameters> parameters(new RenameParameters(
+ ANNOTATE_WITH_SOURCE_INFORMATION, full_path, callback));
+ parameters->client_guid = client_guid;
+ parameters->source_url = source_url;
+ parameters->referrer_url = referrer_url;
+ RenameWithRetryInternal(std::move(parameters));
}
base::TimeDelta DownloadFileImpl::GetRetryDelayForFailedRename(
@@ -139,16 +139,12 @@ bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) {
}
void DownloadFileImpl::RenameWithRetryInternal(
- const base::FilePath& full_path,
- RenameOption option,
- int retries_left,
- base::TimeTicks time_of_first_failure,
- const RenameCompletionCallback& callback) {
+ scoped_ptr<RenameParameters> parameters) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- base::FilePath new_path(full_path);
+ base::FilePath new_path = parameters->new_path;
- if ((option & UNIQUIFY) && full_path != file_.full_path()) {
+ if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) {
int uniquifier =
base::GetUniquePathNumber(new_path, base::FilePath::StringType());
if (uniquifier > 0)
@@ -164,36 +160,36 @@ void DownloadFileImpl::RenameWithRetryInternal(
// have less assurance that the file at file_.full_path() was the one we were
// working with.
if (ShouldRetryFailedRename(reason) && file_.in_progress() &&
- retries_left > 0) {
- int attempt_number = kMaxRenameRetries - retries_left;
+ parameters->retries_left > 0) {
+ int attempt_number = kMaxRenameRetries - parameters->retries_left;
+ --parameters->retries_left;
+ if (parameters->time_of_first_failure.is_null())
+ parameters->time_of_first_failure = base::TimeTicks::Now();
BrowserThread::PostDelayedTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&DownloadFileImpl::RenameWithRetryInternal,
weak_factory_.GetWeakPtr(),
- full_path,
- option,
- --retries_left,
- time_of_first_failure.is_null() ? base::TimeTicks::Now()
- : time_of_first_failure,
- callback),
+ base::Passed(std::move(parameters))),
GetRetryDelayForFailedRename(attempt_number));
return;
}
- if (!time_of_first_failure.is_null())
+ if (!parameters->time_of_first_failure.is_null())
RecordDownloadFileRenameResultAfterRetry(
- base::TimeTicks::Now() - time_of_first_failure, reason);
+ base::TimeTicks::Now() - parameters->time_of_first_failure, reason);
if (reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
- (option & ANNOTATE_WITH_SOURCE_INFORMATION)) {
+ (parameters->option & ANNOTATE_WITH_SOURCE_INFORMATION)) {
// Doing the annotation after the rename rather than before leaves
// a very small window during which the file has the final name but
// hasn't been marked with the Mark Of The Web. However, it allows
// anti-virus scanners on Windows to actually see the data
// (http://crbug.com/127999) under the correct name (which is information
// it uses).
- reason = file_.AnnotateWithSourceInformation();
+ reason = file_.AnnotateWithSourceInformation(parameters->client_guid,
+ parameters->source_url,
+ parameters->referrer_url);
}
if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
@@ -208,8 +204,9 @@ void DownloadFileImpl::RenameWithRetryInternal(
}
BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(callback, reason, new_path));
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(parameters->completion_callback, reason, new_path));
}
void DownloadFileImpl::Detach() {
@@ -220,7 +217,7 @@ void DownloadFileImpl::Cancel() {
file_.Cancel();
}
-base::FilePath DownloadFileImpl::FullPath() const {
+const base::FilePath& DownloadFileImpl::FullPath() const {
return file_.full_path();
}
@@ -228,22 +225,6 @@ bool DownloadFileImpl::InProgress() const {
return file_.in_progress();
}
-int64_t DownloadFileImpl::CurrentSpeed() const {
- return rate_estimator_.GetCountPerSecond();
-}
-
-bool DownloadFileImpl::GetHash(std::string* hash) {
- return file_.GetHash(hash);
-}
-
-std::string DownloadFileImpl::GetHashState() {
- return file_.GetHashState();
-}
-
-void DownloadFileImpl::SetClientGuid(const std::string& guid) {
- file_.SetClientGuid(guid);
-}
-
void DownloadFileImpl::StreamActive() {
base::TimeTicks start(base::TimeTicks::Now());
base::TimeTicks now;
@@ -280,10 +261,6 @@ void DownloadFileImpl::StreamActive() {
stream_reader_->GetStatus());
SendUpdate();
base::TimeTicks close_start(base::TimeTicks::Now());
- if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
- file_.Finish();
- else
- file_.FinishWithError();
base::TimeTicks now(base::TimeTicks::Now());
disk_writes_time_ += (now - close_start);
RecordFileBandwidth(
@@ -321,24 +298,29 @@ void DownloadFileImpl::StreamActive() {
// Our observer will clean us up.
stream_reader_->RegisterCallback(base::Closure());
weak_factory_.InvalidateWeakPtrs();
- SendUpdate(); // Make info up to date before error.
+ SendUpdate(); // Make info up to date before error.
+ scoped_ptr<crypto::SecureHash> hash_state = file_.Finish();
BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
+ BrowserThread::UI,
+ FROM_HERE,
base::Bind(&DownloadDestinationObserver::DestinationError,
- observer_, reason));
+ observer_,
+ reason,
+ file_.bytes_so_far(),
+ base::Passed(&hash_state)));
} else if (state == ByteStreamReader::STREAM_COMPLETE) {
// Signal successful completion and shut down processing.
stream_reader_->RegisterCallback(base::Closure());
weak_factory_.InvalidateWeakPtrs();
- std::string hash;
- if (!GetHash(&hash) || file_.IsEmptyHash(hash))
- hash.clear();
SendUpdate();
+ scoped_ptr<crypto::SecureHash> hash_state = file_.Finish();
BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &DownloadDestinationObserver::DestinationCompleted,
- observer_, hash));
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&DownloadDestinationObserver::DestinationCompleted,
+ observer_,
+ file_.bytes_so_far(),
+ base::Passed(&hash_state)));
}
if (bound_net_log_.IsCapturing()) {
bound_net_log_.AddEvent(
@@ -350,15 +332,23 @@ void DownloadFileImpl::StreamActive() {
void DownloadFileImpl::SendUpdate() {
BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
+ BrowserThread::UI,
+ FROM_HERE,
base::Bind(&DownloadDestinationObserver::DestinationUpdate,
- observer_, file_.bytes_so_far(), CurrentSpeed(),
- GetHashState()));
+ observer_,
+ file_.bytes_so_far(),
+ rate_estimator_.GetCountPerSecond()));
}
-// static
-int DownloadFile::GetNumberOfDownloadFiles() {
- return number_active_objects_;
-}
+DownloadFileImpl::RenameParameters::RenameParameters(
+ RenameOption option,
+ const base::FilePath& new_path,
+ const RenameCompletionCallback& completion_callback)
+ : option(option),
+ new_path(new_path),
+ retries_left(kMaxRenameRetries),
+ completion_callback(completion_callback) {}
+
+DownloadFileImpl::RenameParameters::~RenameParameters() {}
} // namespace content
diff --git a/chromium/content/browser/download/download_file_impl.h b/chromium/content/browser/download/download_file_impl.h
index 98381128505..93b1e551703 100644
--- a/chromium/content/browser/download/download_file_impl.h
+++ b/chromium/content/browser/download/download_file_impl.h
@@ -10,6 +10,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -38,15 +39,11 @@ class CONTENT_EXPORT DownloadFileImpl : public DownloadFile {
// Note that the DownloadFileImpl automatically reads from the passed in
// stream, and sends updates and status of those reads to the
// DownloadDestinationObserver.
- DownloadFileImpl(
- scoped_ptr<DownloadSaveInfo> save_info,
- const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
- scoped_ptr<ByteStreamReader> stream,
- const net::BoundNetLog& bound_net_log,
- base::WeakPtr<DownloadDestinationObserver> observer);
+ DownloadFileImpl(scoped_ptr<DownloadSaveInfo> save_info,
+ const base::FilePath& default_downloads_directory,
+ scoped_ptr<ByteStreamReader> byte_stream,
+ const net::BoundNetLog& bound_net_log,
+ base::WeakPtr<DownloadDestinationObserver> observer);
~DownloadFileImpl() override;
@@ -55,15 +52,14 @@ class CONTENT_EXPORT DownloadFileImpl : public DownloadFile {
void RenameAndUniquify(const base::FilePath& full_path,
const RenameCompletionCallback& callback) override;
void RenameAndAnnotate(const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
const RenameCompletionCallback& callback) override;
void Detach() override;
void Cancel() override;
- base::FilePath FullPath() const override;
+ const base::FilePath& FullPath() const override;
bool InProgress() const override;
- int64_t CurrentSpeed() const override;
- bool GetHash(std::string* hash) override;
- std::string GetHashState() override;
- void SetClientGuid(const std::string& guid) override;
protected:
// For test class overrides.
@@ -85,20 +81,29 @@ class CONTENT_EXPORT DownloadFileImpl : public DownloadFile {
ANNOTATE_WITH_SOURCE_INFORMATION = 1 << 1
};
- // Rename file_ to |new_path|.
- // |option| specifies additional operations to be performed during the rename.
- // See RenameOption above.
- // |retries_left| indicates how many times to retry the operation if the
- // rename fails with a transient error.
- // |time_of_first_failure| Set to an empty base::TimeTicks during the first
- // call. Once the first failure is seen, subsequent calls of
- // RenameWithRetryInternal will have a non-empty value keeping track of
- // the time of first observed failure. Used for UMA.
- void RenameWithRetryInternal(const base::FilePath& new_path,
- RenameOption option,
- int retries_left,
- base::TimeTicks time_of_first_failure,
- const RenameCompletionCallback& callback);
+ struct RenameParameters {
+ RenameParameters(RenameOption option,
+ const base::FilePath& new_path,
+ const RenameCompletionCallback& completion_callback);
+ ~RenameParameters();
+
+ RenameOption option;
+ base::FilePath new_path;
+ std::string client_guid; // See BaseFile::AnnotateWithSourceInformation()
+ GURL source_url; // See BaseFile::AnnotateWithSourceInformation()
+ GURL referrer_url; // See BaseFile::AnnotateWithSourceInformation()
+ int retries_left; // RenameWithRetryInternal() will
+ // automatically retry until this
+ // count reaches 0. Each attempt
+ // decrements this counter.
+ base::TimeTicks time_of_first_failure; // Set to empty at first, but is set
+ // when a failure is first
+ // encountered. Used for UMA.
+ RenameCompletionCallback completion_callback;
+ };
+
+ // Rename file_ based on |parameters|.
+ void RenameWithRetryInternal(scoped_ptr<RenameParameters> parameters);
// Send an update on our progress.
void SendUpdate();
@@ -110,6 +115,11 @@ class CONTENT_EXPORT DownloadFileImpl : public DownloadFile {
// The base file instance.
BaseFile file_;
+ // DownloadSaveInfo provided during construction. Since the DownloadFileImpl
+ // can be created on any thread, this holds the save_info_ until it can be
+ // used to initialize file_ on the FILE thread.
+ scoped_ptr<DownloadSaveInfo> save_info_;
+
// The default directory for creating the download file.
base::FilePath default_download_directory_;
diff --git a/chromium/content/browser/download/download_file_unittest.cc b/chromium/content/browser/download/download_file_unittest.cc
index 9630a49b066..d24eeb81392 100644
--- a/chromium/content/browser/download/download_file_unittest.cc
+++ b/chromium/content/browser/download/download_file_unittest.cc
@@ -4,7 +4,9 @@
#include <stddef.h>
#include <stdint.h>
+
#include <utility>
+#include <vector>
#include "base/files/file.h"
#include "base/files/file_util.h"
@@ -18,9 +20,9 @@
#include "content/browser/browser_thread_impl.h"
#include "content/browser/byte_stream.h"
#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_destination_observer.h"
#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_request_handle.h"
-#include "content/public/browser/download_destination_observer.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_manager.h"
#include "content/public/test/mock_download_manager.h"
@@ -41,6 +43,14 @@ using ::testing::StrictMock;
namespace content {
namespace {
+std::string GetHexEncodedHashValue(crypto::SecureHash* hash_state) {
+ if (!hash_state)
+ return std::string();
+ std::vector<char> hash_value(hash_state->GetHashLength());
+ hash_state->Finish(&hash_value.front(), hash_value.size());
+ return base::HexEncode(&hash_value.front(), hash_value.size());
+}
+
class MockByteStreamReader : public ByteStreamReader {
public:
MockByteStreamReader() {}
@@ -55,21 +65,33 @@ class MockByteStreamReader : public ByteStreamReader {
class MockDownloadDestinationObserver : public DownloadDestinationObserver {
public:
- MOCK_METHOD3(DestinationUpdate, void(int64_t, int64_t, const std::string&));
- MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
- MOCK_METHOD1(DestinationCompleted, void(const std::string&));
+ MOCK_METHOD2(DestinationUpdate, void(int64_t, int64_t));
+ void DestinationError(DownloadInterruptReason reason,
+ int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state) override {
+ MockDestinationError(
+ reason, bytes_so_far, GetHexEncodedHashValue(hash_state.get()));
+ }
+ void DestinationCompleted(
+ int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> hash_state) override {
+ MockDestinationCompleted(total_bytes,
+ GetHexEncodedHashValue(hash_state.get()));
+ }
+
+ MOCK_METHOD3(MockDestinationError,
+ void(DownloadInterruptReason, int64_t, const std::string&));
+ MOCK_METHOD2(MockDestinationCompleted, void(int64_t, const std::string&));
// Doesn't override any methods in the base class. Used to make sure
// that the last DestinationUpdate before a Destination{Completed,Error}
// had the right values.
- MOCK_METHOD3(CurrentUpdateStatus, void(int64_t, int64_t, const std::string&));
+ MOCK_METHOD2(CurrentUpdateStatus, void(int64_t, int64_t));
};
MATCHER(IsNullCallback, "") { return (arg.is_null()); }
-typedef void (DownloadFile::*DownloadFileRenameMethodType)(
- const base::FilePath&,
- const DownloadFile::RenameCompletionCallback&);
+enum DownloadFileRenameMethodType { RENAME_AND_UNIQUIFY, RENAME_AND_ANNOTATE };
// This is a test DownloadFileImpl that has no retry delay and, on Posix,
// retries renames failed due to ACCESS_DENIED.
@@ -77,17 +99,11 @@ class TestDownloadFileImpl : public DownloadFileImpl {
public:
TestDownloadFileImpl(scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_downloads_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer)
: DownloadFileImpl(std::move(save_info),
default_downloads_directory,
- url,
- referrer_url,
- calculate_hash,
std::move(stream),
bound_net_log,
observer) {}
@@ -111,11 +127,11 @@ class TestDownloadFileImpl : public DownloadFileImpl {
class DownloadFileTest : public testing::Test {
public:
-
- static const char* kTestData1;
- static const char* kTestData2;
- static const char* kTestData3;
- static const char* kDataHash;
+ static const char kTestData1[];
+ static const char kTestData2[];
+ static const char kTestData3[];
+ static const char kDataHash[];
+ static const char kEmptyHash[];
static const uint32_t kDummyDownloadId;
static const int kDummyChildId;
static const int kDummyRequestId;
@@ -126,27 +142,23 @@ class DownloadFileTest : public testing::Test {
input_stream_(NULL),
bytes_(-1),
bytes_per_sec_(-1),
- hash_state_("xyzzy"),
ui_thread_(BrowserThread::UI, &loop_),
file_thread_(BrowserThread::FILE, &loop_) {
}
~DownloadFileTest() override {}
- void SetUpdateDownloadInfo(int64_t bytes,
- int64_t bytes_per_sec,
- const std::string& hash_state) {
+ void SetUpdateDownloadInfo(int64_t bytes, int64_t bytes_per_sec) {
bytes_ = bytes;
bytes_per_sec_ = bytes_per_sec;
- hash_state_ = hash_state;
}
void ConfirmUpdateDownloadInfo() {
- observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
+ observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_);
}
void SetUp() override {
- EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
+ EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _))
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
}
@@ -176,15 +188,12 @@ class DownloadFileTest : public testing::Test {
.RetiresOnSaturation();
scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
- scoped_ptr<TestDownloadFileImpl> download_file_impl(
- new TestDownloadFileImpl(
- std::move(save_info), base::FilePath(),
- GURL(), // Source
- GURL(), // Referrer
- calculate_hash, scoped_ptr<ByteStreamReader>(input_stream_),
- net::BoundNetLog(), observer_factory_.GetWeakPtr()));
- download_file_impl->SetClientGuid("12345678-ABCD-1234-DCBA-123456789ABC");
- download_file_ = std::move(download_file_impl);
+ download_file_.reset(
+ new TestDownloadFileImpl(std::move(save_info),
+ base::FilePath(),
+ scoped_ptr<ByteStreamReader>(input_stream_),
+ net::BoundNetLog(),
+ observer_factory_.GetWeakPtr()));
EXPECT_CALL(*input_stream_, Read(_, _))
.WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
@@ -269,19 +278,21 @@ class DownloadFileTest : public testing::Test {
}
void FinishStream(DownloadInterruptReason interrupt_reason,
- bool check_observer) {
+ bool check_observer,
+ const std::string& expected_hash) {
::testing::Sequence s1;
SetupFinishStream(interrupt_reason, s1);
sink_callback_.Run();
VerifyStreamAndSize();
if (check_observer) {
- EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
+ EXPECT_CALL(*(observer_.get()),
+ MockDestinationCompleted(_, expected_hash));
loop_.RunUntilIdle();
::testing::Mock::VerifyAndClearExpectations(observer_.get());
- EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
+ EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _))
.Times(AnyNumber())
- .WillRepeatedly(Invoke(this,
- &DownloadFileTest::SetUpdateDownloadInfo));
+ .WillRepeatedly(
+ Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
}
}
@@ -289,14 +300,14 @@ class DownloadFileTest : public testing::Test {
const base::FilePath& full_path,
base::FilePath* result_path_p) {
return InvokeRenameMethodAndWaitForCallback(
- &DownloadFile::RenameAndUniquify, full_path, result_path_p);
+ RENAME_AND_UNIQUIFY, full_path, result_path_p);
}
DownloadInterruptReason RenameAndAnnotate(
const base::FilePath& full_path,
base::FilePath* result_path_p) {
return InvokeRenameMethodAndWaitForCallback(
- &DownloadFile::RenameAndAnnotate, full_path, result_path_p);
+ RENAME_AND_ANNOTATE, full_path, result_path_p);
}
void ExpectPermissionError(DownloadInterruptReason err) {
@@ -306,20 +317,40 @@ class DownloadFileTest : public testing::Test {
}
protected:
+ void InvokeRenameMethod(
+ DownloadFileRenameMethodType method,
+ const base::FilePath& full_path,
+ const DownloadFile::RenameCompletionCallback& completion_callback) {
+ switch (method) {
+ case RENAME_AND_UNIQUIFY:
+ download_file_->RenameAndUniquify(full_path, completion_callback);
+ break;
+
+ case RENAME_AND_ANNOTATE:
+ download_file_->RenameAndAnnotate(
+ full_path,
+ "12345678-ABCD-1234-DCBA-123456789ABC",
+ GURL(),
+ GURL(),
+ completion_callback);
+ break;
+ }
+ }
+
DownloadInterruptReason InvokeRenameMethodAndWaitForCallback(
DownloadFileRenameMethodType method,
const base::FilePath& full_path,
base::FilePath* result_path_p) {
DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
base::FilePath result_path;
-
base::RunLoop loop_runner;
- ((*download_file_).*method)(full_path,
- base::Bind(&DownloadFileTest::SetRenameResult,
- base::Unretained(this),
- loop_runner.QuitClosure(),
- &result_reason,
- result_path_p));
+ DownloadFile::RenameCompletionCallback completion_callback =
+ base::Bind(&DownloadFileTest::SetRenameResult,
+ base::Unretained(this),
+ loop_runner.QuitClosure(),
+ &result_reason,
+ result_path_p);
+ InvokeRenameMethod(method, full_path, completion_callback);
loop_runner.Run();
return result_reason;
}
@@ -340,7 +371,6 @@ class DownloadFileTest : public testing::Test {
// Latest update sent to the observer.
int64_t bytes_;
int64_t bytes_per_sec_;
- std::string hash_state_;
base::MessageLoop loop_;
@@ -390,15 +420,17 @@ class DownloadFileTestWithRename
// the value parameter.
INSTANTIATE_TEST_CASE_P(DownloadFile,
DownloadFileTestWithRename,
- ::testing::Values(&DownloadFile::RenameAndAnnotate,
- &DownloadFile::RenameAndUniquify));
+ ::testing::Values(RENAME_AND_ANNOTATE,
+ RENAME_AND_UNIQUIFY));
-const char* DownloadFileTest::kTestData1 =
+const char DownloadFileTest::kTestData1[] =
"Let's write some data to the file!\n";
-const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
-const char* DownloadFileTest::kTestData3 = "Final line.";
-const char* DownloadFileTest::kDataHash =
+const char DownloadFileTest::kTestData2[] = "Writing more data.\n";
+const char DownloadFileTest::kTestData3[] = "Final line.";
+const char DownloadFileTest::kDataHash[] =
"CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
+const char DownloadFileTest::kEmptyHash[] =
+ "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855";
const uint32_t DownloadFileTest::kDummyDownloadId = 23;
const int DownloadFileTest::kDummyChildId = 3;
@@ -456,10 +488,7 @@ TEST_P(DownloadFileTestWithRename, RenameFileFinal) {
EXPECT_FALSE(base::PathExists(path_2));
EXPECT_TRUE(base::PathExists(path_3));
- // Should not be able to get the hash until the file is closed.
- std::string hash;
- EXPECT_FALSE(download_file_->GetHash(&hash));
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kDataHash);
loop_.RunUntilIdle();
// Rename the file after downloading all the data and closing the file.
@@ -473,10 +502,6 @@ TEST_P(DownloadFileTestWithRename, RenameFileFinal) {
EXPECT_FALSE(base::PathExists(path_3));
EXPECT_TRUE(base::PathExists(path_4));
- // Check the hash.
- EXPECT_TRUE(download_file_->GetHash(&hash));
- EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
-
DestroyDownloadFile(0);
}
@@ -504,7 +529,7 @@ TEST_F(DownloadFileTest, RenameOverwrites) {
ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
EXPECT_NE(std::string(file_data), file_contents);
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
}
@@ -529,7 +554,7 @@ TEST_F(DownloadFileTest, RenameUniquifies) {
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
EXPECT_TRUE(base::PathExists(path_1_suffixed));
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
}
@@ -546,7 +571,7 @@ TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) {
RenameAndUniquify(initial_path, &new_path));
EXPECT_TRUE(base::PathExists(initial_path));
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
EXPECT_EQ(initial_path.value(), new_path.value());
@@ -581,7 +606,7 @@ TEST_P(DownloadFileTestWithRename, RenameError) {
EXPECT_FALSE(base::PathExists(target_path_suffixed));
}
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
}
@@ -644,10 +669,11 @@ TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
// The Rename() should fail here and enqueue a retry task without invoking
// the completion callback.
- ((*download_file_).*GetParam())(target_path,
- base::Bind(&TestRenameCompletionCallback,
- succeeding_run.QuitClosure(),
- &did_run_callback));
+ InvokeRenameMethod(GetParam(),
+ target_path,
+ base::Bind(&TestRenameCompletionCallback,
+ succeeding_run.QuitClosure(),
+ &did_run_callback));
EXPECT_FALSE(did_run_callback);
base::RunLoop first_failing_run;
@@ -673,7 +699,7 @@ TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
succeeding_run.Run();
EXPECT_TRUE(did_run_callback);
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
}
@@ -688,10 +714,8 @@ TEST_F(DownloadFileTest, StreamEmptySuccess) {
// do anything.
AppendDataToFile(NULL, 0);
- // Finish the download this way and make sure we see it on the
- // observer.
- EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
+ // Finish the download this way and make sure we see it on the observer.
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
loop_.RunUntilIdle();
DestroyDownloadFile(0);
@@ -704,9 +728,10 @@ TEST_F(DownloadFileTest, StreamEmptyError) {
// Finish the download in error and make sure we see it on the
// observer.
- EXPECT_CALL(*(observer_.get()),
- DestinationError(
- DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
+ EXPECT_CALL(
+ *(observer_.get()),
+ MockDestinationError(
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, 0, kEmptyHash))
.WillOnce(InvokeWithoutArgs(
this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
@@ -715,9 +740,10 @@ TEST_F(DownloadFileTest, StreamEmptyError) {
// the last one may have the correct information even if the failure
// doesn't produce an update, as the timer update may have triggered at the
// same time.
- EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
+ EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _));
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
+ FinishStream(
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false, kEmptyHash);
loop_.RunUntilIdle();
@@ -733,7 +759,7 @@ TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
::testing::Sequence s1;
SetupDataAppend(chunks1, 2, s1);
SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
- EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
+ EXPECT_CALL(*(observer_.get()), MockDestinationCompleted(_, _));
sink_callback_.Run();
VerifyStreamAndSize();
loop_.RunUntilIdle();
@@ -751,8 +777,8 @@ TEST_F(DownloadFileTest, StreamNonEmptyError) {
SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
EXPECT_CALL(*(observer_.get()),
- DestinationError(
- DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
+ MockDestinationError(
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, _, _))
.WillOnce(InvokeWithoutArgs(
this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
@@ -762,8 +788,7 @@ TEST_F(DownloadFileTest, StreamNonEmptyError) {
// doesn't produce an update, as the timer update may have triggered at the
// same time.
EXPECT_CALL(*(observer_.get()),
- CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
- _, _));
+ CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2), _));
sink_callback_.Run();
loop_.RunUntilIdle();
@@ -771,26 +796,4 @@ TEST_F(DownloadFileTest, StreamNonEmptyError) {
DestroyDownloadFile(0);
}
-// Send some data, wait 3/4s of a second, run the message loop, and
-// confirm the values the observer received are correct.
-TEST_F(DownloadFileTest, ConfirmUpdate) {
- CreateDownloadFile(0, true);
-
- const char* chunks1[] = { kTestData1, kTestData2 };
- AppendDataToFile(chunks1, 2);
-
- // Run the message loops for 750ms and check for results.
- loop_.task_runner()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitWhenIdleClosure(),
- base::TimeDelta::FromMilliseconds(750));
- loop_.Run();
-
- EXPECT_EQ(static_cast<int64_t>(strlen(kTestData1) + strlen(kTestData2)),
- bytes_);
- EXPECT_EQ(download_file_->GetHashState(), hash_state_);
-
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
- DestroyDownloadFile(0);
-}
-
} // namespace content
diff --git a/chromium/content/browser/download/download_interrupt_reasons_impl.cc b/chromium/content/browser/download/download_interrupt_reasons_impl.cc
index 2ed8f147ee0..406c4e9d33a 100644
--- a/chromium/content/browser/download/download_interrupt_reasons_impl.cc
+++ b/chromium/content/browser/download/download_interrupt_reasons_impl.cc
@@ -83,7 +83,8 @@ DownloadInterruptReason ConvertNetErrorToInterruptReason(
case net::ERR_TIMED_OUT:
return DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT;
- // The network connection has been lost.
+ // The network connection was lost or changed.
+ case net::ERR_NETWORK_CHANGED:
case net::ERR_INTERNET_DISCONNECTED:
return DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED;
diff --git a/chromium/content/browser/download/download_item_factory.h b/chromium/content/browser/download/download_item_factory.h
index 0069e43422e..caf8ef8ce4b 100644
--- a/chromium/content/browser/download/download_item_factory.h
+++ b/chromium/content/browser/download/download_item_factory.h
@@ -41,6 +41,7 @@ public:
virtual DownloadItemImpl* CreatePersistedItem(
DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t download_id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -54,6 +55,7 @@ public:
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
diff --git a/chromium/content/browser/download/download_item_impl.cc b/chromium/content/browser/download/download_item_impl.cc
index cef57731792..08d90390a60 100644
--- a/chromium/content/browser/download/download_item_impl.cc
+++ b/chromium/content/browser/download/download_item_impl.cc
@@ -29,15 +29,18 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
+#include "base/guid.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
#include "content/browser/download/download_item_impl_delegate.h"
+#include "content/browser/download/download_net_log_parameters.h"
#include "content/browser/download/download_request_handle.h"
#include "content/browser/download/download_stats.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -50,7 +53,6 @@
#include "content/public/browser/download_url_parameters.h"
#include "content/public/common/content_features.h"
#include "content/public/common/referrer.h"
-#include "net/base/net_util.h"
namespace content {
@@ -99,13 +101,12 @@ bool IsDownloadResumptionEnabled() {
const uint32_t DownloadItem::kInvalidId = 0;
-const char DownloadItem::kEmptyFileHash[] = "";
-
// The maximum number of attempts we will make to resume automatically.
const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
// Constructor for reading from the history service.
DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t download_id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -119,27 +120,20 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
bool opened,
const net::BoundNetLog& bound_net_log)
- : is_save_package_download_(false),
+ : guid_(base::ToUpperASCII(guid)),
download_id_(download_id),
- current_path_(current_path),
target_path_(target_path),
- target_disposition_(TARGET_DISPOSITION_OVERWRITE),
url_chain_(url_chain),
referrer_url_(referrer_url),
- transition_type_(ui::PAGE_TRANSITION_LINK),
- has_user_gesture_(false),
mime_type_(mime_type),
original_mime_type_(original_mime_type),
total_bytes_(total_bytes),
- received_bytes_(received_bytes),
- bytes_per_sec_(0),
- last_modified_time_(last_modified),
- etag_(etag),
last_reason_(interrupt_reason),
start_tick_(base::TimeTicks()),
state_(ExternalToInternalState(state)),
@@ -147,20 +141,19 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
start_time_(start_time),
end_time_(end_time),
delegate_(delegate),
- is_paused_(false),
- auto_resume_count_(0),
- open_when_complete_(false),
- file_externally_removed_(false),
- auto_opened_(false),
- is_temporary_(false),
- all_data_saved_(state == COMPLETE),
- destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
opened_(opened),
- delegate_delayed_complete_(false),
+ current_path_(current_path),
+ received_bytes_(received_bytes),
+ all_data_saved_(state == COMPLETE),
+ hash_(hash),
+ last_modified_time_(last_modified),
+ etag_(etag),
bound_net_log_(bound_net_log),
weak_ptr_factory_(this) {
delegate_->Attach();
- DCHECK_NE(IN_PROGRESS_INTERNAL, state_);
+ DCHECK(state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
+ state_ == CANCELLED_INTERNAL);
+ DCHECK(base::IsValidGUID(guid_));
Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
}
@@ -169,7 +162,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
uint32_t download_id,
const DownloadCreateInfo& info,
const net::BoundNetLog& bound_net_log)
- : is_save_package_download_(false),
+ : guid_(base::ToUpperASCII(base::GenerateGUID())),
download_id_(download_id),
target_disposition_((info.save_info->prompt_for_save_location)
? TARGET_DISPOSITION_PROMPT
@@ -187,26 +180,14 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
original_mime_type_(info.original_mime_type),
remote_address_(info.remote_address),
total_bytes_(info.total_bytes),
- received_bytes_(0),
- bytes_per_sec_(0),
- last_modified_time_(info.last_modified),
- etag_(info.etag),
- last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
+ last_reason_(info.result),
start_tick_(base::TimeTicks::Now()),
- state_(IN_PROGRESS_INTERNAL),
- danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
+ state_(INITIAL_INTERNAL),
start_time_(info.start_time),
delegate_(delegate),
- is_paused_(false),
- auto_resume_count_(0),
- open_when_complete_(false),
- file_externally_removed_(false),
- auto_opened_(false),
is_temporary_(!info.save_info->file_path.empty()),
- all_data_saved_(false),
- destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
- opened_(false),
- delegate_delayed_complete_(false),
+ last_modified_time_(info.last_modified),
+ etag_(info.etag),
bound_net_log_(bound_net_log),
weak_ptr_factory_(this) {
delegate_->Attach();
@@ -233,35 +214,17 @@ DownloadItemImpl::DownloadItemImpl(
const net::BoundNetLog& bound_net_log)
: is_save_package_download_(true),
request_handle_(std::move(request_handle)),
+ guid_(base::ToUpperASCII(base::GenerateGUID())),
download_id_(download_id),
- current_path_(path),
target_path_(path),
- target_disposition_(TARGET_DISPOSITION_OVERWRITE),
url_chain_(1, url),
- referrer_url_(GURL()),
- transition_type_(ui::PAGE_TRANSITION_LINK),
- has_user_gesture_(false),
mime_type_(mime_type),
original_mime_type_(mime_type),
- total_bytes_(0),
- received_bytes_(0),
- bytes_per_sec_(0),
- last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
start_tick_(base::TimeTicks::Now()),
state_(IN_PROGRESS_INTERNAL),
- danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
start_time_(base::Time::Now()),
delegate_(delegate),
- is_paused_(false),
- auto_resume_count_(0),
- open_when_complete_(false),
- file_externally_removed_(false),
- auto_opened_(false),
- is_temporary_(false),
- all_data_saved_(false),
- destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
- opened_(false),
- delegate_delayed_complete_(false),
+ current_path_(path),
bound_net_log_(bound_net_log),
weak_ptr_factory_(this) {
delegate_->Attach();
@@ -294,6 +257,7 @@ void DownloadItemImpl::RemoveObserver(Observer* observer) {
void DownloadItemImpl::UpdateObservers() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << "()";
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
}
@@ -317,7 +281,9 @@ void DownloadItemImpl::ValidateDangerousDownload() {
net::NetLog::TYPE_DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
base::Bind(&ItemCheckedNetLogCallback, GetDangerType()));
- UpdateObservers();
+ UpdateObservers(); // TODO(asanka): This is potentially unsafe. The download
+ // may not be in a consistent state or around at all after
+ // invoking observers. http://crbug.com/586610
MaybeCompleteDownload();
}
@@ -327,6 +293,7 @@ void DownloadItemImpl::StealDangerousDownload(
DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(IsDangerous());
+
if (download_file_) {
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE,
@@ -345,17 +312,50 @@ void DownloadItemImpl::Pause() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Ignore irrelevant states.
- if (state_ != IN_PROGRESS_INTERNAL || is_paused_)
+ if (is_paused_)
return;
- request_handle_->PauseRequest();
- is_paused_ = true;
- UpdateObservers();
+ switch (state_) {
+ case CANCELLED_INTERNAL:
+ case COMPLETE_INTERNAL:
+ case COMPLETING_INTERNAL:
+ case INITIAL_INTERNAL:
+ case INTERRUPTED_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ case RESUMING_INTERNAL:
+ // No active request.
+ // TODO(asanka): In the case of RESUMING_INTERNAL, consider setting
+ // is_paused_ even if there's no request currently associated with this
+ // DII. When a request is assigned (due to a resumption, for example) we
+ // can honor the is_paused_ setting.
+ return;
+
+ case IN_PROGRESS_INTERNAL:
+ case TARGET_PENDING_INTERNAL:
+ request_handle_->PauseRequest();
+ is_paused_ = true;
+ UpdateObservers();
+ return;
+
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ case TARGET_RESOLVED_INTERNAL:
+ NOTREACHED();
+ }
}
void DownloadItemImpl::Resume() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
switch (state_) {
+ case CANCELLED_INTERNAL: // Nothing to resume.
+ case COMPLETE_INTERNAL:
+ case COMPLETING_INTERNAL:
+ case INITIAL_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ case RESUMING_INTERNAL: // Resumption in progress.
+ return;
+
+ case TARGET_PENDING_INTERNAL:
case IN_PROGRESS_INTERNAL:
if (!is_paused_)
return;
@@ -364,70 +364,25 @@ void DownloadItemImpl::Resume() {
UpdateObservers();
return;
- case COMPLETING_INTERNAL:
- case COMPLETE_INTERNAL:
- case CANCELLED_INTERNAL:
- case RESUMING_INTERNAL:
- return;
-
case INTERRUPTED_INTERNAL:
auto_resume_count_ = 0; // User input resets the counter.
ResumeInterruptedDownload();
+ UpdateObservers();
return;
case MAX_DOWNLOAD_INTERNAL_STATE:
+ case TARGET_RESOLVED_INTERNAL:
NOTREACHED();
}
}
void DownloadItemImpl::Cancel(bool user_cancel) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
DVLOG(20) << __FUNCTION__ << "() download = " << DebugString(true);
- if (state_ != IN_PROGRESS_INTERNAL &&
- state_ != INTERRUPTED_INTERNAL &&
- state_ != RESUMING_INTERNAL) {
- // Small downloads might be complete before this method has a chance to run.
- return;
- }
-
- if (IsDangerous()) {
- RecordDangerousDownloadDiscard(
- user_cancel ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
- : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
- GetDangerType(),
- GetTargetFilePath());
- }
-
- last_reason_ = user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
- : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
-
- RecordDownloadCount(CANCELLED_COUNT);
-
- // TODO(rdsmith/benjhayden): Remove condition as part of
- // |SavePackage| integration.
- // |download_file_| can be NULL if Interrupt() is called after the
- // download file has been released.
- if (!is_save_package_download_ && download_file_)
- ReleaseDownloadFile(true);
-
- if (state_ == IN_PROGRESS_INTERNAL) {
- // Cancel the originating URL request unless it's already been cancelled
- // by interrupt.
- request_handle_->CancelRequest();
- }
-
- // Remove the intermediate file if we are cancelling an interrupted download.
- // Continuable interruptions leave the intermediate file around.
- if ((state_ == INTERRUPTED_INTERNAL || state_ == RESUMING_INTERNAL) &&
- !current_path_.empty()) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(base::IgnoreResult(&DeleteDownloadedFile), current_path_));
- current_path_.clear();
- }
-
- TransitionTo(CANCELLED_INTERNAL, UPDATE_OBSERVERS);
+ InterruptAndDiscardPartialState(
+ user_cancel ? DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
+ : DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN);
+ UpdateObservers();
}
void DownloadItemImpl::Remove() {
@@ -435,7 +390,8 @@ void DownloadItemImpl::Remove() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_->AssertStateConsistent(this);
- Cancel(true);
+ InterruptAndDiscardPartialState(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
+ UpdateObservers();
delegate_->AssertStateConsistent(this);
NotifyRemoved();
@@ -478,6 +434,10 @@ uint32_t DownloadItemImpl::GetId() const {
return download_id_;
}
+const std::string& DownloadItemImpl::GetGuid() const {
+ return guid_;
+}
+
DownloadItem::DownloadState DownloadItemImpl::GetState() const {
return InternalToExternalState(state_);
}
@@ -495,26 +455,45 @@ bool DownloadItemImpl::IsTemporary() const {
}
bool DownloadItemImpl::CanResume() const {
- if ((GetState() == IN_PROGRESS) && IsPaused())
- return true;
-
- if (state_ != INTERRUPTED_INTERNAL)
- return false;
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ switch (state_) {
+ case INITIAL_INTERNAL:
+ case COMPLETING_INTERNAL:
+ case COMPLETE_INTERNAL:
+ case CANCELLED_INTERNAL:
+ case RESUMING_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ return false;
- // We currently only support HTTP(S) requests for download resumption.
- if (!GetURL().SchemeIsHTTPOrHTTPS())
- return false;
+ case TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ case IN_PROGRESS_INTERNAL:
+ return is_paused_;
+
+ case INTERRUPTED_INTERNAL: {
+ ResumeMode resume_mode = GetResumeMode();
+ // Only allow Resume() calls if the resumption mode requires a user
+ // action.
+ return IsDownloadResumptionEnabled() &&
+ (resume_mode == RESUME_MODE_USER_RESTART ||
+ resume_mode == RESUME_MODE_USER_CONTINUE);
+ }
- ResumeMode resume_mode = GetResumeMode();
- return IsDownloadResumptionEnabled() &&
- (resume_mode == RESUME_MODE_USER_RESTART ||
- resume_mode == RESUME_MODE_USER_CONTINUE);
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ NOTREACHED();
+ }
+ return false;
}
bool DownloadItemImpl::IsDone() const {
switch (state_) {
- case IN_PROGRESS_INTERNAL:
+ case INITIAL_INTERNAL:
case COMPLETING_INTERNAL:
+ case RESUMING_INTERNAL:
+ case TARGET_PENDING_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ case IN_PROGRESS_INTERNAL:
return false;
case COMPLETE_INTERNAL:
@@ -524,14 +503,10 @@ bool DownloadItemImpl::IsDone() const {
case INTERRUPTED_INTERNAL:
return !CanResume();
- case RESUMING_INTERNAL:
- return false;
-
case MAX_DOWNLOAD_INTERNAL_STATE:
- break;
+ NOTREACHED();
}
- NOTREACHED();
- return true;
+ return false;
}
const GURL& DownloadItemImpl::GetURL() const {
@@ -628,10 +603,6 @@ const std::string& DownloadItemImpl::GetHash() const {
return hash_;
}
-const std::string& DownloadItemImpl::GetHashState() const {
- return hash_state_;
-}
-
bool DownloadItemImpl::GetFileExternallyRemoved() const {
return file_externally_removed_;
}
@@ -770,6 +741,14 @@ WebContents* DownloadItemImpl::GetWebContents() const {
void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(AllDataSaved());
+
+ // Danger type is only allowed to be set on an active download after all data
+ // has been saved. This excludes all other states. In particular,
+ // OnContentCheckCompleted() isn't allowed on an INTERRUPTED download since
+ // such an interruption would need to happen between OnAllDataSaved() and
+ // OnContentCheckCompleted() during which no disk or network activity
+ // should've taken place.
+ DCHECK_EQ(state_, IN_PROGRESS_INTERNAL);
DVLOG(20) << __FUNCTION__ << " danger_type=" << danger_type
<< " download=" << DebugString(true);
SetDangerType(danger_type);
@@ -815,8 +794,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
if (verbose) {
description += base::StringPrintf(
- " total = %" PRId64
- " received = %" PRId64
+ " total = %" PRId64 " received = %" PRId64
" reason = %s"
" paused = %c"
" resume_mode = %s"
@@ -827,7 +805,8 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
" etag = '%s'"
" has_download_file = %s"
" url_chain = \n\t\"%s\"\n\t"
- " full_path = \"%" PRFilePath "\"\n\t"
+ " current_path = \"%" PRFilePath
+ "\"\n\t"
" target_path = \"%" PRFilePath "\"",
GetTotalBytes(),
GetReceivedBytes(),
@@ -854,62 +833,78 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!IsDownloadResumptionEnabled())
+ return RESUME_MODE_INVALID;
+
+ // Only support resumption for HTTP(S).
+ if (!GetURL().SchemeIsHTTPOrHTTPS())
+ return RESUME_MODE_INVALID;
+
// We can't continue without a handle on the intermediate file.
// We also can't continue if we don't have some verifier to make sure
// we're getting the same file.
- const bool force_restart =
+ bool restart_required =
(current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
// We won't auto-restart if we've used up our attempts or the
// download has been paused by user action.
- const bool force_user =
+ bool user_action_required =
(auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
- ResumeMode mode = RESUME_MODE_INVALID;
-
switch(last_reason_) {
case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
- if (force_restart && force_user)
- mode = RESUME_MODE_USER_RESTART;
- else if (force_restart)
- mode = RESUME_MODE_IMMEDIATE_RESTART;
- else if (force_user)
- mode = RESUME_MODE_USER_CONTINUE;
- else
- mode = RESUME_MODE_IMMEDIATE_CONTINUE;
break;
case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+ // The server disagreed with the file offset that we sent.
+
+ case DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
+ // The file on disk was found to not match the expected hash. Discard and
+ // start from beginning.
+
case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
- if (force_user)
- mode = RESUME_MODE_USER_RESTART;
- else
- mode = RESUME_MODE_IMMEDIATE_RESTART;
+ // The [possibly persisted] file offset disagreed with the file on disk.
+
+ // The intermediate stub is not usable and the server is responding. Hence
+ // retrying the request from the beginning is likely to work.
+ restart_required = true;
break;
case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
case DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
case DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
- case DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
case DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
+ case DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE:
case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
case DOWNLOAD_INTERRUPT_REASON_CRASH:
- if (force_restart)
- mode = RESUME_MODE_USER_RESTART;
- else
- mode = RESUME_MODE_USER_CONTINUE;
+ // It is not clear whether attempting a resumption is acceptable at this
+ // time or whether it would work at all. Hence allow the user to retry the
+ // download manually.
+ user_action_required = true;
+ break;
+
+ case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
+ // There was no space. Require user interaction so that the user may, for
+ // example, choose a different location to store the file. Or they may
+ // free up some space on the targret device and retry. But try to reuse
+ // the partial stub.
+ user_action_required = true;
break;
case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
- case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
- mode = RESUME_MODE_USER_RESTART;
+ // Assume the partial stub is unusable. Also it may not be possible to
+ // restart immediately.
+ user_action_required = true;
+ restart_required = true;
break;
case DOWNLOAD_INTERRUPT_REASON_NONE:
+ case DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
case DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
case DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
@@ -918,14 +913,23 @@ DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
case DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
- mode = RESUME_MODE_INVALID;
- break;
+ // Unhandled.
+ return RESUME_MODE_INVALID;
}
- return mode;
+ if (user_action_required && restart_required)
+ return RESUME_MODE_USER_RESTART;
+
+ if (restart_required)
+ return RESUME_MODE_IMMEDIATE_RESTART;
+
+ if (user_action_required)
+ return RESUME_MODE_USER_CONTINUE;
+
+ return RESUME_MODE_IMMEDIATE_CONTINUE;
}
-void DownloadItemImpl::MergeOriginInfoOnResume(
+void DownloadItemImpl::UpdateValidatorsOnResumption(
const DownloadCreateInfo& new_create_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(RESUMING_INTERNAL, state_);
@@ -955,8 +959,7 @@ void DownloadItemImpl::MergeOriginInfoOnResume(
origin_state |= ORIGIN_STATE_ON_RESUMPTION_VALIDATORS_CHANGED;
if (content_disposition_ != new_create_info.content_disposition)
origin_state |= ORIGIN_STATE_ON_RESUMPTION_CONTENT_DISPOSITION_CHANGED;
- RecordOriginStateOnResumption(new_create_info.save_info->offset != 0,
- origin_state);
+ RecordOriginStateOnResumption(received_bytes_ != 0, origin_state);
url_chain_.insert(
url_chain_.end(), chain_iter, new_create_info.url_chain.end());
@@ -992,18 +995,20 @@ void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) {
total_bytes_ = total_bytes;
}
-void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
+void DownloadItemImpl::OnAllDataSaved(
+ int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> hash_state) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
DCHECK(!all_data_saved_);
all_data_saved_ = true;
- DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
-
- // Store final hash and null out intermediate serialized hash state.
- hash_ = final_hash;
- hash_state_ = "";
+ SetTotalBytes(total_bytes);
+ UpdateProgress(total_bytes, 0);
+ SetHashState(std::move(hash_state));
+ hash_state_.reset(); // No need to retain hash_state_ since we are done with
+ // the download and don't expect to receive any more
+ // data.
+ DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
UpdateObservers();
}
@@ -1012,38 +1017,28 @@ void DownloadItemImpl::MarkAsComplete() {
DCHECK(all_data_saved_);
end_time_ = base::Time::Now();
- TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
+ TransitionTo(COMPLETE_INTERNAL);
+ UpdateObservers();
}
void DownloadItemImpl::DestinationUpdate(int64_t bytes_so_far,
- int64_t bytes_per_sec,
- const std::string& hash_state) {
+ int64_t bytes_per_sec) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DVLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
- << " per_sec=" << bytes_per_sec << " download="
- << DebugString(true);
-
- if (GetState() != IN_PROGRESS) {
- // Ignore if we're no longer in-progress. This can happen if we race a
- // Cancel on the UI thread with an update on the FILE thread.
- //
- // TODO(rdsmith): Arguably we should let this go through, as this means
- // the download really did get further than we know before it was
- // cancelled. But the gain isn't very large, and the code is more
- // fragile if it has to support in progress updates in a non-in-progress
- // state. This issue should be readdressed when we revamp performance
- // reporting.
- return;
- }
- bytes_per_sec_ = bytes_per_sec;
- hash_state_ = hash_state;
- received_bytes_ = bytes_so_far;
+ // If the download is in any other state we don't expect any
+ // DownloadDestinationObserver callbacks. An interruption or a cancellation
+ // results in a call to ReleaseDownloadFile which invalidates the weak
+ // reference held by the DownloadFile and hence cuts off any pending
+ // callbacks.
+ DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
- // If we've received more data than we were expecting (bad server info?),
- // revert to 'unknown size mode'.
- if (received_bytes_ > total_bytes_)
- total_bytes_ = 0;
+ // There must be no pending destination_error_.
+ DCHECK_EQ(destination_error_, DOWNLOAD_INTERRUPT_REASON_NONE);
+ DVLOG(20) << __FUNCTION__ << " so_far=" << bytes_so_far
+ << " per_sec=" << bytes_per_sec
+ << " download=" << DebugString(true);
+
+ UpdateProgress(bytes_so_far, bytes_per_sec);
if (bound_net_log_.IsCapturing()) {
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
@@ -1053,21 +1048,47 @@ void DownloadItemImpl::DestinationUpdate(int64_t bytes_so_far,
UpdateObservers();
}
-void DownloadItemImpl::DestinationError(DownloadInterruptReason reason) {
+void DownloadItemImpl::DestinationError(
+ DownloadInterruptReason reason,
+ int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> secure_hash) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // If the download is in any other state we don't expect any
+ // DownloadDestinationObserver callbacks. An interruption or a cancellation
+ // results in a call to ReleaseDownloadFile which invalidates the weak
+ // reference held by the DownloadFile and hence cuts off any pending
+ // callbacks.
+ DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
+ DVLOG(20) << __FUNCTION__
+ << "() reason:" << DownloadInterruptReasonToString(reason);
+
// Postpone recognition of this error until after file name determination
// has completed and the intermediate file has been renamed to simplify
// resumption conditions.
- if (current_path_.empty() || target_path_.empty())
+ if (state_ == TARGET_PENDING_INTERNAL) {
+ received_bytes_ = bytes_so_far;
+ hash_state_ = std::move(secure_hash);
+ hash_.clear();
destination_error_ = reason;
- else
- Interrupt(reason);
+ return;
+ }
+ InterruptWithPartialState(bytes_so_far, std::move(secure_hash), reason);
+ UpdateObservers();
}
-void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
+void DownloadItemImpl::DestinationCompleted(
+ int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> secure_hash) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // If the download is in any other state we don't expect any
+ // DownloadDestinationObserver callbacks. An interruption or a cancellation
+ // results in a call to ReleaseDownloadFile which invalidates the weak
+ // reference held by the DownloadFile and hence cuts off any pending
+ // callbacks.
+ DCHECK(state_ == TARGET_PENDING_INTERNAL || state_ == IN_PROGRESS_INTERNAL);
DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
- if (GetState() != IN_PROGRESS)
- return;
- OnAllDataSaved(final_hash);
+
+ OnAllDataSaved(total_bytes, std::move(secure_hash));
MaybeCompleteDownload();
}
@@ -1111,24 +1132,79 @@ void DownloadItemImpl::Init(bool active,
// We're starting the download.
void DownloadItemImpl::Start(
scoped_ptr<DownloadFile> file,
- scoped_ptr<DownloadRequestHandleInterface> req_handle) {
+ scoped_ptr<DownloadRequestHandleInterface> req_handle,
+ const DownloadCreateInfo& new_create_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!download_file_.get());
- DCHECK(file.get());
- DCHECK(req_handle.get());
+ DVLOG(20) << __FUNCTION__ << "() this=" << DebugString(true);
download_file_ = std::move(file);
request_handle_ = std::move(req_handle);
+ destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
- if (GetState() == CANCELLED) {
+ if (state_ == CANCELLED_INTERNAL) {
// The download was in the process of resuming when it was cancelled. Don't
// proceed.
ReleaseDownloadFile(true);
- request_handle_->CancelRequest();
+ if (request_handle_)
+ request_handle_->CancelRequest();
+ return;
+ }
+
+ // The state could be one of the following:
+ //
+ // INITIAL_INTERNAL: A normal download attempt.
+ //
+ // RESUMING_INTERNAL: A resumption attempt. May or may not have been
+ // successful.
+ DCHECK(state_ == INITIAL_INTERNAL || state_ == RESUMING_INTERNAL);
+
+ // If the state_ is INITIAL_INTERNAL, then the target path must be empty.
+ DCHECK(state_ != INITIAL_INTERNAL || target_path_.empty());
+
+ // If a resumption attempted failed, or if the download was DOA, then the
+ // download should go back to being interrupted.
+ if (new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) {
+ DCHECK(!download_file_.get());
+
+ // Download requests that are interrupted by Start() should result in a
+ // DownloadCreateInfo with an intact DownloadSaveInfo.
+ DCHECK(new_create_info.save_info);
+
+ int64_t offset = new_create_info.save_info->offset;
+ scoped_ptr<crypto::SecureHash> hash_state =
+ make_scoped_ptr(new_create_info.save_info->hash_state
+ ? new_create_info.save_info->hash_state->Clone()
+ : nullptr);
+
+ // Interrupted downloads also need a target path.
+ if (target_path_.empty()) {
+ received_bytes_ = offset;
+ hash_state_ = std::move(hash_state);
+ hash_.clear();
+ destination_error_ = new_create_info.result;
+ TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
+ DetermineDownloadTarget();
+ return;
+ }
+
+ // Otherwise, this was a resumption attempt which ended with an
+ // interruption. Continue with current target path.
+ TransitionTo(TARGET_RESOLVED_INTERNAL);
+ InterruptWithPartialState(
+ offset, std::move(hash_state), new_create_info.result);
+ UpdateObservers();
return;
}
- TransitionTo(IN_PROGRESS_INTERNAL, UPDATE_OBSERVERS);
+ // Successful download start.
+ DCHECK(download_file_.get());
+ DCHECK(request_handle_.get());
+
+ if (state_ == RESUMING_INTERNAL)
+ UpdateValidatorsOnResumption(new_create_info);
+
+ TransitionTo(TARGET_PENDING_INTERNAL);
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
@@ -1142,32 +1218,41 @@ void DownloadItemImpl::Start(
void DownloadItemImpl::OnDownloadFileInitialized(
DownloadInterruptReason result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
+ DVLOG(20) << __FUNCTION__
+ << "() result:" << DownloadInterruptReasonToString(result);
if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
- Interrupt(result);
- // TODO(rdsmith/asanka): Arguably we should show this in the UI, but
- // it's not at all clear what to show--we haven't done filename
- // determination, so we don't know what name to display. OTOH,
- // the failure mode of not showing the DI if the file initialization
- // fails isn't a good one. Can we hack up a name based on the
- // URLRequest? We'll need to make sure that initialization happens
- // properly. Possibly the right thing is to have the UI handle
- // this case specially.
- return;
+ // Whoops. That didn't work. Proceed as an interrupted download, but reset
+ // the partial state. Currently, the partial stub cannot be recovered if the
+ // download file initialization fails.
+ received_bytes_ = 0;
+ hash_state_.reset();
+ hash_.clear();
+ destination_error_ = result;
+ TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
}
+ DetermineDownloadTarget();
+}
+
+void DownloadItemImpl::DetermineDownloadTarget() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << "() " << DebugString(true);
+
delegate_->DetermineDownloadTarget(
this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
weak_ptr_factory_.GetWeakPtr()));
}
-// Called by delegate_ when the download target path has been
-// determined.
+// Called by delegate_ when the download target path has been determined.
void DownloadItemImpl::OnDownloadTargetDetermined(
const base::FilePath& target_path,
TargetDisposition disposition,
DownloadDangerType danger_type,
const base::FilePath& intermediate_path) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(state_ == TARGET_PENDING_INTERNAL ||
+ state_ == INTERRUPTED_TARGET_PENDING_INTERNAL);
// If the |target_path| is empty, then we consider this download to be
// canceled.
@@ -1176,21 +1261,24 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
return;
}
- // TODO(rdsmith,asanka): We are ignoring the possibility that the download
- // has been interrupted at this point until we finish the intermediate
- // rename and set the full path. That's dangerous, because we might race
- // with resumption, either manual (because the interrupt is visible to the
- // UI) or automatic. If we keep the "ignore an error on download until file
- // name determination complete" semantics, we need to make sure that the
- // error is kept completely invisible until that point.
-
- DVLOG(20) << __FUNCTION__ << " " << target_path.value() << " " << disposition
- << " " << danger_type << " " << DebugString(true);
+ DVLOG(20) << __FUNCTION__ << "() target_path:" << target_path.value()
+ << " disposition:" << disposition << " danger_type:" << danger_type
+ << " this:" << DebugString(true);
target_path_ = target_path;
target_disposition_ = disposition;
SetDangerType(danger_type);
+ // This was an interrupted download that was looking for a filename. Now that
+ // it has one, transition to interrupted.
+ if (state_ == INTERRUPTED_TARGET_PENDING_INTERNAL) {
+ InterruptWithPartialState(
+ received_bytes_, std::move(hash_state_), destination_error_);
+ destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
+ UpdateObservers();
+ return;
+ }
+
// We want the intermediate and target paths to refer to the same directory so
// that they are both on the same device and subject to same
// space/permission/availability constraints.
@@ -1231,27 +1319,38 @@ void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
DownloadInterruptReason reason,
const base::FilePath& full_path) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_EQ(state_, TARGET_PENDING_INTERNAL);
DVLOG(20) << __FUNCTION__ << " download=" << DebugString(true);
+ TransitionTo(TARGET_RESOLVED_INTERNAL);
+
+ // If the intermediate rename fails while there's also a destination_error_,
+ // then the former is considered the critical error since it requires
+ // discarding the partial state.
+ if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
+ // TODO(asanka): Even though the rename failed, it may still be possible to
+ // recover the partial state from the 'before' name.
+ InterruptAndDiscardPartialState(reason);
+ UpdateObservers();
+ return;
+ }
+
if (DOWNLOAD_INTERRUPT_REASON_NONE != destination_error_) {
- // Process destination error. If both |reason| and |destination_error_|
- // refer to actual errors, we want to use the |destination_error_| as the
- // argument to the Interrupt() routine, as it happened first.
- if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
- SetFullPath(full_path);
- Interrupt(destination_error_);
- destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
- } else if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
- Interrupt(reason);
- // All file errors result in file deletion above; no need to cleanup. The
- // current_path_ should be empty. Resuming this download will force a
- // restart and a re-doing of filename determination.
- DCHECK(current_path_.empty());
- } else {
SetFullPath(full_path);
+ InterruptWithPartialState(
+ received_bytes_, std::move(hash_state_), destination_error_);
+ destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
UpdateObservers();
- MaybeCompleteDownload();
+ return;
}
+
+ SetFullPath(full_path);
+ TransitionTo(IN_PROGRESS_INTERNAL);
+ // TODO(asanka): Calling UpdateObservers() prior to MaybeCompleteDownload() is
+ // not safe. The download could be in an underminate state after invoking
+ // observers. http://crbug.com/586610
+ UpdateObservers();
+ MaybeCompleteDownload();
}
// When SavePackage downloads MHTML to GData (see
@@ -1272,12 +1371,8 @@ void DownloadItemImpl::MaybeCompleteDownload() {
weak_ptr_factory_.GetWeakPtr())))
return;
- // TODO(rdsmith): DCHECK that we only pass through this point
- // once per download. The natural way to do this is by a state
- // transition on the DownloadItem.
-
- // Confirm we're in the proper set of states to be here;
- // have all data, have a history handle, (validated or safe).
+ // Confirm we're in the proper set of states to be here; have all data, have a
+ // history handle, (validated or safe).
DCHECK_EQ(IN_PROGRESS_INTERNAL, state_);
DCHECK(!IsDangerous());
DCHECK(all_data_saved_);
@@ -1301,9 +1396,8 @@ void DownloadItemImpl::OnDownloadCompleting() {
// TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
if (is_save_package_download_) {
// Avoid doing anything on the file thread; there's nothing we control
- // there.
- // Strictly speaking, this skips giving the embedder a chance to open
- // the download. But on a save package download, there's no real
+ // there. Strictly speaking, this skips giving the embedder a chance to
+ // open the download. But on a save package download, there's no real
// concept of opening.
Completed();
return;
@@ -1316,10 +1410,15 @@ void DownloadItemImpl::OnDownloadCompleting() {
base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
weak_ptr_factory_.GetWeakPtr());
BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
+ BrowserThread::FILE,
+ FROM_HERE,
base::Bind(&DownloadFile::RenameAndAnnotate,
base::Unretained(download_file_.get()),
- GetTargetFilePath(), callback));
+ GetTargetFilePath(),
+ delegate_->GetApplicationClientIdForFileScanning(),
+ GetURL(),
+ GetReferrerUrl(),
+ callback));
}
void DownloadItemImpl::OnDownloadRenamedToFinalName(
@@ -1339,11 +1438,11 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
<< " " << DebugString(false);
if (DOWNLOAD_INTERRUPT_REASON_NONE != reason) {
- Interrupt(reason);
-
- // All file errors should have resulted in in file deletion above. On
- // resumption we will need to re-do filename determination.
- DCHECK(current_path_.empty());
+ // Failure to perform the final rename is considered fatal. TODO(asanka): It
+ // may not be, in which case we should figure out whether we can recover the
+ // state.
+ InterruptAndDiscardPartialState(reason);
+ UpdateObservers();
return;
}
@@ -1356,14 +1455,14 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
}
// Complete the download and release the DownloadFile.
- DCHECK(download_file_.get());
+ DCHECK(download_file_);
ReleaseDownloadFile(false);
// We're not completely done with the download item yet, but at this
// point we're committed to complete the download. Cancels (or Interrupts,
// though it's not clear how they could happen) after this point will be
// ignored.
- TransitionTo(COMPLETING_INTERNAL, DONT_UPDATE_OBSERVERS);
+ TransitionTo(COMPLETING_INTERNAL);
if (delegate_->ShouldOpenDownload(
this, base::Bind(&DownloadItemImpl::DelayedDownloadOpened,
@@ -1389,7 +1488,7 @@ void DownloadItemImpl::Completed() {
DCHECK(all_data_saved_);
end_time_ = base::Time::Now();
- TransitionTo(COMPLETE_INTERNAL, UPDATE_OBSERVERS);
+ TransitionTo(COMPLETE_INTERNAL);
RecordDownloadCompleted(start_tick_, received_bytes_);
if (auto_opened_) {
@@ -1404,32 +1503,28 @@ void DownloadItemImpl::Completed() {
OpenDownload();
auto_opened_ = true;
- UpdateObservers();
}
-}
-
-void DownloadItemImpl::OnResumeRequestStarted(
- DownloadItem* item,
- DownloadInterruptReason interrupt_reason) {
- // If |item| is not NULL, then Start() has been called already, and nothing
- // more needs to be done here.
- if (item) {
- DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
- DCHECK_EQ(static_cast<DownloadItem*>(this), item);
- return;
- }
- // Otherwise, the request failed without passing through
- // DownloadResourceHandler::OnResponseStarted.
- DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
- Interrupt(interrupt_reason);
+ UpdateObservers();
}
// **** End of Download progression cascade
-// An error occurred somewhere.
-void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
+void DownloadItemImpl::InterruptAndDiscardPartialState(
+ DownloadInterruptReason reason) {
+ InterruptWithPartialState(0, scoped_ptr<crypto::SecureHash>(), reason);
+}
+
+void DownloadItemImpl::InterruptWithPartialState(
+ int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state,
+ DownloadInterruptReason reason) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason);
+ DVLOG(20) << __FUNCTION__
+ << "() reason:" << DownloadInterruptReasonToString(reason)
+ << " bytes_so_far:" << bytes_so_far
+ << " hash_state:" << (hash_state ? "Valid" : "Invalid")
+ << " this=" << DebugString(true);
// Somewhat counter-intuitively, it is possible for us to receive an
// interrupt after we've already been interrupted. The generation of
@@ -1439,56 +1534,130 @@ void DownloadItemImpl::Interrupt(DownloadInterruptReason reason) {
// respectively), and since we choose not to keep state on the File thread,
// this is the place where the races collide. It's also possible for
// interrupts to race with cancels.
+ switch (state_) {
+ case CANCELLED_INTERNAL:
+ // If the download is already cancelled, then there's no point in
+ // transitioning out to interrupted.
+ case COMPLETING_INTERNAL:
+ case COMPLETE_INTERNAL:
+ // Already complete.
+ return;
- // Whatever happens, the first one to hit the UI thread wins.
- if (state_ != IN_PROGRESS_INTERNAL && state_ != RESUMING_INTERNAL)
- return;
+ case INITIAL_INTERNAL:
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ NOTREACHED();
+ return;
- last_reason_ = reason;
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ case IN_PROGRESS_INTERNAL:
+ case TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ // last_reason_ needs to be set for GetResumeMode() to work.
+ last_reason_ = reason;
+
+ if (download_file_) {
+ ResumeMode resume_mode = GetResumeMode();
+ ReleaseDownloadFile(resume_mode != RESUME_MODE_IMMEDIATE_CONTINUE &&
+ resume_mode != RESUME_MODE_USER_CONTINUE);
+ }
+ break;
- ResumeMode resume_mode = GetResumeMode();
+ case RESUMING_INTERNAL:
+ case INTERRUPTED_INTERNAL:
+ DCHECK(!download_file_);
+ // The first non-cancel interrupt reason wins in cases where multiple
+ // things go wrong.
+ if (reason != DOWNLOAD_INTERRUPT_REASON_USER_CANCELED &&
+ reason != DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN)
+ return;
- if (state_ == IN_PROGRESS_INTERNAL) {
- // Cancel (delete file) if:
- // 1) we're going to restart.
- // 2) Resumption isn't possible (download was cancelled or blocked due to
- // security restrictions).
- // 3) Resumption isn't enabled.
- // No point in leaving data around we aren't going to use.
- ReleaseDownloadFile(resume_mode == RESUME_MODE_IMMEDIATE_RESTART ||
- resume_mode == RESUME_MODE_USER_RESTART ||
- resume_mode == RESUME_MODE_INVALID ||
- !IsDownloadResumptionEnabled());
+ last_reason_ = reason;
+ if (!current_path_.empty()) {
+ // There is no download file and this is transitioning from INTERRUPTED
+ // to CANCELLED. The intermediate file is no longer usable, and should
+ // be deleted.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(base::IgnoreResult(&DeleteDownloadedFile),
+ current_path_));
+ current_path_.clear();
+ }
+ break;
+ }
- // Cancel the originating URL request.
- request_handle_->CancelRequest();
+ // Reset all data saved, as even if we did save all the data we're going to go
+ // through another round of downloading when we resume. There's a potential
+ // problem here in the abstract, as if we did download all the data and then
+ // run into a continuable error, on resumption we won't download any more
+ // data. However, a) there are currently no continuable errors that can occur
+ // after we download all the data, and b) if there were, that would probably
+ // simply result in a null range request, which would generate a
+ // DestinationCompleted() notification from the DownloadFile, which would
+ // behave properly with setting all_data_saved_ to false here.
+ all_data_saved_ = false;
+
+ if (current_path_.empty()) {
+ hash_state_.reset();
+ hash_.clear();
+ received_bytes_ = 0;
} else {
- DCHECK(!download_file_.get());
+ UpdateProgress(bytes_so_far, 0);
+ SetHashState(std::move(hash_state));
}
- // Reset all data saved, as even if we did save all the data we're going
- // to go through another round of downloading when we resume.
- // There's a potential problem here in the abstract, as if we did download
- // all the data and then run into a continuable error, on resumption we
- // won't download any more data. However, a) there are currently no
- // continuable errors that can occur after we download all the data, and
- // b) if there were, that would probably simply result in a null range
- // request, which would generate a DestinationCompleted() notification
- // from the DownloadFile, which would behave properly with setting
- // all_data_saved_ to false here.
- all_data_saved_ = false;
+ if (request_handle_)
+ request_handle_->CancelRequest();
+
+ if (reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED ||
+ reason == DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN) {
+ if (IsDangerous()) {
+ RecordDangerousDownloadDiscard(
+ reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
+ ? DOWNLOAD_DISCARD_DUE_TO_USER_ACTION
+ : DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN,
+ GetDangerType(), GetTargetFilePath());
+ }
+
+ RecordDownloadCount(CANCELLED_COUNT);
+ TransitionTo(CANCELLED_INTERNAL);
+ return;
+ }
- TransitionTo(INTERRUPTED_INTERNAL, DONT_UPDATE_OBSERVERS);
RecordDownloadInterrupted(reason, received_bytes_, total_bytes_);
if (!GetWebContents())
RecordDownloadCount(INTERRUPTED_WITHOUT_WEBCONTENTS);
+ TransitionTo(INTERRUPTED_INTERNAL);
AutoResumeIfValid();
- UpdateObservers();
+}
+
+void DownloadItemImpl::UpdateProgress(int64_t bytes_so_far,
+ int64_t bytes_per_sec) {
+ received_bytes_ = bytes_so_far;
+ bytes_per_sec_ = bytes_per_sec;
+
+ // If we've received more data than we were expecting (bad server info?),
+ // revert to 'unknown size mode'.
+ if (received_bytes_ > total_bytes_)
+ total_bytes_ = 0;
+}
+
+void DownloadItemImpl::SetHashState(scoped_ptr<crypto::SecureHash> hash_state) {
+ hash_state_ = std::move(hash_state);
+ if (!hash_state_) {
+ hash_.clear();
+ return;
+ }
+
+ scoped_ptr<crypto::SecureHash> clone_of_hash_state(hash_state_->Clone());
+ std::vector<char> hash_value(clone_of_hash_state->GetHashLength());
+ clone_of_hash_state->Finish(&hash_value.front(), hash_value.size());
+ hash_.assign(hash_value.begin(), hash_value.end());
}
void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DVLOG(20) << __FUNCTION__ << "() destroy_file:" << destroy_file;
if (destroy_file) {
BrowserThread::PostTask(
@@ -1514,6 +1683,11 @@ void DownloadItemImpl::ReleaseDownloadFile(bool destroy_file) {
bool DownloadItemImpl::IsDownloadReadyForCompletion(
const base::Closure& state_change_notification) {
+ // If the download hasn't progressed to the IN_PROGRESS state, then it's not
+ // ready for completion.
+ if (state_ != IN_PROGRESS_INTERNAL)
+ return false;
+
// If we don't have all the data, the download is not ready for
// completion.
if (!AllDataSaved())
@@ -1524,20 +1698,13 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion(
if (IsDangerous())
return false;
- // If the download isn't active (e.g. has been cancelled) it's not
- // ready for completion.
- if (state_ != IN_PROGRESS_INTERNAL)
- return false;
-
- // If the target filename hasn't been determined, then it's not ready for
- // completion. This is checked in ReadyForDownloadCompletionDone().
- if (GetTargetFilePath().empty())
- return false;
-
- // This is checked in NeedsRename(). Without this conditional,
- // browser_tests:DownloadTest.DownloadMimeType fails the DCHECK.
- if (target_path_.DirName() != current_path_.DirName())
- return false;
+ // Check for consistency before invoking delegate. Since there are no pending
+ // target determination calls and the download is in progress, both the target
+ // and current paths should be non-empty and they should point to the same
+ // directory.
+ DCHECK(!target_path_.empty());
+ DCHECK(!current_path_.empty());
+ DCHECK(target_path_.DirName() == current_path_.DirName());
// Give the delegate a chance to hold up a stop sign. It'll call
// use back through the passed callback if it does and that state changes.
@@ -1547,8 +1714,7 @@ bool DownloadItemImpl::IsDownloadReadyForCompletion(
return true;
}
-void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
- ShouldUpdateObservers notify_action) {
+void DownloadItemImpl::TransitionTo(DownloadInternalState new_state) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (state_ == new_state)
@@ -1557,49 +1723,89 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
DownloadInternalState old_state = state_;
state_ = new_state;
+ DCHECK(is_save_package_download_
+ ? IsValidSavePackageStateTransition(old_state, new_state)
+ : IsValidStateTransition(old_state, new_state))
+ << "Invalid state transition from:" << DebugDownloadStateString(old_state)
+ << " to:" << DebugDownloadStateString(new_state);
+
switch (state_) {
+ case INITIAL_INTERNAL:
+ NOTREACHED();
+ break;
+
+ case TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ break;
+
+ case IN_PROGRESS_INTERNAL:
+ DCHECK(!current_path_.empty()) << "Current output path must be known.";
+ DCHECK(!target_path_.empty()) << "Target path must be known.";
+ DCHECK(current_path_.DirName() == target_path_.DirName())
+ << "Current output directory must match target directory.";
+ DCHECK(download_file_) << "Output file must be owned by download item.";
+ DCHECK(request_handle_) << "Download source must be active.";
+ DCHECK(!is_paused_) << "At the time a download enters IN_PROGRESS state, "
+ "it must not be paused.";
+ break;
+
case COMPLETING_INTERNAL:
+ DCHECK(all_data_saved_) << "All data must be saved prior to completion.";
+ DCHECK(!download_file_)
+ << "Download file must be released prior to completion.";
+ DCHECK(!target_path_.empty()) << "Target path must be known.";
+ DCHECK(current_path_ == target_path_)
+ << "Current output path must match target path.";
+
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_COMPLETING,
base::Bind(&ItemCompletingNetLogCallback, received_bytes_, &hash_));
break;
+
case COMPLETE_INTERNAL:
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_FINISHED,
base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
break;
+
case INTERRUPTED_INTERNAL:
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_INTERRUPTED,
- base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
- received_bytes_, &hash_state_));
+ base::Bind(
+ &ItemInterruptedNetLogCallback, last_reason_, received_bytes_));
break;
- case IN_PROGRESS_INTERNAL:
- if (old_state == INTERRUPTED_INTERNAL) {
- bound_net_log_.AddEvent(
- net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
- base::Bind(&ItemResumingNetLogCallback,
- false, last_reason_, received_bytes_, &hash_state_));
- }
+
+ case RESUMING_INTERNAL:
+ bound_net_log_.AddEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_RESUMED,
+ base::Bind(&ItemResumingNetLogCallback,
+ false,
+ last_reason_,
+ received_bytes_));
break;
+
case CANCELLED_INTERNAL:
bound_net_log_.AddEvent(
net::NetLog::TYPE_DOWNLOAD_ITEM_CANCELED,
- base::Bind(&ItemCanceledNetLogCallback, received_bytes_,
- &hash_state_));
+ base::Bind(&ItemCanceledNetLogCallback, received_bytes_));
break;
- default:
+
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ NOTREACHED();
break;
}
- DVLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true)
- << " " << InternalToExternalState(old_state)
- << " " << InternalToExternalState(state_);
+ DVLOG(20) << " " << __FUNCTION__ << "()"
+ << " from:" << DebugDownloadStateString(old_state)
+ << " to:" << DebugDownloadStateString(state_)
+ << " this = " << DebugString(true);
+ bool is_done =
+ (state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
+ state_ == RESUMING_INTERNAL || state_ == CANCELLED_INTERNAL);
+ bool was_done =
+ (old_state == COMPLETE_INTERNAL || old_state == INTERRUPTED_INTERNAL ||
+ old_state == RESUMING_INTERNAL || old_state == CANCELLED_INTERNAL);
- bool is_done = (state_ != IN_PROGRESS_INTERNAL &&
- state_ != COMPLETING_INTERNAL);
- bool was_done = (old_state != IN_PROGRESS_INTERNAL &&
- old_state != COMPLETING_INTERNAL);
// Termination
if (is_done && !was_done)
bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_ITEM_ACTIVE);
@@ -1612,9 +1818,6 @@ void DownloadItemImpl::TransitionTo(DownloadInternalState new_state,
this, SRC_ACTIVE_DOWNLOAD,
&file_name));
}
-
- if (notify_action == UPDATE_OBSERVERS)
- UpdateObservers();
}
void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
@@ -1676,45 +1879,52 @@ void DownloadItemImpl::ResumeInterruptedDownload() {
if (state_ != INTERRUPTED_INTERNAL)
return;
+ // We are starting a new request. Shake off all pending operations.
+ DCHECK(!download_file_);
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
// Reset the appropriate state if restarting.
ResumeMode mode = GetResumeMode();
if (mode == RESUME_MODE_IMMEDIATE_RESTART ||
mode == RESUME_MODE_USER_RESTART) {
received_bytes_ = 0;
- hash_state_ = "";
- last_modified_time_ = "";
- etag_ = "";
- }
-
- scoped_ptr<DownloadUrlParameters> download_params;
- if (GetWebContents()) {
- download_params =
- DownloadUrlParameters::FromWebContents(GetWebContents(), GetURL());
- } else {
- download_params = make_scoped_ptr(new DownloadUrlParameters(
- GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext()));
+ last_modified_time_.clear();
+ etag_.clear();
+ hash_.clear();
+ hash_state_.reset();
}
+ // Avoid using the WebContents even if it's still around. Resumption requests
+ // are consistently routed through the no-renderer code paths so that the
+ // request will not be dropped if the WebContents (and by extension, the
+ // associated renderer) goes away before a response is received.
+ scoped_ptr<DownloadUrlParameters> download_params(new DownloadUrlParameters(
+ GetURL(), -1, -1, -1, GetBrowserContext()->GetResourceContext()));
download_params->set_file_path(GetFullPath());
download_params->set_offset(GetReceivedBytes());
- download_params->set_hash_state(GetHashState());
download_params->set_last_modified(GetLastModifiedTime());
download_params->set_etag(GetETag());
- download_params->set_callback(
- base::Bind(&DownloadItemImpl::OnResumeRequestStarted,
- weak_ptr_factory_.GetWeakPtr()));
+ download_params->set_hash_of_partial_file(hash_);
+ download_params->set_hash_state(std::move(hash_state_));
+ TransitionTo(RESUMING_INTERNAL);
delegate_->ResumeInterruptedDownload(std::move(download_params), GetId());
// Just in case we were interrupted while paused.
is_paused_ = false;
-
- TransitionTo(RESUMING_INTERNAL, DONT_UPDATE_OBSERVERS);
}
// static
DownloadItem::DownloadState DownloadItemImpl::InternalToExternalState(
DownloadInternalState internal_state) {
switch (internal_state) {
+ case INITIAL_INTERNAL:
+ case TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ // TODO(asanka): Introduce an externally visible state to distinguish
+ // between the above states and IN_PROGRESS_INTERNAL. The latter (the
+ // state where the download is active and has a known target) is the state
+ // that most external users are interested in.
case IN_PROGRESS_INTERNAL:
return IN_PROGRESS;
case COMPLETING_INTERNAL:
@@ -1753,9 +1963,96 @@ DownloadItemImpl::ExternalToInternalState(
return MAX_DOWNLOAD_INTERNAL_STATE;
}
+// static
+bool DownloadItemImpl::IsValidSavePackageStateTransition(
+ DownloadInternalState from,
+ DownloadInternalState to) {
+#if DCHECK_IS_ON()
+ switch (from) {
+ case INITIAL_INTERNAL:
+ case TARGET_PENDING_INTERNAL:
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ case TARGET_RESOLVED_INTERNAL:
+ case COMPLETING_INTERNAL:
+ case COMPLETE_INTERNAL:
+ case INTERRUPTED_INTERNAL:
+ case RESUMING_INTERNAL:
+ case CANCELLED_INTERNAL:
+ return false;
+
+ case IN_PROGRESS_INTERNAL:
+ return to == CANCELLED_INTERNAL || to == COMPLETE_INTERNAL;
+
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ NOTREACHED();
+ }
+ return false;
+#else
+ return true;
+#endif
+}
+
+// static
+bool DownloadItemImpl::IsValidStateTransition(DownloadInternalState from,
+ DownloadInternalState to) {
+#if DCHECK_IS_ON()
+ switch (from) {
+ case INITIAL_INTERNAL:
+ return to == TARGET_PENDING_INTERNAL ||
+ to == INTERRUPTED_TARGET_PENDING_INTERNAL;
+
+ case TARGET_PENDING_INTERNAL:
+ return to == INTERRUPTED_TARGET_PENDING_INTERNAL ||
+ to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
+
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ return to == INTERRUPTED_INTERNAL || to == CANCELLED_INTERNAL;
+
+ case TARGET_RESOLVED_INTERNAL:
+ return to == IN_PROGRESS_INTERNAL || to == INTERRUPTED_INTERNAL ||
+ to == CANCELLED_INTERNAL;
+
+ case IN_PROGRESS_INTERNAL:
+ return to == COMPLETING_INTERNAL || to == CANCELLED_INTERNAL ||
+ to == INTERRUPTED_INTERNAL;
+
+ case COMPLETING_INTERNAL:
+ return to == COMPLETE_INTERNAL;
+
+ case COMPLETE_INTERNAL:
+ return false;
+
+ case INTERRUPTED_INTERNAL:
+ return to == RESUMING_INTERNAL || to == CANCELLED_INTERNAL;
+
+ case RESUMING_INTERNAL:
+ return to == TARGET_PENDING_INTERNAL ||
+ to == INTERRUPTED_TARGET_PENDING_INTERNAL ||
+ to == TARGET_RESOLVED_INTERNAL || to == CANCELLED_INTERNAL;
+
+ case CANCELLED_INTERNAL:
+ return false;
+
+ case MAX_DOWNLOAD_INTERNAL_STATE:
+ NOTREACHED();
+ }
+ return false;
+#else
+ return true;
+#endif // DCHECK_IS_ON()
+}
+
const char* DownloadItemImpl::DebugDownloadStateString(
DownloadInternalState state) {
switch (state) {
+ case INITIAL_INTERNAL:
+ return "INITIAL";
+ case TARGET_PENDING_INTERNAL:
+ return "TARGET_PENDING";
+ case INTERRUPTED_TARGET_PENDING_INTERNAL:
+ return "INTERRUPTED_TARGET_PENDING";
+ case TARGET_RESOLVED_INTERNAL:
+ return "TARGET_RESOLVED";
case IN_PROGRESS_INTERNAL:
return "IN_PROGRESS";
case COMPLETING_INTERNAL:
diff --git a/chromium/content/browser/download/download_item_impl.h b/chromium/content/browser/download/download_item_impl.h
index c527861287f..a6afdd86779 100644
--- a/chromium/content/browser/download/download_item_impl.h
+++ b/chromium/content/browser/download/download_item_impl.h
@@ -16,10 +16,10 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
+#include "content/browser/download/download_destination_observer.h"
#include "content/browser/download/download_net_log_parameters.h"
#include "content/browser/download/download_request_handle.h"
#include "content/common/content_export.h"
-#include "content/public/browser/download_destination_observer.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_item.h"
#include "net/log/net_log.h"
@@ -52,6 +52,7 @@ class CONTENT_EXPORT DownloadItemImpl
// Constructing from persistent store:
// |bound_net_log| is constructed externally for our use.
DownloadItemImpl(DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -65,6 +66,7 @@ class CONTENT_EXPORT DownloadItemImpl
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
@@ -73,6 +75,8 @@ class CONTENT_EXPORT DownloadItemImpl
// Constructing for a regular download.
// |bound_net_log| is constructed externally for our use.
+ // TODO(asanka): Get rid of the DownloadCreateInfo parameter since active
+ // downloads end up at Start() immediately after creation.
DownloadItemImpl(DownloadItemImplDelegate* delegate,
uint32_t id,
const DownloadCreateInfo& info,
@@ -103,6 +107,7 @@ class CONTENT_EXPORT DownloadItemImpl
void OpenDownload() override;
void ShowDownloadInShell() override;
uint32_t GetId() const override;
+ const std::string& GetGuid() const override;
DownloadState GetState() const override;
DownloadInterruptReason GetLastReason() const override;
bool IsPaused() const override;
@@ -131,7 +136,6 @@ class CONTENT_EXPORT DownloadItemImpl
base::FilePath GetFileNameToReportUser() const override;
TargetDisposition GetTargetDisposition() const override;
const std::string& GetHash() const override;
- const std::string& GetHashState() const override;
bool GetFileExternallyRemoved() const override;
void DeleteFile(const base::Callback<void(bool)>& callback) override;
bool IsDangerous() const override;
@@ -167,18 +171,18 @@ class CONTENT_EXPORT DownloadItemImpl
// INTERRUPTED state.
virtual ResumeMode GetResumeMode() const;
- // Notify the download item that new origin information is available due to a
- // resumption request receiving a response.
- virtual void MergeOriginInfoOnResume(
- const DownloadCreateInfo& new_create_info);
-
// State transition operations on regular downloads --------------------------
// Start the download.
// |download_file| is the associated file on the storage medium.
// |req_handle| is the new request handle associated with the download.
+ // |new_create_info| is a DownloadCreateInfo containing the new response
+ // parameters. It may be different from the DownloadCreateInfo used to create
+ // the DownloadItem if Start() is being called in response for a download
+ // resumption request.
virtual void Start(scoped_ptr<DownloadFile> download_file,
- scoped_ptr<DownloadRequestHandleInterface> req_handle);
+ scoped_ptr<DownloadRequestHandleInterface> req_handle,
+ const DownloadCreateInfo& new_create_info);
// Needed because of intertwining with DownloadManagerImpl -------------------
@@ -203,94 +207,171 @@ class CONTENT_EXPORT DownloadItemImpl
// Called by SavePackage to set the total number of bytes on the item.
virtual void SetTotalBytes(int64_t total_bytes);
- virtual void OnAllDataSaved(const std::string& final_hash);
+ virtual void OnAllDataSaved(int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> hash_state);
// Called by SavePackage to display progress when the DownloadItem
// should be considered complete.
virtual void MarkAsComplete();
// DownloadDestinationObserver
- void DestinationUpdate(int64_t bytes_so_far,
- int64_t bytes_per_sec,
- const std::string& hash_state) override;
- void DestinationError(DownloadInterruptReason reason) override;
- void DestinationCompleted(const std::string& final_hash) override;
+ void DestinationUpdate(int64_t bytes_so_far, int64_t bytes_per_sec) override;
+ void DestinationError(DownloadInterruptReason reason,
+ int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state) override;
+ void DestinationCompleted(int64_t total_bytes,
+ scoped_ptr<crypto::SecureHash> hash_state) override;
private:
- // Fine grained states of a download. Note that active downloads are created
- // in IN_PROGRESS_INTERNAL state. However, downloads creates via history can
- // be created in COMPLETE_INTERNAL, CANCELLED_INTERNAL and
- // INTERRUPTED_INTERNAL.
-
+ // Fine grained states of a download.
+ //
+ // New downloads can be created in the following states:
+ //
+ // INITIAL_INTERNAL: All active new downloads.
+ //
+ // COMPLETE_INTERNAL: Downloads restored from persisted state.
+ // CANCELLED_INTERNAL: - do -
+ // INTERRUPTED_INTERNAL: - do -
+ //
+ // IN_PROGRESS_INTERNAL: SavePackage downloads.
+ //
+ // On debug builds, state transitions can be verified via
+ // IsValidStateTransition() and IsValidSavePackageStateTransition(). Allowed
+ // state transitions are described below, both for normal downloads and
+ // SavePackage downloads.
enum DownloadInternalState {
- // Includes both before and after file name determination, and paused
- // downloads.
- // TODO(rdsmith): Put in state variable for file name determination.
- // Transitions from:
- // <Initial creation> Active downloads are created in this state.
- // RESUMING_INTERNAL
- // Transitions to:
- // COMPLETING_INTERNAL On final rename completion.
- // CANCELLED_INTERNAL On cancel.
- // INTERRUPTED_INTERNAL On interrupt.
- // COMPLETE_INTERNAL On SavePackage download completion.
+ // Initial state. Regular downloads are created in this state until the
+ // Start() call is received.
+ //
+ // Transitions to (regular):
+ // TARGET_PENDING_INTERNAL: After a successful Start() call.
+ // INTERRUPTED_TARGET_PENDING_INTERNAL: After a failed Start() call.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
+ INITIAL_INTERNAL,
+
+ // Embedder is in the process of determining the target of the download.
+ // Since the embedder is sensitive to state transitions during this time,
+ // any DestinationError/DestinationCompleted events are deferred until
+ // TARGET_RESOLVED_INTERNAL.
+ //
+ // Transitions to (regular):
+ // TARGET_RESOLVED_INTERNAL: Once the embedder invokes the callback.
+ // INTERRUPTED_TARGET_PENDING_INTERNAL: An error occurred prior to target
+ // determination.
+ // CANCELLED_INTERNAL: Cancelled.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
+ TARGET_PENDING_INTERNAL,
+
+ // Embedder is in the process of determining the target of the download, and
+ // the download is in an interrupted state. The interrupted state is not
+ // exposed to the emedder until target determination is complete.
+ //
+ // Transitions to (regular):
+ // INTERRUPTED_INTERNAL: Once the target is determined, the download
+ // is marked as interrupted.
+ // CANCELLED_INTERNAL: Cancelled.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
+ INTERRUPTED_TARGET_PENDING_INTERNAL,
+
+ // Embedder has completed target determination. It is now safe to resolve
+ // the download target as well as process deferred DestinationError events.
+ // This state is differs from TARGET_PENDING_INTERNAL due to it being
+ // allowed to transition to INTERRUPTED_INTERNAL, and it's different from
+ // IN_PROGRESS_INTERNAL in that entering this state doesn't require having
+ // a valid target. This state is transient (i.e. DownloadItemImpl will
+ // transition out of it before yielding execution). It's only purpose in
+ // life is to ensure the integrity of state transitions.
+ //
+ // Transitions to (regular):
+ // IN_PROGRESS_INTERNAL: Target successfully determined. The incoming
+ // data stream can now be written to the target.
+ // INTERRUPTED_INTERNAL: Either the target determination or one of the
+ // deferred signals indicated that the download
+ // should be interrupted.
+ // CANCELLED_INTERNAL: User cancelled the download or there was a
+ // deferred Cancel() call.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
+ TARGET_RESOLVED_INTERNAL,
+
+ // Download target is known and the data can be transferred from our source
+ // to our sink.
+ //
+ // Transitions to (regular):
+ // COMPLETING_INTERNAL: On final rename completion.
+ // CANCELLED_INTERNAL: On cancel.
+ // INTERRUPTED_INTERNAL: On interrupt.
+ //
+ // Transitions to (SavePackage):
+ // COMPLETE_INTERNAL: On completion.
+ // CANCELLED_INTERNAL: On cancel.
IN_PROGRESS_INTERNAL,
// Between commit point (dispatch of download file release) and completed.
// Embedder may be opening the file in this state.
- // Transitions from:
- // IN_PROGRESS_INTERNAL
- // Transitions to:
- // COMPLETE_INTERNAL On successful completion.
+ //
+ // Transitions to (regular):
+ // COMPLETE_INTERNAL: On successful completion.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
COMPLETING_INTERNAL,
// After embedder has had a chance to auto-open. User may now open
// or auto-open based on extension.
- // Transitions from:
- // COMPLETING_INTERNAL
- // IN_PROGRESS_INTERNAL SavePackage only.
- // <Initial creation> Completed persisted downloads.
- // Transitions to:
- // <none> Terminal state.
+ //
+ // Transitions to (regular):
+ // <none> Terminal state.
+ //
+ // Transitions to (SavePackage):
+ // <none> Terminal state.
COMPLETE_INTERNAL,
- // User has cancelled the download.
- // Transitions from:
- // IN_PROGRESS_INTERNAL
- // INTERRUPTED_INTERNAL
- // RESUMING_INTERNAL
- // <Initial creation> Canceleld persisted downloads.
- // Transitions to:
- // <none> Terminal state.
- CANCELLED_INTERNAL,
-
// An error has interrupted the download.
- // Transitions from:
- // IN_PROGRESS_INTERNAL
- // RESUMING_INTERNAL
- // <Initial creation> Interrupted persisted downloads.
- // Transitions to:
- // RESUMING_INTERNAL On resumption.
+ //
+ // Transitions to (regular):
+ // RESUMING_INTERNAL: On resumption.
+ // CANCELLED_INTERNAL: On cancel.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
INTERRUPTED_INTERNAL,
// A request to resume this interrupted download is in progress.
- // Transitions from:
- // INTERRUPTED_INTERNAL
- // Transitions to:
- // IN_PROGRESS_INTERNAL Once a server response is received from a
- // resumption.
- // INTERRUPTED_INTERNAL If the resumption request fails.
- // CANCELLED_INTERNAL On cancel.
+ //
+ // Transitions to (regular):
+ // TARGET_PENDING_INTERNAL: Once a server response is received from a
+ // resumption.
+ // INTERRUPTED_TARGET_PENDING_INTERNAL: A server response was received,
+ // but it indicated an error, and the download
+ // needs to go through target determination.
+ // TARGET_RESOLVED_INTERNAL: A resumption attempt received an error
+ // but it was not necessary to go through target
+ // determination.
+ // CANCELLED_INTERNAL: On cancel.
+ //
+ // Transitions to (SavePackage):
+ // <n/a> SavePackage downloads never reach this state.
RESUMING_INTERNAL,
- MAX_DOWNLOAD_INTERNAL_STATE,
- };
+ // User has cancelled the download.
+ // TODO(asanka): Merge interrupted and cancelled states.
+ //
+ // Transitions to (regular):
+ // <none> Terminal state.
+ //
+ // Transitions to (SavePackage):
+ // <none> Terminal state.
+ CANCELLED_INTERNAL,
- // Used with TransitionTo() to indicate whether or not to call
- // UpdateObservers() after the state transition.
- enum ShouldUpdateObservers {
- UPDATE_OBSERVERS,
- DONT_UPDATE_OBSERVERS
+ MAX_DOWNLOAD_INTERNAL_STATE,
};
// Normal progression of a download ------------------------------------------
@@ -305,6 +386,13 @@ class CONTENT_EXPORT DownloadItemImpl
// this is.
void Init(bool active, DownloadType download_type);
+ // Callback from file thread when we initialize the DownloadFile.
+ void OnDownloadFileInitialized(DownloadInterruptReason result);
+
+ // Called to determine the target path. Will cause OnDownloadTargetDetermined
+ // to be called when the target information is available.
+ void DetermineDownloadTarget();
+
// Called when the target path has been determined. |target_path| is the
// suggested target path. |disposition| indicates how the target path should
// be used (see TargetDisposition). |danger_type| is the danger level of
@@ -316,9 +404,6 @@ class CONTENT_EXPORT DownloadItemImpl
DownloadDangerType danger_type,
const base::FilePath& intermediate_path);
- // Callback from file thread when we initialize the DownloadFile.
- void OnDownloadFileInitialized(DownloadInterruptReason result);
-
void OnDownloadRenamedToIntermediateName(
DownloadInterruptReason reason, const base::FilePath& full_path);
@@ -339,18 +424,29 @@ class CONTENT_EXPORT DownloadItemImpl
// the download has been opened.
void DelayedDownloadOpened(bool auto_opened);
- // Called when the entire download operation (including renaming etc)
+ // Called when the entire download operation (including renaming etc.)
// is completed.
void Completed();
- // Callback invoked when the URLRequest for a download resumption has started.
- void OnResumeRequestStarted(DownloadItem* item,
- DownloadInterruptReason interrupt_reason);
-
// Helper routines -----------------------------------------------------------
- // Indicate that an error has occurred on the download.
- void Interrupt(DownloadInterruptReason reason);
+ // Indicate that an error has occurred on the download. Discards partial
+ // state. The interrupted download will not be considered continuable, but may
+ // be restarted.
+ void InterruptAndDiscardPartialState(DownloadInterruptReason reason);
+
+ // Indiates that an error has occurred on the download. The |bytes_so_far| and
+ // |hash_state| should correspond to the state of the DownloadFile. If the
+ // interrupt reason allows, this partial state may be allowed to continue the
+ // interrupted download upon resumption.
+ void InterruptWithPartialState(int64_t bytes_so_far,
+ scoped_ptr<crypto::SecureHash> hash_state,
+ DownloadInterruptReason reason);
+
+ void UpdateProgress(int64_t bytes_so_far, int64_t bytes_per_sec);
+
+ // Set |hash_| and |hash_state_| based on |hash_state|.
+ void SetHashState(scoped_ptr<crypto::SecureHash> hash_state);
// Destroy the DownloadFile object. If |destroy_file| is true, the file is
// destroyed with it. Otherwise, DownloadFile::Detach() is called before
@@ -366,10 +462,9 @@ class CONTENT_EXPORT DownloadItemImpl
// Call to transition state; all state transitions should go through this.
// |notify_action| specifies whether or not to call UpdateObservers() after
// the state transition.
- void TransitionTo(DownloadInternalState new_state,
- ShouldUpdateObservers notify_action);
+ void TransitionTo(DownloadInternalState new_state);
- // Set the |danger_type_| and invoke obserers if necessary.
+ // Set the |danger_type_| and invoke observers if necessary.
void SetDangerType(DownloadDangerType danger_type);
void SetFullPath(const base::FilePath& new_path);
@@ -378,6 +473,11 @@ class CONTENT_EXPORT DownloadItemImpl
void ResumeInterruptedDownload();
+ // Update origin information based on the response to a download resumption
+ // request. Should only be called if the resumption request was successful.
+ virtual void UpdateValidatorsOnResumption(
+ const DownloadCreateInfo& new_create_info);
+
static DownloadState InternalToExternalState(
DownloadInternalState internal_state);
static DownloadInternalState ExternalToInternalState(
@@ -386,34 +486,34 @@ class CONTENT_EXPORT DownloadItemImpl
// Debugging routines --------------------------------------------------------
static const char* DebugDownloadStateString(DownloadInternalState state);
static const char* DebugResumeModeString(ResumeMode mode);
+ static bool IsValidSavePackageStateTransition(DownloadInternalState from,
+ DownloadInternalState to);
+ static bool IsValidStateTransition(DownloadInternalState from,
+ DownloadInternalState to);
// Will be false for save package downloads retrieved from the history.
// TODO(rdsmith): Replace with a generalized enum for "download source".
- const bool is_save_package_download_;
+ const bool is_save_package_download_ = false;
// The handle to the request information. Used for operations outside the
// download system.
scoped_ptr<DownloadRequestHandleInterface> request_handle_;
- uint32_t download_id_;
+ std::string guid_;
+
+ uint32_t download_id_ = kInvalidId;
// Display name for the download. If this is empty, then the display name is
// considered to be |target_path_.BaseName()|.
base::FilePath display_name_;
- // Full path to the downloaded or downloading file. This is the path to the
- // physical file, if one exists. The final target path is specified by
- // |target_path_|. |current_path_| can be empty if the in-progress path hasn't
- // been determined.
- base::FilePath current_path_;
-
// Target path of an in-progress download. We may be downloading to a
// temporary or intermediate file (specified by |current_path_|. Once the
// download completes, we will rename the file to |target_path_|.
base::FilePath target_path_;
// Whether the target should be overwritten, uniquified or prompted for.
- TargetDisposition target_disposition_;
+ TargetDisposition target_disposition_ = TARGET_DISPOSITION_OVERWRITE;
// The chain of redirects that leading up to and including the final URL.
std::vector<GURL> url_chain_;
@@ -437,10 +537,10 @@ class CONTENT_EXPORT DownloadItemImpl
base::FilePath forced_file_path_;
// Page transition that triggerred the download.
- ui::PageTransition transition_type_;
+ ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
// Whether the download was triggered with a user gesture.
- bool has_user_gesture_;
+ bool has_user_gesture_ = false;
// Information from the request.
// Content-disposition field from the header.
@@ -459,40 +559,19 @@ class CONTENT_EXPORT DownloadItemImpl
std::string remote_address_;
// Total bytes expected.
- int64_t total_bytes_;
-
- // Current received bytes.
- int64_t received_bytes_;
-
- // Current speed. Calculated by the DownloadFile.
- int64_t bytes_per_sec_;
-
- // Sha256 hash of the content. This might be empty either because
- // the download isn't done yet or because the hash isn't needed
- // (ChromeDownloadManagerDelegate::GenerateFileHash() returned false).
- std::string hash_;
-
- // A blob containing the state of the hash algorithm. Only valid while the
- // download is in progress.
- std::string hash_state_;
-
- // Server's time stamp for the file.
- std::string last_modified_time_;
-
- // Server's ETAG for the file.
- std::string etag_;
+ int64_t total_bytes_ = 0;
// Last reason.
- DownloadInterruptReason last_reason_;
+ DownloadInterruptReason last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
// Start time for recording statistics.
base::TimeTicks start_tick_;
// The current state of this download.
- DownloadInternalState state_;
+ DownloadInternalState state_ = INITIAL_INTERNAL;
// Current danger type for the download.
- DownloadDangerType danger_type_;
+ DownloadDangerType danger_type_ = DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
// The views of this item in the download shelf and download contents.
base::ObserverList<Observer> observers_;
@@ -504,44 +583,40 @@ class CONTENT_EXPORT DownloadItemImpl
base::Time end_time_;
// Our delegate.
- DownloadItemImplDelegate* delegate_;
+ DownloadItemImplDelegate* delegate_ = nullptr;
// In progress downloads may be paused by the user, we note it here.
- bool is_paused_;
-
- // The number of times this download has been resumed automatically.
- int auto_resume_count_;
+ bool is_paused_ = false;
// A flag for indicating if the download should be opened at completion.
- bool open_when_complete_;
+ bool open_when_complete_ = false;
// A flag for indicating if the downloaded file is externally removed.
- bool file_externally_removed_;
+ bool file_externally_removed_ = false;
// True if the download was auto-opened. We set this rather than using
// an observer as it's frequently possible for the download to be auto opened
// before the observer is added.
- bool auto_opened_;
+ bool auto_opened_ = false;
// True if the item was downloaded temporarily.
- bool is_temporary_;
-
- // True if we've saved all the data for the download.
- bool all_data_saved_;
-
- // Error return from DestinationError. Stored separately from
- // last_reason_ so that we can avoid handling destination errors until
- // after file name determination has occurred.
- DownloadInterruptReason destination_error_;
+ bool is_temporary_ = false;
// Did the user open the item either directly or indirectly (such as by
// setting always open files of this type)? The shelf also sets this field
// when the user closes the shelf before the item has been opened but should
// be treated as though the user opened it.
- bool opened_;
+ bool opened_ = false;
// Did the delegate delay calling Complete on this download?
- bool delegate_delayed_complete_;
+ bool delegate_delayed_complete_ = false;
+
+ // Error return from DestinationError. Stored separately from
+ // last_reason_ so that we can avoid handling destination errors until
+ // after file name determination has occurred.
+ DownloadInterruptReason destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
+
+ // The following fields describe the current state of the download file.
// DownloadFile associated with this download. Note that this
// pointer may only be used or destroyed on the FILE thread.
@@ -549,6 +624,47 @@ class CONTENT_EXPORT DownloadItemImpl
// the IN_PROGRESS state.
scoped_ptr<DownloadFile> download_file_;
+ // Full path to the downloaded or downloading file. This is the path to the
+ // physical file, if one exists. The final target path is specified by
+ // |target_path_|. |current_path_| can be empty if the in-progress path hasn't
+ // been determined.
+ base::FilePath current_path_;
+
+ // Current received bytes.
+ int64_t received_bytes_ = 0;
+
+ // Current speed. Calculated by the DownloadFile.
+ int64_t bytes_per_sec_ = 0;
+
+ // True if we've saved all the data for the download. If true, then the file
+ // at |current_path_| contains |received_bytes_|, which constitute the
+ // entirety of what we expect to save there. A digest of its contents can be
+ // found at |hash_|.
+ bool all_data_saved_ = false;
+
+ // The number of times this download has been resumed automatically. Will be
+ // reset to 0 if a resumption is performed in response to a Resume() call.
+ int auto_resume_count_ = 0;
+
+ // SHA256 hash of the possibly partial content. The hash is updated each time
+ // the download is interrupted, and when the all the data has been
+ // transferred. |hash_| contains the raw binary hash and is not hex encoded.
+ //
+ // While the download is in progress, and while resuming, |hash_| will be
+ // empty.
+ std::string hash_;
+
+ // In the event of an interruption, the DownloadDestinationObserver interface
+ // exposes the partial hash state. This state can be held by the download item
+ // in case it's needed for resumption.
+ scoped_ptr<crypto::SecureHash> hash_state_;
+
+ // Contents of the Last-Modified header for the most recent server response.
+ std::string last_modified_time_;
+
+ // Server's ETAG for the file.
+ std::string etag_;
+
// Net log to use for this download.
const net::BoundNetLog bound_net_log_;
diff --git a/chromium/content/browser/download/download_item_impl_delegate.cc b/chromium/content/browser/download/download_item_impl_delegate.cc
index c1ed48cd124..be7432599e1 100644
--- a/chromium/content/browser/download/download_item_impl_delegate.cc
+++ b/chromium/content/browser/download/download_item_impl_delegate.cc
@@ -56,6 +56,11 @@ bool DownloadItemImplDelegate::ShouldOpenFileBasedOnExtension(
void DownloadItemImplDelegate::CheckForFileRemoval(
DownloadItemImpl* download_item) {}
+std::string DownloadItemImplDelegate::GetApplicationClientIdForFileScanning()
+ const {
+ return std::string();
+}
+
void DownloadItemImplDelegate::ResumeInterruptedDownload(
scoped_ptr<DownloadUrlParameters> params,
uint32_t id) {}
diff --git a/chromium/content/browser/download/download_item_impl_delegate.h b/chromium/content/browser/download/download_item_impl_delegate.h
index 1925963f0a2..8dd9d8cb740 100644
--- a/chromium/content/browser/download/download_item_impl_delegate.h
+++ b/chromium/content/browser/download/download_item_impl_delegate.h
@@ -69,6 +69,11 @@ class CONTENT_EXPORT DownloadItemImplDelegate {
// to OnDownloadedFileRemoved().
virtual void CheckForFileRemoval(DownloadItemImpl* download_item);
+ // Return a GUID string used for identifying the application to the system AV
+ // function for scanning downloaded files. If an empty or invalid GUID string
+ // is returned, no client identification will be given to the AV function.
+ virtual std::string GetApplicationClientIdForFileScanning() const;
+
// Called when an interrupted download is resumed.
virtual void ResumeInterruptedDownload(
scoped_ptr<content::DownloadUrlParameters> params,
diff --git a/chromium/content/browser/download/download_item_impl_unittest.cc b/chromium/content/browser/download/download_item_impl_unittest.cc
index 0afad1bfca2..45c822cfc55 100644
--- a/chromium/content/browser/download/download_item_impl_unittest.cc
+++ b/chromium/content/browser/download/download_item_impl_unittest.cc
@@ -5,39 +5,54 @@
#include "content/browser/download/download_item_impl.h"
#include <stdint.h>
+
+#include <iterator>
+#include <queue>
#include <utility>
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/threading/thread.h"
#include "content/browser/byte_stream.h"
#include "content/browser/download/download_create_info.h"
+#include "content/browser/download/download_destination_observer.h"
#include "content/browser/download/download_file_factory.h"
#include "content/browser/download/download_item_impl_delegate.h"
#include "content/browser/download/download_request_handle.h"
#include "content/browser/download/mock_download_file.h"
-#include "content/public/browser/download_destination_observer.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_url_parameters.h"
#include "content/public/common/content_features.h"
#include "content/public/test/mock_download_item.h"
+#include "content/public/test/mock_download_item.h"
#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/web_contents_tester.h"
+#include "crypto/secure_hash.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::_;
+using ::testing::DoAll;
using ::testing::NiceMock;
using ::testing::Property;
using ::testing::Return;
+using ::testing::ReturnRefOfCopy;
using ::testing::SaveArg;
using ::testing::StrictMock;
+using ::testing::WithArg;
+using ::testing::_;
const int kDownloadChunkSize = 1000;
const int kDownloadSpeed = 1000;
-const base::FilePath::CharType kDummyPath[] = FILE_PATH_LITERAL("/testpath");
+const base::FilePath::CharType kDummyTargetPath[] =
+ FILE_PATH_LITERAL("/testpath");
+const base::FilePath::CharType kDummyIntermediatePath[] =
+ FILE_PATH_LITERAL("/testpathx");
namespace content {
@@ -66,7 +81,6 @@ class MockDelegate : public DownloadItemImplDelegate {
void(DownloadUrlParameters* params, uint32_t id));
MOCK_CONST_METHOD0(GetBrowserContext, BrowserContext*());
- MOCK_METHOD1(UpdatePersistence, void(DownloadItemImpl*));
MOCK_METHOD1(DownloadOpened, void(DownloadItemImpl*));
MOCK_METHOD1(DownloadRemoved, void(DownloadItemImpl*));
MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItemImpl*));
@@ -128,8 +142,8 @@ class TestDownloadItemObserver : public DownloadItem::Observer {
private:
void OnDownloadRemoved(DownloadItem* download) override {
- DVLOG(20) << " " << __FUNCTION__
- << " download = " << download->DebugString(false);
+ SCOPED_TRACE(::testing::Message() << " " << __FUNCTION__ << " download = "
+ << download->DebugString(false));
removed_ = true;
}
@@ -159,7 +173,7 @@ class TestDownloadItemObserver : public DownloadItem::Observer {
<< " download = " << download->DebugString(false);
destroyed_ = true;
item_->RemoveObserver(this);
- item_ = NULL;
+ item_ = nullptr;
}
DownloadItem* item_;
@@ -173,54 +187,82 @@ class TestDownloadItemObserver : public DownloadItem::Observer {
// Schedules a task to invoke the RenameCompletionCallback with |new_path| on
// the UI thread. Should only be used as the action for
-// MockDownloadFile::Rename as follows:
-// EXPECT_CALL(download_file, Rename*(_,_))
-// .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
-// new_path));
-ACTION_P2(ScheduleRenameCallback, interrupt_reason, new_path) {
+// MockDownloadFile::RenameAndUniquify as follows:
+// EXPECT_CALL(download_file, RenameAndUniquify(_,_))
+// .WillOnce(ScheduleRenameAndUniquifyCallback(
+// DOWNLOAD_INTERRUPT_REASON_NONE, new_path));
+ACTION_P2(ScheduleRenameAndUniquifyCallback, interrupt_reason, new_path) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(arg1, interrupt_reason, new_path));
}
+// Schedules a task to invoke the RenameCompletionCallback with |new_path| on
+// the UI thread. Should only be used as the action for
+// MockDownloadFile::RenameAndAnnotate as follows:
+// EXPECT_CALL(download_file, RenameAndAnnotate(_,_,_,_,_))
+// .WillOnce(ScheduleRenameAndAnnotateCallback(
+// DOWNLOAD_INTERRUPT_REASON_NONE, new_path));
+ACTION_P2(ScheduleRenameAndAnnotateCallback, interrupt_reason, new_path) {
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(arg4, interrupt_reason, new_path));
+}
+
+// Schedules a task to invoke a callback that's bound to the specified
+// parameter.
+// E.g.:
+//
+// EXPECT_CALL(foo, Bar(1, _))
+// .WithArg<1>(ScheduleCallbackWithParam(0));
+//
+// .. will invoke the second argument to Bar with 0 as the parameter.
+ACTION_P(ScheduleCallbackWithParam, param) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(arg0, param));
+}
+
+// Schedules a task to invoke a closure.
+// E.g.:
+//
+// EXPECT_CALL(foo, Bar(1, _))
+// .WillOnce(ScheduleClosure(some_closure));
+ACTION_P(ScheduleClosure, closure) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closure);
+}
+
+const char kTestData1[] = {'M', 'a', 'r', 'y', ' ', 'h', 'a', 'd',
+ ' ', 'a', ' ', 'l', 'i', 't', 't', 'l',
+ 'e', ' ', 'l', 'a', 'm', 'b', '.'};
+
+// SHA256 hash of TestData1
+const uint8_t kHashOfTestData1[] = {
+ 0xd2, 0xfc, 0x16, 0xa1, 0xf5, 0x1a, 0x65, 0x3a, 0xa0, 0x19, 0x64,
+ 0xef, 0x9c, 0x92, 0x33, 0x36, 0xe1, 0x06, 0x53, 0xfe, 0xc1, 0x95,
+ 0xf4, 0x93, 0x45, 0x8b, 0x3b, 0x21, 0x89, 0x0e, 0x1b, 0x97};
+
} // namespace
class DownloadItemTest : public testing::Test {
public:
DownloadItemTest()
- : ui_thread_(BrowserThread::UI, &loop_),
- file_thread_(BrowserThread::FILE, &loop_),
- delegate_() {
- }
-
- ~DownloadItemTest() {
- }
-
- virtual void SetUp() {
+ : delegate_(), next_download_id_(DownloadItem::kInvalidId + 1) {
base::FeatureList::ClearInstanceForTesting();
scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->InitializeFromCommandLine(features::kDownloadResumption.name,
std::string());
base::FeatureList::SetInstance(std::move(feature_list));
- }
- virtual void TearDown() {
- ui_thread_.DeprecatedGetThreadObject()->message_loop()->RunUntilIdle();
- STLDeleteElements(&allocated_downloads_);
+ create_info_.reset(new DownloadCreateInfo());
+ create_info_->save_info =
+ scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo());
+ create_info_->save_info->prompt_for_save_location = false;
+ create_info_->url_chain.push_back(GURL("http://example.com/download"));
+ create_info_->etag = "SomethingToSatisfyResumption";
}
- // This class keeps ownership of the created download item; it will
- // be torn down at the end of the test unless DestroyDownloadItem is
- // called.
- DownloadItemImpl* CreateDownloadItem() {
- scoped_ptr<DownloadCreateInfo> info;
-
- info.reset(new DownloadCreateInfo());
- info->save_info = scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo());
- info->save_info->prompt_for_save_location = false;
- info->url_chain.push_back(GURL());
- info->etag = "SomethingToSatisfyResumption";
-
- return CreateDownloadItemWithCreateInfo(std::move(info));
+ ~DownloadItemTest() {
+ RunAllPendingInMessageLoops();
+ STLDeleteElements(&allocated_downloads_);
}
DownloadItemImpl* CreateDownloadItemWithCreateInfo(
@@ -231,26 +273,47 @@ class DownloadItemTest : public testing::Test {
return download;
}
- // Add DownloadFile to DownloadItem
- MockDownloadFile* AddDownloadFileToDownloadItem(
+ // This class keeps ownership of the created download item; it will
+ // be torn down at the end of the test unless DestroyDownloadItem is
+ // called.
+ DownloadItemImpl* CreateDownloadItem() {
+ create_info_->download_id = ++next_download_id_;
+ DownloadItemImpl* download =
+ new DownloadItemImpl(&delegate_, create_info_->download_id,
+ *create_info_, net::BoundNetLog());
+ allocated_downloads_.insert(download);
+ return download;
+ }
+
+ // Add DownloadFile to DownloadItem. Set |callback| to nullptr if a download
+ // target determination is not expected.
+ MockDownloadFile* CallDownloadItemStart(
DownloadItemImpl* item,
- DownloadItemImplDelegate::DownloadTargetCallback *callback) {
- MockDownloadFile* mock_download_file(new StrictMock<MockDownloadFile>);
- scoped_ptr<DownloadFile> download_file(mock_download_file);
- EXPECT_CALL(*mock_download_file, Initialize(_));
+ DownloadItemImplDelegate::DownloadTargetCallback* callback) {
+ MockDownloadFile* mock_download_file = nullptr;
+ scoped_ptr<DownloadFile> download_file;
if (callback) {
- // Save the callback.
EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
.WillOnce(SaveArg<1>(callback));
} else {
- // Drop it on the floor.
- EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _)).Times(0);
+ }
+
+ // Only create a DownloadFile if the request was successful.
+ if (create_info_->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ mock_download_file = new StrictMock<MockDownloadFile>;
+ download_file.reset(mock_download_file);
+ EXPECT_CALL(*mock_download_file, Initialize(_))
+ .WillOnce(ScheduleCallbackWithParam(DOWNLOAD_INTERRUPT_REASON_NONE));
+ EXPECT_CALL(*mock_download_file, FullPath())
+ .WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
}
- scoped_ptr<DownloadRequestHandleInterface> request_handle(
+ scoped_ptr<MockRequestHandle> request_handle(
new NiceMock<MockRequestHandle>);
- item->Start(std::move(download_file), std::move(request_handle));
- loop_.RunUntilIdle();
+ item->Start(std::move(download_file), std::move(request_handle),
+ *create_info_);
+ RunAllPendingInMessageLoops();
// So that we don't have a function writing to a stack variable
// lying around if the above failed.
@@ -266,27 +329,42 @@ class DownloadItemTest : public testing::Test {
}
// Perform the intermediate rename for |item|. The target path for the
- // download will be set to kDummyPath. Returns the MockDownloadFile* that was
- // added to the DownloadItem.
+ // download will be set to kDummyTargetPath. Returns the MockDownloadFile*
+ // that was added to the DownloadItem.
MockDownloadFile* DoIntermediateRename(DownloadItemImpl* item,
DownloadDangerType danger_type) {
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
EXPECT_TRUE(item->GetTargetFilePath().empty());
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
- base::FilePath target_path(kDummyPath);
- base::FilePath intermediate_path(
- target_path.InsertBeforeExtensionASCII("x"));
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
+ base::FilePath target_path(kDummyTargetPath);
+ base::FilePath intermediate_path(kDummyIntermediatePath);
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, intermediate_path));
callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
danger_type, intermediate_path);
RunAllPendingInMessageLoops();
return download_file;
}
+ void DoDestinationComplete(DownloadItemImpl* item,
+ MockDownloadFile* download_file) {
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(_, _))
+ .WillOnce(Return(true));
+ base::FilePath final_path(kDummyTargetPath);
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, final_path));
+ EXPECT_CALL(*download_file, FullPath())
+ .WillRepeatedly(ReturnRefOfCopy(base::FilePath(kDummyTargetPath)));
+ EXPECT_CALL(*download_file, Detach());
+
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
+ RunAllPendingInMessageLoops();
+ }
+
// Cleanup a download item (specifically get rid of the DownloadFile on it).
// The item must be in the expected state.
void CleanupItem(DownloadItemImpl* item,
@@ -298,7 +376,7 @@ class DownloadItemTest : public testing::Test {
if (download_file)
EXPECT_CALL(*download_file, Cancel());
item->Cancel(true);
- loop_.RunUntilIdle();
+ RunAllPendingInMessageLoops();
}
}
@@ -308,9 +386,7 @@ class DownloadItemTest : public testing::Test {
delete item;
}
- void RunAllPendingInMessageLoops() {
- loop_.RunUntilIdle();
- }
+ void RunAllPendingInMessageLoops() { base::RunLoop().RunUntilIdle(); }
MockDelegate* mock_delegate() {
return &delegate_;
@@ -321,13 +397,17 @@ class DownloadItemTest : public testing::Test {
*return_path = path;
}
+ DownloadCreateInfo* create_info() { return create_info_.get(); }
+
+ BrowserContext* browser_context() { return &browser_context_; }
+
private:
- int next_download_id_ = DownloadItem::kInvalidId + 1;
- base::MessageLoopForUI loop_;
- TestBrowserThread ui_thread_; // UI thread
- TestBrowserThread file_thread_; // FILE thread
StrictMock<MockDelegate> delegate_;
std::set<DownloadItem*> allocated_downloads_;
+ scoped_ptr<DownloadCreateInfo> create_info_;
+ uint32_t next_download_id_ = DownloadItem::kInvalidId + 1;
+ TestBrowserContext browser_context_;
+ TestBrowserThreadBundle thread_bundle_;
};
// Tests to ensure calls that change a DownloadItem generate an update to
@@ -340,28 +420,33 @@ class DownloadItemTest : public testing::Test {
TEST_F(DownloadItemTest, NotificationAfterUpdate) {
DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+ ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
TestDownloadItemObserver observer(item);
- item->DestinationUpdate(kDownloadChunkSize, kDownloadSpeed, std::string());
+ item->DestinationUpdate(kDownloadChunkSize, kDownloadSpeed);
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
EXPECT_EQ(kDownloadSpeed, item->CurrentSpeed());
+ CleanupItem(item, file, DownloadItem::IN_PROGRESS);
}
TEST_F(DownloadItemTest, NotificationAfterCancel) {
DownloadItemImpl* user_cancel = CreateDownloadItem();
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(user_cancel, NULL);
+ CallDownloadItemStart(user_cancel, &target_callback);
EXPECT_CALL(*download_file, Cancel());
- TestDownloadItemObserver observer1(user_cancel);
+ TestDownloadItemObserver observer1(user_cancel);
user_cancel->Cancel(true);
ASSERT_TRUE(observer1.CheckAndResetDownloadUpdated());
DownloadItemImpl* system_cancel = CreateDownloadItem();
- download_file = AddDownloadFileToDownloadItem(system_cancel, NULL);
+ download_file = CallDownloadItemStart(system_cancel, &target_callback);
EXPECT_CALL(*download_file, Cancel());
- TestDownloadItemObserver observer2(system_cancel);
+ TestDownloadItemObserver observer2(system_cancel);
system_cancel->Cancel(false);
ASSERT_TRUE(observer2.CheckAndResetDownloadUpdated());
}
@@ -369,11 +454,10 @@ TEST_F(DownloadItemTest, NotificationAfterCancel) {
TEST_F(DownloadItemTest, NotificationAfterComplete) {
DownloadItemImpl* item = CreateDownloadItem();
TestDownloadItemObserver observer(item);
-
- item->OnAllDataSaved(DownloadItem::kEmptyFileHash);
+ MockDownloadFile* download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
-
- item->MarkAsComplete();
+ DoDestinationComplete(item, download_file);
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
}
@@ -396,7 +480,9 @@ TEST_F(DownloadItemTest, NotificationAfterInterrupted) {
.Times(0);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
}
@@ -408,8 +494,8 @@ TEST_F(DownloadItemTest, NotificationAfterDestroyed) {
ASSERT_TRUE(observer.download_destroyed());
}
+// Test that a download is resumed automatcially after a continuable interrupt.
TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
- TestBrowserContext test_browser_context;
DownloadItemImpl* item = CreateDownloadItem();
TestDownloadItemObserver observer(item);
MockDownloadFile* download_file =
@@ -417,13 +503,15 @@ TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
// Interrupt the download, using a continuable interrupt.
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
EXPECT_CALL(*mock_delegate(), GetBrowserContext())
- .WillRepeatedly(Return(&test_browser_context));
+ .WillRepeatedly(Return(browser_context()));
EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(_, _)).Times(1);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
+ DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
// Since the download is resumed automatically, the interrupt count doesn't
// increase.
@@ -441,7 +529,8 @@ TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
CleanupItem(item, nullptr, DownloadItem::IN_PROGRESS);
}
-// Same as above, but with a non-continuable interrupt.
+// Test that automatic resumption doesn't happen after a non-continuable
+// interrupt.
TEST_F(DownloadItemTest, RestartAfterInterrupted) {
DownloadItemImpl* item = CreateDownloadItem();
TestDownloadItemObserver observer(item);
@@ -451,7 +540,9 @@ TEST_F(DownloadItemTest, RestartAfterInterrupted) {
// Interrupt the download, using a restartable interrupt.
EXPECT_CALL(*download_file, Cancel());
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
// Should not try to auto-resume.
ASSERT_EQ(1, observer.interrupt_count());
@@ -471,13 +562,15 @@ TEST_F(DownloadItemTest, UnresumableInterrupt) {
// Fail final rename with unresumable reason.
EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
.WillOnce(Return(true));
- EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED, base::FilePath()));
EXPECT_CALL(*download_file, Cancel());
// Complete download to trigger final rename.
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
@@ -489,25 +582,24 @@ TEST_F(DownloadItemTest, UnresumableInterrupt) {
}
TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
- TestBrowserContext test_browser_context;
DownloadItemImpl* item = CreateDownloadItem();
base::WeakPtr<DownloadDestinationObserver> as_observer(
item->DestinationObserverAsWeakPtr());
TestDownloadItemObserver observer(item);
- MockDownloadFile* mock_download_file(NULL);
+ MockDownloadFile* mock_download_file(nullptr);
scoped_ptr<DownloadFile> download_file;
- MockRequestHandle* mock_request_handle(NULL);
+ MockRequestHandle* mock_request_handle(nullptr);
scoped_ptr<DownloadRequestHandleInterface> request_handle;
DownloadItemImplDelegate::DownloadTargetCallback callback;
EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
.WillRepeatedly(SaveArg<1>(&callback));
EXPECT_CALL(*mock_delegate(), GetBrowserContext())
- .WillRepeatedly(Return(&test_browser_context));
+ .WillRepeatedly(Return(browser_context()));
EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(_, _))
.Times(DownloadItemImpl::kMaxAutoResumeAttempts);
for (int i = 0; i < (DownloadItemImpl::kMaxAutoResumeAttempts + 1); ++i) {
- DVLOG(20) << "Loop iteration " << i;
+ SCOPED_TRACE(::testing::Message() << "Iteration " << i);
mock_download_file = new NiceMock<MockDownloadFile>;
download_file.reset(mock_download_file);
@@ -515,65 +607,128 @@ TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
request_handle.reset(mock_request_handle);
ON_CALL(*mock_download_file, FullPath())
- .WillByDefault(Return(base::FilePath()));
+ .WillByDefault(ReturnRefOfCopy(base::FilePath()));
- // Copied key parts of DoIntermediateRename & AddDownloadFileToDownloadItem
+ // Copied key parts of DoIntermediateRename & CallDownloadItemStart
// to allow for holding onto the request handle.
- item->Start(std::move(download_file), std::move(request_handle));
+ item->Start(std::move(download_file), std::move(request_handle),
+ *create_info());
RunAllPendingInMessageLoops();
+
+ base::FilePath target_path(kDummyTargetPath);
+ base::FilePath intermediate_path(kDummyIntermediatePath);
if (i == 0) {
- // Target determination is only done the first time through.
- base::FilePath target_path(kDummyPath);
- base::FilePath intermediate_path(
- target_path.InsertBeforeExtensionASCII("x"));
+ // RenameAndUniquify is only called the first time. In all the subsequent
+ // iterations, the intermediate file already has the correct name, hence
+ // no rename is necessary.
EXPECT_CALL(*mock_download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- intermediate_path));
- callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
- DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
- RunAllPendingInMessageLoops();
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, intermediate_path));
}
+ callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
+ RunAllPendingInMessageLoops();
// Use a continuable interrupt.
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
+ DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
+ RunAllPendingInMessageLoops();
::testing::Mock::VerifyAndClearExpectations(mock_download_file);
}
+ EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
EXPECT_EQ(1, observer.interrupt_count());
CleanupItem(item, nullptr, DownloadItem::INTERRUPTED);
}
+// If the download attempts to resume and the resumption request fails, the
+// subsequent Start() call shouldn't update the origin state (URL redirect
+// chains, Content-Disposition, download URL, etc..)
+TEST_F(DownloadItemTest, FailedResumptionDoesntUpdateOriginState) {
+ const char kContentDisposition[] = "attachment; filename=foo";
+ const char kFirstETag[] = "ABC";
+ const char kFirstLastModified[] = "Yesterday";
+ const char kFirstURL[] = "http://www.example.com/download";
+ create_info()->content_disposition = kContentDisposition;
+ create_info()->etag = kFirstETag;
+ create_info()->last_modified = kFirstLastModified;
+ create_info()->url_chain.push_back(GURL(kFirstURL));
+
+ DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+ EXPECT_EQ(kContentDisposition, item->GetContentDisposition());
+ EXPECT_EQ(kFirstETag, item->GetETag());
+ EXPECT_EQ(kFirstLastModified, item->GetLastModifiedTime());
+ EXPECT_EQ(kFirstURL, item->GetURL().spec());
+
+ EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(_, _));
+ EXPECT_CALL(*mock_delegate(), GetBrowserContext())
+ .WillRepeatedly(Return(browser_context()));
+ EXPECT_CALL(*download_file, Detach());
+ item->DestinationObserverAsWeakPtr()->DestinationError(
+ DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
+ RunAllPendingInMessageLoops();
+ EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
+
+ // Now change the create info. The changes should not cause the DownloadItem
+ // to be updated.
+ const char kSecondContentDisposition[] = "attachment; filename=bar";
+ const char kSecondETag[] = "123";
+ const char kSecondLastModified[] = "Today";
+ const char kSecondURL[] = "http://example.com/another-download";
+ create_info()->content_disposition = kSecondContentDisposition;
+ create_info()->etag = kSecondETag;
+ create_info()->last_modified = kSecondLastModified;
+ create_info()->url_chain.clear();
+ create_info()->url_chain.push_back(GURL(kSecondURL));
+ create_info()->result = DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED;
+
+ // The following ends up calling DownloadItem::Start(), but shouldn't result
+ // in an origin update.
+ download_file = CallDownloadItemStart(item, nullptr);
+
+ EXPECT_EQ(kContentDisposition, item->GetContentDisposition());
+ EXPECT_EQ(kFirstETag, item->GetETag());
+ EXPECT_EQ(kFirstLastModified, item->GetLastModifiedTime());
+ EXPECT_EQ(kFirstURL, item->GetURL().spec());
+ EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
+}
+
// Test that resumption uses the final URL in a URL chain when resuming.
TEST_F(DownloadItemTest, ResumeUsingFinalURL) {
- TestBrowserContext test_browser_context;
- scoped_ptr<DownloadCreateInfo> create_info(new DownloadCreateInfo);
- create_info->save_info = scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo());
- create_info->save_info->prompt_for_save_location = false;
- create_info->etag = "SomethingToSatisfyResumption";
- create_info->url_chain.push_back(GURL("http://example.com/a"));
- create_info->url_chain.push_back(GURL("http://example.com/b"));
- create_info->url_chain.push_back(GURL("http://example.com/c"));
-
- DownloadItemImpl* item =
- CreateDownloadItemWithCreateInfo(std::move(create_info));
+ create_info()->save_info->prompt_for_save_location = false;
+ create_info()->url_chain.clear();
+ create_info()->url_chain.push_back(GURL("http://example.com/a"));
+ create_info()->url_chain.push_back(GURL("http://example.com/b"));
+ create_info()->url_chain.push_back(GURL("http://example.com/c"));
+
+ DownloadItemImpl* item = CreateDownloadItem();
TestDownloadItemObserver observer(item);
MockDownloadFile* download_file =
DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
// Interrupt the download, using a continuable interrupt.
- EXPECT_CALL(*download_file, FullPath()).WillOnce(Return(base::FilePath()));
+ EXPECT_CALL(*download_file, FullPath())
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
EXPECT_CALL(*mock_delegate(), GetBrowserContext())
- .WillRepeatedly(Return(&test_browser_context));
+ .WillRepeatedly(Return(browser_context()));
EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(
Property(&DownloadUrlParameters::url,
GURL("http://example.com/c")),
_))
.Times(1);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
+ DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
// Test expectations verify that ResumeInterruptedDownload() is called (by way
// of MockResumeInterruptedDownload) after the download is interrupted. But
@@ -588,7 +743,9 @@ TEST_F(DownloadItemTest, ResumeUsingFinalURL) {
TEST_F(DownloadItemTest, NotificationAfterRemove) {
DownloadItemImpl* item = CreateDownloadItem();
- MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
+ MockDownloadFile* download_file =
+ CallDownloadItemStart(item, &target_callback);
EXPECT_CALL(*download_file, Cancel());
EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
TestDownloadItemObserver observer(item);
@@ -601,37 +758,52 @@ TEST_F(DownloadItemTest, NotificationAfterRemove) {
TEST_F(DownloadItemTest, NotificationAfterOnContentCheckCompleted) {
// Setting to NOT_DANGEROUS does not trigger a notification.
DownloadItemImpl* safe_item = CreateDownloadItem();
+ MockDownloadFile* download_file =
+ DoIntermediateRename(safe_item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
TestDownloadItemObserver safe_observer(safe_item);
- safe_item->OnAllDataSaved(std::string());
+ safe_item->OnAllDataSaved(0, scoped_ptr<crypto::SecureHash>());
EXPECT_TRUE(safe_observer.CheckAndResetDownloadUpdated());
safe_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
EXPECT_TRUE(safe_observer.CheckAndResetDownloadUpdated());
+ CleanupItem(safe_item, download_file, DownloadItem::IN_PROGRESS);
// Setting to unsafe url or unsafe file should trigger a notification.
DownloadItemImpl* unsafeurl_item =
CreateDownloadItem();
+ download_file =
+ DoIntermediateRename(unsafeurl_item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
TestDownloadItemObserver unsafeurl_observer(unsafeurl_item);
- unsafeurl_item->OnAllDataSaved(std::string());
+ unsafeurl_item->OnAllDataSaved(0, scoped_ptr<crypto::SecureHash>());
EXPECT_TRUE(unsafeurl_observer.CheckAndResetDownloadUpdated());
unsafeurl_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
EXPECT_TRUE(unsafeurl_observer.CheckAndResetDownloadUpdated());
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(_, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _));
unsafeurl_item->ValidateDangerousDownload();
EXPECT_TRUE(unsafeurl_observer.CheckAndResetDownloadUpdated());
+ CleanupItem(unsafeurl_item, download_file, DownloadItem::IN_PROGRESS);
DownloadItemImpl* unsafefile_item =
CreateDownloadItem();
+ download_file =
+ DoIntermediateRename(unsafefile_item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
TestDownloadItemObserver unsafefile_observer(unsafefile_item);
- unsafefile_item->OnAllDataSaved(std::string());
+ unsafefile_item->OnAllDataSaved(0, scoped_ptr<crypto::SecureHash>());
EXPECT_TRUE(unsafefile_observer.CheckAndResetDownloadUpdated());
unsafefile_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
EXPECT_TRUE(unsafefile_observer.CheckAndResetDownloadUpdated());
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(_, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _));
unsafefile_item->ValidateDangerousDownload();
EXPECT_TRUE(unsafefile_observer.CheckAndResetDownloadUpdated());
+ CleanupItem(unsafefile_item, download_file, DownloadItem::IN_PROGRESS);
}
// DownloadItemImpl::OnDownloadTargetDetermined will schedule a task to run
@@ -642,16 +814,15 @@ TEST_F(DownloadItemTest, NotificationAfterOnContentCheckCompleted) {
TEST_F(DownloadItemTest, NotificationAfterOnDownloadTargetDetermined) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
TestDownloadItemObserver observer(item);
- base::FilePath target_path(kDummyPath);
+ base::FilePath target_path(kDummyTargetPath);
base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
target_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, new_intermediate_path));
// Currently, a notification would be generated if the danger type is anything
// other than NOT_DANGEROUS.
@@ -675,7 +846,8 @@ TEST_F(DownloadItemTest, NotificationAfterTogglePause) {
EXPECT_CALL(*mock_download_file, Initialize(_));
EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _));
- item->Start(std::move(download_file), std::move(request_handle));
+ item->Start(std::move(download_file), std::move(request_handle),
+ *create_info());
item->Pause();
ASSERT_TRUE(observer.CheckAndResetDownloadUpdated());
@@ -693,15 +865,15 @@ TEST_F(DownloadItemTest, NotificationAfterTogglePause) {
TEST_F(DownloadItemTest, DisplayName) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
- base::FilePath target_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
+ base::FilePath target_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
EXPECT_EQ(FILE_PATH_LITERAL(""),
item->GetFileNameToReportUser().value());
EXPECT_CALL(*download_file, RenameAndUniquify(_, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, intermediate_path));
callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
RunAllPendingInMessageLoops();
@@ -722,25 +894,90 @@ TEST_F(DownloadItemTest, Start) {
scoped_ptr<DownloadRequestHandleInterface> request_handle(
new NiceMock<MockRequestHandle>);
EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
- item->Start(std::move(download_file), std::move(request_handle));
+ item->Start(std::move(download_file), std::move(request_handle),
+ *create_info());
RunAllPendingInMessageLoops();
CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
}
+// Download file and the request should be cancelled as a result of download
+// file initialization failing.
+TEST_F(DownloadItemTest, InitDownloadFileFails) {
+ DownloadItemImpl* item = CreateDownloadItem();
+ scoped_ptr<MockDownloadFile> file(new MockDownloadFile());
+ scoped_ptr<MockRequestHandle> request_handle(new MockRequestHandle());
+ EXPECT_CALL(*file, Cancel());
+ EXPECT_CALL(*request_handle, CancelRequest());
+ EXPECT_CALL(*file, Initialize(_))
+ .WillOnce(ScheduleCallbackWithParam(
+ DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED));
+
+ base::RunLoop start_download_loop;
+ DownloadItemImplDelegate::DownloadTargetCallback download_target_callback;
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
+ .WillOnce(DoAll(SaveArg<1>(&download_target_callback),
+ ScheduleClosure(start_download_loop.QuitClosure())));
+
+ item->Start(std::move(file), std::move(request_handle), *create_info());
+ start_download_loop.Run();
+
+ download_target_callback.Run(base::FilePath(kDummyTargetPath),
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ base::FilePath(kDummyIntermediatePath));
+ RunAllPendingInMessageLoops();
+
+ EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
+ item->GetLastReason());
+}
+
+// Handling of downloads initiated via a failed request. In this case, Start()
+// will get called with a DownloadCreateInfo with a non-zero interrupt_reason.
+TEST_F(DownloadItemTest, StartFailedDownload) {
+ create_info()->result = DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED;
+ DownloadItemImpl* item = CreateDownloadItem();
+
+ // DownloadFile and DownloadRequestHandleInterface objects aren't created for
+ // failed downloads.
+ scoped_ptr<DownloadFile> null_download_file;
+ scoped_ptr<DownloadRequestHandleInterface> null_request_handle;
+ DownloadItemImplDelegate::DownloadTargetCallback download_target_callback;
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
+ .WillOnce(SaveArg<1>(&download_target_callback));
+ item->Start(std::move(null_download_file), std::move(null_request_handle),
+ *create_info());
+ EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
+ RunAllPendingInMessageLoops();
+
+ // The DownloadItemImpl should attempt to determine a target path even if the
+ // download was interrupted.
+ ASSERT_FALSE(download_target_callback.is_null());
+ ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
+ base::FilePath target_path(FILE_PATH_LITERAL("foo"));
+ download_target_callback.Run(target_path,
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, target_path);
+ RunAllPendingInMessageLoops();
+
+ EXPECT_EQ(target_path, item->GetTargetFilePath());
+ CleanupItem(item, NULL, DownloadItem::INTERRUPTED);
+}
+
// Test that the delegate is invoked after the download file is renamed.
TEST_F(DownloadItemTest, CallbackAfterRename) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
- base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
+ base::FilePath final_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
final_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, new_intermediate_path));
callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
@@ -751,13 +988,14 @@ TEST_F(DownloadItemTest, CallbackAfterRename) {
EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
.WillOnce(Return(true));
- EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- final_path));
+ EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, final_path));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
::testing::Mock::VerifyAndClearExpectations(download_file);
mock_delegate()->VerifyAndClearExpectations();
@@ -768,15 +1006,15 @@ TEST_F(DownloadItemTest, CallbackAfterRename) {
TEST_F(DownloadItemTest, CallbackAfterInterruptedRename) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
- base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
+ base::FilePath final_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
final_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, new_intermediate_path));
EXPECT_CALL(*download_file, Cancel())
.Times(1);
@@ -798,7 +1036,8 @@ TEST_F(DownloadItemTest, Interrupted) {
// Confirm interrupt sets state properly.
EXPECT_CALL(*download_file, Cancel());
- item->DestinationObserverAsWeakPtr()->DestinationError(reason);
+ item->DestinationObserverAsWeakPtr()->DestinationError(
+ reason, 0, scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
EXPECT_EQ(reason, item->GetLastReason());
@@ -814,19 +1053,21 @@ TEST_F(DownloadItemTest, Interrupted) {
TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
- base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ base::FilePath final_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
final_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, new_intermediate_path));
EXPECT_CALL(*download_file, Cancel())
.Times(1);
@@ -847,21 +1088,23 @@ TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
- base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ base::FilePath final_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
final_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, new_intermediate_path));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath(new_intermediate_path)));
+ .WillOnce(ReturnRefOfCopy(base::FilePath(new_intermediate_path)));
EXPECT_CALL(*download_file, Detach());
callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
@@ -876,23 +1119,25 @@ TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
}
// As above. If the intermediate rename fails, then the interrupt reason should
-// be set to the destination error and the intermediate path should be empty.
+// be set to the file error and the intermediate path should be empty.
TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
- MockDownloadFile* download_file =
- AddDownloadFileToDownloadItem(item, &callback);
+ MockDownloadFile* download_file = CallDownloadItemStart(item, &callback);
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
- base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
+ base::FilePath final_path(
+ base::FilePath(kDummyTargetPath).AppendASCII("foo.bar"));
base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
base::FilePath new_intermediate_path(
final_path.InsertBeforeExtensionASCII("y"));
EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
- new_intermediate_path));
+ .WillOnce(ScheduleRenameAndUniquifyCallback(
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, new_intermediate_path));
EXPECT_CALL(*download_file, Cancel())
.Times(1);
@@ -903,14 +1148,16 @@ TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
::testing::Mock::VerifyAndClearExpectations(download_file);
mock_delegate()->VerifyAndClearExpectations();
EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, item->GetLastReason());
EXPECT_TRUE(item->GetFullPath().empty());
EXPECT_EQ(final_path, item->GetTargetFilePath());
}
TEST_F(DownloadItemTest, Canceled) {
DownloadItemImpl* item = CreateDownloadItem();
- MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
+ MockDownloadFile* download_file =
+ CallDownloadItemStart(item, &target_callback);
// Confirm cancel sets state properly.
EXPECT_CALL(*download_file, Cancel());
@@ -928,34 +1175,62 @@ TEST_F(DownloadItemTest, FileRemoved) {
TEST_F(DownloadItemTest, DestinationUpdate) {
DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
base::WeakPtr<DownloadDestinationObserver> as_observer(
item->DestinationObserverAsWeakPtr());
TestDownloadItemObserver observer(item);
EXPECT_EQ(0l, item->CurrentSpeed());
- EXPECT_EQ("", item->GetHashState());
EXPECT_EQ(0l, item->GetReceivedBytes());
EXPECT_EQ(0l, item->GetTotalBytes());
EXPECT_FALSE(observer.CheckAndResetDownloadUpdated());
item->SetTotalBytes(100l);
EXPECT_EQ(100l, item->GetTotalBytes());
- as_observer->DestinationUpdate(10, 20, "deadbeef");
+ as_observer->DestinationUpdate(10, 20);
EXPECT_EQ(20l, item->CurrentSpeed());
- EXPECT_EQ("deadbeef", item->GetHashState());
EXPECT_EQ(10l, item->GetReceivedBytes());
EXPECT_EQ(100l, item->GetTotalBytes());
EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
- as_observer->DestinationUpdate(200, 20, "livebeef");
+ as_observer->DestinationUpdate(200, 20);
EXPECT_EQ(20l, item->CurrentSpeed());
- EXPECT_EQ("livebeef", item->GetHashState());
EXPECT_EQ(200l, item->GetReceivedBytes());
EXPECT_EQ(0l, item->GetTotalBytes());
EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
+
+ CleanupItem(item, file, DownloadItem::IN_PROGRESS);
}
-TEST_F(DownloadItemTest, DestinationError) {
+TEST_F(DownloadItemTest, DestinationError_NoRestartRequired) {
+ DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+ base::WeakPtr<DownloadDestinationObserver> as_observer(
+ item->DestinationObserverAsWeakPtr());
+ TestDownloadItemObserver observer(item);
+
+ EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, item->GetLastReason());
+ EXPECT_FALSE(observer.CheckAndResetDownloadUpdated());
+
+ scoped_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(kTestData1, sizeof(kTestData1));
+
+ EXPECT_CALL(*download_file, Detach());
+ as_observer->DestinationError(
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, 0, std::move(hash));
+ mock_delegate()->VerifyAndClearExpectations();
+ EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
+ EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
+ EXPECT_EQ(
+ std::string(std::begin(kHashOfTestData1), std::end(kHashOfTestData1)),
+ item->GetHash());
+}
+TEST_F(DownloadItemTest, DestinationError_RestartRequired) {
DownloadItemImpl* item = CreateDownloadItem();
MockDownloadFile* download_file =
DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
@@ -967,43 +1242,58 @@ TEST_F(DownloadItemTest, DestinationError) {
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, item->GetLastReason());
EXPECT_FALSE(observer.CheckAndResetDownloadUpdated());
+ scoped_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(kTestData1, sizeof(kTestData1));
+
EXPECT_CALL(*download_file, Cancel());
as_observer->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, 0, std::move(hash));
mock_delegate()->VerifyAndClearExpectations();
EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
- item->GetLastReason());
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, item->GetLastReason());
+ EXPECT_EQ(std::string(), item->GetHash());
}
TEST_F(DownloadItemTest, DestinationCompleted) {
DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
base::WeakPtr<DownloadDestinationObserver> as_observer(
item->DestinationObserverAsWeakPtr());
TestDownloadItemObserver observer(item);
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
EXPECT_EQ("", item->GetHash());
- EXPECT_EQ("", item->GetHashState());
EXPECT_FALSE(item->AllDataSaved());
EXPECT_FALSE(observer.CheckAndResetDownloadUpdated());
- as_observer->DestinationUpdate(10, 20, "deadbeef");
+ as_observer->DestinationUpdate(10, 20);
EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
EXPECT_FALSE(observer.CheckAndResetDownloadUpdated()); // Confirm reset.
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
EXPECT_EQ("", item->GetHash());
- EXPECT_EQ("deadbeef", item->GetHashState());
EXPECT_FALSE(item->AllDataSaved());
- as_observer->DestinationCompleted("livebeef");
+ scoped_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(kTestData1, sizeof(kTestData1));
+
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(_, _));
+ as_observer->DestinationCompleted(10, std::move(hash));
mock_delegate()->VerifyAndClearExpectations();
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
EXPECT_TRUE(observer.CheckAndResetDownloadUpdated());
- EXPECT_EQ("livebeef", item->GetHash());
- EXPECT_EQ("", item->GetHashState());
+ EXPECT_EQ(
+ std::string(std::begin(kHashOfTestData1), std::end(kHashOfTestData1)),
+ item->GetHash());
EXPECT_TRUE(item->AllDataSaved());
+
+ // Even though the DownloadItem receives a DestinationCompleted() event,
+ // target determination hasn't completed, hence the download item is stuck in
+ // TARGET_PENDING.
+ CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
}
TEST_F(DownloadItemTest, EnabledActionsForNormalDownload) {
@@ -1018,15 +1308,16 @@ TEST_F(DownloadItemTest, EnabledActionsForNormalDownload) {
EXPECT_TRUE(item->CanOpenDownload());
// Complete
- EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
.WillOnce(Return(true));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
@@ -1050,13 +1341,14 @@ TEST_F(DownloadItemTest, EnabledActionsForTemporaryDownload) {
// Complete Temporary
EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
.WillOnce(Return(true));
- EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
@@ -1071,13 +1363,15 @@ TEST_F(DownloadItemTest, EnabledActionsForInterruptedDownload) {
EXPECT_CALL(*download_file, Cancel());
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
RunAllPendingInMessageLoops();
ASSERT_EQ(DownloadItem::INTERRUPTED, item->GetState());
ASSERT_FALSE(item->GetTargetFilePath().empty());
EXPECT_FALSE(item->CanShowInFolder());
- EXPECT_FALSE(item->CanOpenDownload());
+ EXPECT_TRUE(item->CanOpenDownload());
}
TEST_F(DownloadItemTest, EnabledActionsForCancelledDownload) {
@@ -1107,18 +1401,20 @@ TEST_F(DownloadItemTest, CompleteDelegate_ReturnTrue) {
// Drive the delegate interaction.
EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
.WillOnce(Return(true));
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
EXPECT_FALSE(item->IsDangerous());
// Make sure the download can complete.
- EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
.WillOnce(Return(true));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
RunAllPendingInMessageLoops();
EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
@@ -1139,7 +1435,8 @@ TEST_F(DownloadItemTest, CompleteDelegate_BlockOnce) {
.WillOnce(DoAll(SaveArg<1>(&delegate_callback),
Return(false)))
.WillOnce(Return(true));
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
ASSERT_FALSE(delegate_callback.is_null());
copy_delegate_callback = delegate_callback;
delegate_callback.Reset();
@@ -1150,13 +1447,14 @@ TEST_F(DownloadItemTest, CompleteDelegate_BlockOnce) {
EXPECT_FALSE(item->IsDangerous());
// Make sure the download can complete.
- EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
.WillOnce(Return(true));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
RunAllPendingInMessageLoops();
EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
@@ -1177,7 +1475,8 @@ TEST_F(DownloadItemTest, CompleteDelegate_SetDanger) {
.WillOnce(DoAll(SaveArg<1>(&delegate_callback),
Return(false)))
.WillOnce(Return(true));
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
ASSERT_FALSE(delegate_callback.is_null());
copy_delegate_callback = delegate_callback;
delegate_callback.Reset();
@@ -1191,13 +1490,14 @@ TEST_F(DownloadItemTest, CompleteDelegate_SetDanger) {
EXPECT_TRUE(item->IsDangerous());
// Make sure the download doesn't complete until we've validated it.
- EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
.WillOnce(Return(true));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
RunAllPendingInMessageLoops();
EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
@@ -1226,7 +1526,8 @@ TEST_F(DownloadItemTest, CompleteDelegate_BlockTwice) {
.WillOnce(DoAll(SaveArg<1>(&delegate_callback),
Return(false)))
.WillOnce(Return(true));
- item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, scoped_ptr<crypto::SecureHash>());
ASSERT_FALSE(delegate_callback.is_null());
copy_delegate_callback = delegate_callback;
delegate_callback.Reset();
@@ -1242,13 +1543,14 @@ TEST_F(DownloadItemTest, CompleteDelegate_BlockTwice) {
EXPECT_FALSE(item->IsDangerous());
// Make sure the download can complete.
- EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
- .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
- base::FilePath(kDummyPath)));
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(base::FilePath(kDummyTargetPath), _, _, _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath)));
EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
.WillOnce(Return(true));
EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(base::FilePath()));
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
EXPECT_CALL(*download_file, Detach());
RunAllPendingInMessageLoops();
EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
@@ -1262,8 +1564,7 @@ TEST_F(DownloadItemTest, StealDangerousDownload) {
base::FilePath full_path(FILE_PATH_LITERAL("foo.txt"));
base::FilePath returned_path;
- EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(full_path));
+ EXPECT_CALL(*download_file, FullPath()).WillOnce(ReturnRefOfCopy(full_path));
EXPECT_CALL(*download_file, Detach());
EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
@@ -1282,11 +1583,12 @@ TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
base::FilePath full_path = item->GetFullPath();
EXPECT_FALSE(full_path.empty());
- EXPECT_CALL(*download_file, FullPath())
- .WillOnce(Return(full_path));
+ EXPECT_CALL(*download_file, FullPath()).WillOnce(ReturnRefOfCopy(full_path));
EXPECT_CALL(*download_file, Detach());
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_TRUE(item->IsDangerous());
EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
@@ -1306,7 +1608,9 @@ TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
EXPECT_CALL(*download_file, Cancel());
item->DestinationObserverAsWeakPtr()->DestinationError(
- DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
+ DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ 0,
+ scoped_ptr<crypto::SecureHash>());
ASSERT_TRUE(item->IsDangerous());
EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
@@ -1319,6 +1623,428 @@ TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
EXPECT_TRUE(returned_path.empty());
}
+namespace {
+
+// The DownloadItemDestinationUpdateRaceTest fixture (defined below) is used to
+// test for race conditions between download destination events received via the
+// DownloadDestinationObserver interface, and the target determination logic.
+//
+// The general control flow for DownloadItemImpl looks like this:
+//
+// * Start() called, which in turn calls DownloadFile::Initialize().
+//
+// Even though OnDownloadFileInitialized hasn't been called, there could now
+// be destination observer calls queued prior to the task that calls
+// OnDownloadFileInitialized. Let's call this point in the workflow "A".
+//
+// * DownloadItemImpl::OnDownloadFileInitialized() called.
+//
+// * Assuming the result is successful, DII now invokes the delegate's
+// DetermineDownloadTarget method.
+//
+// At this point DonwnloadFile acts as the source of
+// DownloadDestinationObserver events, and may invoke callbacks. Let's call
+// this point in the workflow "B".
+//
+// * DII::OnDownloadTargetDetermined() invoked after delegate is done with
+// target determination.
+//
+// * DII attempts to rename the DownloadFile to its intermediate name.
+//
+// More DownloadDestinationObserver events can happen here. Let's call this
+// point in the workflow "C".
+//
+// * DII::OnDownloadRenamedToIntermediateName() invoked. Assuming all went well,
+// DII is now in IN_PROGRESS state.
+//
+// More DownloadDestinationObserver events can happen here. Let's call this
+// point in the workflow "D".
+//
+// The DownloadItemDestinationUpdateRaceTest works by generating various
+// combinations of DownloadDestinationObserver events that might occur at the
+// points "A", "B", "C", and "D" above. Each test in this suite cranks a
+// DownloadItemImpl through the states listed above and invokes the events
+// assigned to each position.
+
+// This type of callback represents a call to a DownloadDestinationObserver
+// method that's missing the DownloadDestinationObserver object. Currying this
+// way allows us to bind a call prior to constructing the object on which the
+// method would be invoked. This is necessary since we are going to construct
+// various permutations of observer calls that will then be applied to a
+// DownloadItem in a state as yet undetermined.
+using CurriedObservation =
+ base::Callback<void(base::WeakPtr<DownloadDestinationObserver>)>;
+
+// A list of observations that are to be made during some event in the
+// DownloadItemImpl control flow. Ordering of the observations is significant.
+using ObservationList = std::deque<CurriedObservation>;
+
+// An ordered list of events.
+//
+// An "event" in this context refers to some stage in the DownloadItemImpl's
+// workflow described as "A", "B", "C", or "D" above. An EventList is expected
+// to always contains kEventCount events.
+using EventList = std::deque<ObservationList>;
+
+// Number of events in an EventList. This is always 4 for now as described
+// above.
+const int kEventCount = 4;
+
+// The following functions help us with currying the calls to
+// DownloadDestinationObserver. If std::bind was allowed along with
+// std::placeholders, it is possible to avoid these functions, but currently
+// Chromium doesn't allow using std::bind for good reasons.
+void DestinationUpdateInvoker(
+ int64_t bytes_so_far,
+ int64_t bytes_per_sec,
+ base::WeakPtr<DownloadDestinationObserver> observer) {
+ DVLOG(20) << "DestinationUpdate(bytes_so_far:" << bytes_so_far
+ << ", bytes_per_sec:" << bytes_per_sec
+ << ") observer:" << !!observer;
+ if (observer)
+ observer->DestinationUpdate(bytes_so_far, bytes_per_sec);
+}
+
+void DestinationErrorInvoker(
+ DownloadInterruptReason reason,
+ int64_t bytes_so_far,
+ base::WeakPtr<DownloadDestinationObserver> observer) {
+ DVLOG(20) << "DestinationError(reason:"
+ << DownloadInterruptReasonToString(reason)
+ << ", bytes_so_far:" << bytes_so_far << ") observer:" << !!observer;
+ if (observer)
+ observer->DestinationError(
+ reason, bytes_so_far, scoped_ptr<crypto::SecureHash>());
+}
+
+void DestinationCompletedInvoker(
+ int64_t total_bytes,
+ base::WeakPtr<DownloadDestinationObserver> observer) {
+ DVLOG(20) << "DestinationComplete(total_bytes:" << total_bytes
+ << ") observer:" << !!observer;
+ if (observer)
+ observer->DestinationCompleted(total_bytes,
+ scoped_ptr<crypto::SecureHash>());
+}
+
+// Given a set of observations (via the range |begin|..|end|), constructs a list
+// of EventLists such that:
+//
+// * There are exactly |event_count| ObservationSets in each EventList.
+//
+// * Each ObservationList in each EventList contains a subrange (possibly empty)
+// of observations from the input range, in the same order as the input range.
+//
+// * The ordering of the ObservationList in each EventList is such that all
+// observations in one ObservationList occur earlier than all observations in
+// an ObservationList that follows it.
+//
+// * The list of EventLists together describe all the possible ways in which the
+// list of observations can be distributed into |event_count| events.
+std::vector<EventList> DistributeObservationsIntoEvents(
+ const std::vector<CurriedObservation>::iterator begin,
+ const std::vector<CurriedObservation>::iterator end,
+ int event_count) {
+ std::vector<EventList> all_event_lists;
+ for (auto partition = begin;; ++partition) {
+ ObservationList first_group_of_observations(begin, partition);
+ if (event_count > 1) {
+ std::vector<EventList> list_of_subsequent_events =
+ DistributeObservationsIntoEvents(partition, end, event_count - 1);
+ for (const auto& subsequent_events : list_of_subsequent_events) {
+ EventList event_list;
+ event_list = subsequent_events;
+ event_list.push_front(first_group_of_observations);
+ all_event_lists.push_back(event_list);
+ }
+ } else {
+ EventList event_list;
+ event_list.push_front(first_group_of_observations);
+ all_event_lists.push_back(event_list);
+ }
+ if (partition == end)
+ break;
+ }
+ return all_event_lists;
+}
+
+// For the purpose of this tests, we are only concerned with 3 events:
+//
+// 1. Immediately after the DownloadFile is initialized.
+// 2. Immediately after the DownloadTargetCallback is invoked.
+// 3. Immediately after the intermediate file is renamed.
+//
+// We are going to take a couple of sets of DownloadDestinationObserver events
+// and distribute them into the three events described above. And then we are
+// going to invoke the observations while a DownloadItemImpl is carefully
+// stepped through its stages.
+
+std::vector<EventList> GenerateSuccessfulEventLists() {
+ std::vector<CurriedObservation> all_observations;
+ all_observations.push_back(base::Bind(&DestinationUpdateInvoker, 100, 100));
+ all_observations.push_back(base::Bind(&DestinationUpdateInvoker, 200, 100));
+ all_observations.push_back(base::Bind(&DestinationCompletedInvoker, 200));
+ return DistributeObservationsIntoEvents(all_observations.begin(),
+ all_observations.end(), kEventCount);
+}
+
+std::vector<EventList> GenerateFailingEventLists() {
+ std::vector<CurriedObservation> all_observations;
+ all_observations.push_back(base::Bind(&DestinationUpdateInvoker, 100, 100));
+ all_observations.push_back(base::Bind(
+ &DestinationErrorInvoker, DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, 100));
+ return DistributeObservationsIntoEvents(all_observations.begin(),
+ all_observations.end(), kEventCount);
+}
+
+class DownloadItemDestinationUpdateRaceTest
+ : public DownloadItemTest,
+ public ::testing::WithParamInterface<EventList> {
+ public:
+ DownloadItemDestinationUpdateRaceTest()
+ : DownloadItemTest(),
+ item_(CreateDownloadItem()),
+ file_(new ::testing::StrictMock<MockDownloadFile>()),
+ request_handle_(new ::testing::StrictMock<MockRequestHandle>()) {
+ DCHECK_EQ(GetParam().size(), static_cast<unsigned>(kEventCount));
+ EXPECT_CALL(*request_handle_, GetWebContents())
+ .WillRepeatedly(Return(nullptr));
+ }
+
+ protected:
+ const ObservationList& PreInitializeFileObservations() {
+ return GetParam().front();
+ }
+ const ObservationList& PostInitializeFileObservations() {
+ return *(GetParam().begin() + 1);
+ }
+ const ObservationList& PostTargetDeterminationObservations() {
+ return *(GetParam().begin() + 2);
+ }
+ const ObservationList& PostIntermediateRenameObservations() {
+ return *(GetParam().begin() + 3);
+ }
+
+ // Apply all the observations in |observations| to |observer|, but do so
+ // asynchronously so that the events are applied in order behind any tasks
+ // that are already scheduled.
+ void ScheduleObservations(
+ const ObservationList& observations,
+ base::WeakPtr<DownloadDestinationObserver> observer) {
+ for (const auto action : observations)
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(action, observer));
+ }
+
+ DownloadItemImpl* item_;
+ scoped_ptr<MockDownloadFile> file_;
+ scoped_ptr<MockRequestHandle> request_handle_;
+
+ std::queue<base::Closure> successful_update_events_;
+ std::queue<base::Closure> failing_update_events_;
+};
+
+INSTANTIATE_TEST_CASE_P(Success,
+ DownloadItemDestinationUpdateRaceTest,
+ ::testing::ValuesIn(GenerateSuccessfulEventLists()));
+
+INSTANTIATE_TEST_CASE_P(Failure,
+ DownloadItemDestinationUpdateRaceTest,
+ ::testing::ValuesIn(GenerateFailingEventLists()));
+
+} // namespace
+
+// Run through the DII workflow but the embedder cancels the download at target
+// determination.
+TEST_P(DownloadItemDestinationUpdateRaceTest, DownloadCancelledByUser) {
+ // Expect that the download file and the request will be cancelled as a
+ // result.
+ EXPECT_CALL(*file_, Cancel());
+ EXPECT_CALL(*request_handle_, CancelRequest());
+
+ base::RunLoop download_start_loop;
+ DownloadFile::InitializeCallback initialize_callback;
+ EXPECT_CALL(*file_, Initialize(_))
+ .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
+ ScheduleClosure(download_start_loop.QuitClosure())));
+ item_->Start(std::move(file_), std::move(request_handle_), *create_info());
+ download_start_loop.Run();
+
+ base::WeakPtr<DownloadDestinationObserver> destination_observer =
+ item_->DestinationObserverAsWeakPtr();
+
+ ScheduleObservations(PreInitializeFileObservations(), destination_observer);
+ RunAllPendingInMessageLoops();
+
+ base::RunLoop initialize_completion_loop;
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&target_callback),
+ ScheduleClosure(initialize_completion_loop.QuitClosure())));
+ ScheduleObservations(PostInitializeFileObservations(), destination_observer);
+ initialize_callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE);
+ initialize_completion_loop.Run();
+
+ RunAllPendingInMessageLoops();
+
+ ASSERT_FALSE(target_callback.is_null());
+ ScheduleObservations(PostTargetDeterminationObservations(),
+ destination_observer);
+ target_callback.Run(base::FilePath(),
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, base::FilePath());
+ EXPECT_EQ(DownloadItem::CANCELLED, item_->GetState());
+ RunAllPendingInMessageLoops();
+}
+
+// Run through the DII workflow, but the intermediate rename fails.
+TEST_P(DownloadItemDestinationUpdateRaceTest, IntermediateRenameFails) {
+ // Expect that the download file and the request will be cancelled as a
+ // result.
+ EXPECT_CALL(*file_, Cancel());
+ EXPECT_CALL(*request_handle_, CancelRequest());
+
+ // Intermediate rename loop is not used immediately, but let's set up the
+ // DownloadFile expectations since we are about to transfer its ownership to
+ // the DownloadItem.
+ base::RunLoop intermediate_rename_loop;
+ DownloadFile::RenameCompletionCallback intermediate_rename_callback;
+ EXPECT_CALL(*file_, RenameAndUniquify(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&intermediate_rename_callback),
+ ScheduleClosure(intermediate_rename_loop.QuitClosure())));
+
+ base::RunLoop download_start_loop;
+ DownloadFile::InitializeCallback initialize_callback;
+ EXPECT_CALL(*file_, Initialize(_))
+ .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
+ ScheduleClosure(download_start_loop.QuitClosure())));
+
+ item_->Start(std::move(file_), std::move(request_handle_), *create_info());
+ download_start_loop.Run();
+ base::WeakPtr<DownloadDestinationObserver> destination_observer =
+ item_->DestinationObserverAsWeakPtr();
+
+ ScheduleObservations(PreInitializeFileObservations(), destination_observer);
+ RunAllPendingInMessageLoops();
+
+ base::RunLoop initialize_completion_loop;
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&target_callback),
+ ScheduleClosure(initialize_completion_loop.QuitClosure())));
+ ScheduleObservations(PostInitializeFileObservations(), destination_observer);
+ initialize_callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE);
+ initialize_completion_loop.Run();
+
+ RunAllPendingInMessageLoops();
+ ASSERT_FALSE(target_callback.is_null());
+
+ ScheduleObservations(PostTargetDeterminationObservations(),
+ destination_observer);
+ target_callback.Run(base::FilePath(kDummyTargetPath),
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ base::FilePath(kDummyIntermediatePath));
+
+ intermediate_rename_loop.Run();
+ ASSERT_FALSE(intermediate_rename_callback.is_null());
+
+ ScheduleObservations(PostIntermediateRenameObservations(),
+ destination_observer);
+ intermediate_rename_callback.Run(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
+ base::FilePath());
+ RunAllPendingInMessageLoops();
+
+ EXPECT_EQ(DownloadItem::INTERRUPTED, item_->GetState());
+}
+
+// Run through the DII workflow. Download file initialization, target
+// determination and intermediate rename all succeed.
+TEST_P(DownloadItemDestinationUpdateRaceTest, IntermediateRenameSucceeds) {
+ // We expect either that the download will fail (in which case the request and
+ // the download file will be cancelled), or it will succeed (in which case the
+ // DownloadFile will Detach()). It depends on the list of observations that
+ // are given to us.
+ EXPECT_CALL(*file_, Cancel()).Times(::testing::AnyNumber());
+ EXPECT_CALL(*request_handle_, CancelRequest()).Times(::testing::AnyNumber());
+ EXPECT_CALL(*file_, Detach()).Times(::testing::AnyNumber());
+
+ EXPECT_CALL(*file_, FullPath())
+ .WillRepeatedly(ReturnRefOfCopy(base::FilePath(kDummyIntermediatePath)));
+
+ // Intermediate rename loop is not used immediately, but let's set up the
+ // DownloadFile expectations since we are about to transfer its ownership to
+ // the DownloadItem.
+ base::RunLoop intermediate_rename_loop;
+ DownloadFile::RenameCompletionCallback intermediate_rename_callback;
+ EXPECT_CALL(*file_, RenameAndUniquify(_, _))
+ .WillOnce(DoAll(SaveArg<1>(&intermediate_rename_callback),
+ ScheduleClosure(intermediate_rename_loop.QuitClosure())));
+
+ base::RunLoop download_start_loop;
+ DownloadFile::InitializeCallback initialize_callback;
+ EXPECT_CALL(*file_, Initialize(_))
+ .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
+ ScheduleClosure(download_start_loop.QuitClosure())));
+
+ item_->Start(std::move(file_), std::move(request_handle_), *create_info());
+ download_start_loop.Run();
+ base::WeakPtr<DownloadDestinationObserver> destination_observer =
+ item_->DestinationObserverAsWeakPtr();
+
+ ScheduleObservations(PreInitializeFileObservations(), destination_observer);
+ RunAllPendingInMessageLoops();
+
+ base::RunLoop initialize_completion_loop;
+ DownloadItemImplDelegate::DownloadTargetCallback target_callback;
+ EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&target_callback),
+ ScheduleClosure(initialize_completion_loop.QuitClosure())));
+ ScheduleObservations(PostInitializeFileObservations(), destination_observer);
+ initialize_callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE);
+ initialize_completion_loop.Run();
+
+ RunAllPendingInMessageLoops();
+ ASSERT_FALSE(target_callback.is_null());
+
+ ScheduleObservations(PostTargetDeterminationObservations(),
+ destination_observer);
+ target_callback.Run(base::FilePath(kDummyTargetPath),
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ base::FilePath(kDummyIntermediatePath));
+
+ intermediate_rename_loop.Run();
+ ASSERT_FALSE(intermediate_rename_callback.is_null());
+
+ // This may or may not be called, depending on whether there are any errors in
+ // our action list.
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(_, _))
+ .Times(::testing::AnyNumber());
+
+ ScheduleObservations(PostIntermediateRenameObservations(),
+ destination_observer);
+ intermediate_rename_callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE,
+ base::FilePath(kDummyIntermediatePath));
+ RunAllPendingInMessageLoops();
+
+ // The state of the download depends on the observer events that were played
+ // back to the DownloadItemImpl. Hence we can't establish a single expectation
+ // here. On Debug builds, the DCHECKs will verify that the state transitions
+ // were correct. On Release builds, tests are expected to run to completion
+ // without crashing on success.
+ EXPECT_TRUE(item_->GetState() == DownloadItem::IN_PROGRESS ||
+ item_->GetState() == DownloadItem::INTERRUPTED);
+ if (item_->GetState() == DownloadItem::INTERRUPTED)
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item_->GetLastReason());
+
+ item_->Cancel(true);
+ RunAllPendingInMessageLoops();
+}
+
TEST(MockDownloadItem, Compiles) {
MockDownloadItem mock_item;
}
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index 97c0a85e714..28f1c3fca65 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -45,6 +45,7 @@
#include "net/base/request_priority.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/url_request/url_request_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
#include "url/origin.h"
namespace content {
@@ -55,90 +56,53 @@ scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread> BeginDownload(
uint32_t download_id,
base::WeakPtr<DownloadManagerImpl> download_manager) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
- // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
- // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
- scoped_ptr<net::URLRequest> request(
- params->resource_context()->GetRequestContext()->CreateRequest(
- params->url(), net::DEFAULT_PRIORITY, NULL));
- request->set_method(params->method());
- if (!params->post_body().empty()) {
- const std::string& body = params->post_body();
- scoped_ptr<net::UploadElementReader> reader(
- net::UploadOwnedBytesElementReader::CreateWithString(body));
- request->set_upload(
- net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
- }
- if (params->post_id() >= 0) {
- // The POST in this case does not have an actual body, and only works
- // when retrieving data from cache. This is done because we don't want
- // to do a re-POST without user consent, and currently don't have a good
- // plan on how to display the UI for that.
- DCHECK(params->prefer_cache());
- DCHECK_EQ("POST", params->method());
- std::vector<scoped_ptr<net::UploadElementReader>> element_readers;
- request->set_upload(make_scoped_ptr(new net::ElementsUploadDataStream(
- std::move(element_readers), params->post_id())));
- }
- // If we're not at the beginning of the file, retrieve only the remaining
- // portion.
- bool has_last_modified = !params->last_modified().empty();
- bool has_etag = !params->etag().empty();
-
- // If we've asked for a range, we want to make sure that we only
- // get that range if our current copy of the information is good.
- // We shouldn't be asked to continue if we don't have a verifier.
- DCHECK(params->offset() == 0 || has_etag || has_last_modified);
-
- if (params->offset() > 0 && (has_etag || has_last_modified)) {
- request->SetExtraRequestHeaderByName(
- "Range",
- base::StringPrintf("bytes=%" PRId64 "-", params->offset()),
- true);
-
- // In accordance with RFC 2616 Section 14.27, use If-Range to specify that
- // the server return the entire entity if the validator doesn't match.
- // Last-Modified can be used in the absence of ETag as a validator if the
- // response headers satisfied the HttpUtil::HasStrongValidators() predicate.
- //
- // This function assumes that HasStrongValidators() was true and that the
- // ETag and Last-Modified header values supplied are valid.
- request->SetExtraRequestHeaderByName(
- "If-Range", has_etag ? params->etag() : params->last_modified(), true);
+ scoped_ptr<net::URLRequest> url_request =
+ DownloadRequestCore::CreateRequestOnIOThread(download_id, params.get());
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle =
+ params->GetBlobDataHandle();
+ if (blob_data_handle) {
+ storage::BlobProtocolHandler::SetRequestedBlobDataHandle(
+ url_request.get(), std::move(blob_data_handle));
}
- for (DownloadUrlParameters::RequestHeadersType::const_iterator iter
- = params->request_headers_begin();
- iter != params->request_headers_end();
- ++iter) {
- request->SetExtraRequestHeaderByName(
- iter->first, iter->second, false /*overwrite*/);
- }
-
- scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
- save_info->file_path = params->file_path();
- save_info->suggested_name = params->suggested_name();
- save_info->offset = params->offset();
- save_info->hash_state = params->hash_state();
- save_info->prompt_for_save_location = params->prompt();
- save_info->file = params->GetFile();
-
+ // If there's a valid renderer process associated with the request, then the
+ // request should be driven by the ResourceLoader. Pass it over to the
+ // ResourceDispatcherHostImpl which will in turn pass it along to the
+ // ResourceLoader.
if (params->render_process_host_id() != -1) {
- ResourceDispatcherHost::Get()->BeginDownload(
- std::move(request), params->referrer(), params->content_initiated(),
- params->resource_context(), params->render_process_host_id(),
- params->render_view_host_routing_id(),
- params->render_frame_host_routing_id(), params->prefer_cache(),
- params->do_not_prompt_for_login(), std::move(save_info), download_id,
- params->callback());
+ DownloadInterruptReason reason =
+ ResourceDispatcherHostImpl::Get()->BeginDownload(
+ std::move(url_request), params->referrer(),
+ params->content_initiated(), params->resource_context(),
+ params->render_process_host_id(),
+ params->render_view_host_routing_id(),
+ params->render_frame_host_routing_id(),
+ params->do_not_prompt_for_login());
+
+ // If the download was accepted, the DownloadResourceHandler is now
+ // responsible for driving the request to completion.
+ if (reason == DOWNLOAD_INTERRUPT_REASON_NONE)
+ return nullptr;
+
+ // Otherwise, create an interrupted download.
+ scoped_ptr<DownloadCreateInfo> failed_created_info(
+ new DownloadCreateInfo(base::Time::Now(), net::BoundNetLog(),
+ make_scoped_ptr(new DownloadSaveInfo)));
+ failed_created_info->url_chain.push_back(params->url());
+ failed_created_info->result = reason;
+ scoped_ptr<ByteStreamReader> empty_byte_stream;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DownloadManager::StartDownload, download_manager,
+ base::Passed(&failed_created_info),
+ base::Passed(&empty_byte_stream), params->callback()));
return nullptr;
}
+
return scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread>(
- UrlDownloader::BeginDownload(download_manager, std::move(request),
- params->referrer(), params->prefer_cache(),
- std::move(save_info), download_id,
- params->callback())
+ UrlDownloader::BeginDownload(download_manager, std::move(url_request),
+ params->referrer())
.release());
}
@@ -149,6 +113,7 @@ class DownloadItemFactoryImpl : public DownloadItemFactory {
DownloadItemImpl* CreatePersistedItem(
DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t download_id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -162,31 +127,33 @@ class DownloadItemFactoryImpl : public DownloadItemFactory {
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
bool opened,
const net::BoundNetLog& bound_net_log) override {
- return new DownloadItemImpl(
- delegate,
- download_id,
- current_path,
- target_path,
- url_chain,
- referrer_url,
- mime_type,
- original_mime_type,
- start_time,
- end_time,
- etag,
- last_modified,
- received_bytes,
- total_bytes,
- state,
- danger_type,
- interrupt_reason,
- opened,
- bound_net_log);
+ return new DownloadItemImpl(delegate,
+ guid,
+ download_id,
+ current_path,
+ target_path,
+ url_chain,
+ referrer_url,
+ mime_type,
+ original_mime_type,
+ start_time,
+ end_time,
+ etag,
+ last_modified,
+ received_bytes,
+ total_bytes,
+ hash,
+ state,
+ danger_type,
+ interrupt_reason,
+ opened,
+ bound_net_log);
}
DownloadItemImpl* CreateActiveItem(
@@ -240,6 +207,7 @@ DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
DownloadItemImpl* download =
item_factory_->CreateActiveItem(this, id, info, bound_net_log);
downloads_[id] = download;
+ downloads_by_guid_[download->GetGuid()] = download;
return download;
}
@@ -322,13 +290,13 @@ void DownloadManagerImpl::Shutdown() {
// dangerous downloads which will remain in history if they aren't explicitly
// accepted or discarded. Canceling will remove the intermediate download
// file.
- for (DownloadMap::iterator it = downloads_.begin(); it != downloads_.end();
- ++it) {
- DownloadItemImpl* download = it->second;
+ for (const auto& it : downloads_) {
+ DownloadItemImpl* download = it.second;
if (download->GetState() == DownloadItem::IN_PROGRESS)
download->Cancel(false);
}
STLDeleteValues(&downloads_);
+ downloads_by_guid_.clear();
url_downloaders_.clear();
// We'll have nothing more to report to the observers after this point.
@@ -345,6 +313,11 @@ void DownloadManagerImpl::StartDownload(
const DownloadUrlParameters::OnStartedCallback& on_started) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(info);
+ // |stream| is only non-nil if the download request was successful.
+ DCHECK((info->result == DOWNLOAD_INTERRUPT_REASON_NONE && stream.get()) ||
+ (info->result != DOWNLOAD_INTERRUPT_REASON_NONE && !stream.get()));
+ DVLOG(20) << __FUNCTION__ << "()"
+ << " result=" << DownloadInterruptReasonToString(info->result);
uint32_t download_id = info->download_id;
const bool new_download = (download_id == content::DownloadItem::kInvalidId);
base::Callback<void(uint32_t)> got_id(base::Bind(
@@ -380,13 +353,12 @@ void DownloadManagerImpl::StartDownloadWithId(
if (!on_started.is_null())
on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
// The ByteStreamReader lives and dies on the FILE thread.
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE,
- stream.release());
+ if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE)
+ BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE,
+ stream.release());
return;
}
download = item_iterator->second;
- DCHECK_EQ(download->GetState(), DownloadItem::IN_PROGRESS);
- download->MergeOriginInfoOnResume(*info);
}
base::FilePath default_download_directory;
@@ -397,20 +369,23 @@ void DownloadManagerImpl::StartDownloadWithId(
&default_download_directory, &skip_dir_check);
}
- // Create the download file and start the download.
- scoped_ptr<DownloadFile> download_file(file_factory_->CreateFile(
- std::move(info->save_info), default_download_directory, info->url(),
- info->referrer_url, delegate_ && delegate_->GenerateFileHash(),
- std::move(stream), download->GetBoundNetLog(),
- download->DestinationObserverAsWeakPtr()));
-
- // Attach the client ID identifying the app to the AV system.
- if (download_file.get() && delegate_) {
- download_file->SetClientGuid(
- delegate_->ApplicationClientIdForFileScanning());
+ scoped_ptr<DownloadFile> download_file;
+
+ if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ DCHECK(stream.get());
+ download_file.reset(
+ file_factory_->CreateFile(std::move(info->save_info),
+ default_download_directory,
+ std::move(stream),
+ download->GetBoundNetLog(),
+ download->DestinationObserverAsWeakPtr()));
}
+ // It is important to leave info->save_info intact in the case of an interrupt
+ // so that the DownloadItem can salvage what it can out of a failed resumption
+ // attempt.
- download->Start(std::move(download_file), std::move(info->request_handle));
+ download->Start(std::move(download_file), std::move(info->request_handle),
+ *info);
// For interrupted downloads, Start() will transition the state to
// IN_PROGRESS and consumers will be notified via OnDownloadUpdated().
@@ -426,9 +401,8 @@ void DownloadManagerImpl::StartDownloadWithId(
void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- DownloadItemImpl* item = it->second;
+ for (const auto& it : downloads_) {
+ DownloadItemImpl* item = it.second;
CheckForFileRemoval(item);
}
}
@@ -487,6 +461,8 @@ void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
this, id, main_file_path, page_url, mime_type, std::move(request_handle),
bound_net_log);
downloads_[download_item->GetId()] = download_item;
+ DCHECK(!ContainsKey(downloads_by_guid_, download_item->GetGuid()));
+ downloads_by_guid_[download_item->GetGuid()] = download_item;
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(
this, download_item));
if (!item_created.is_null())
@@ -532,6 +508,8 @@ void DownloadManagerImpl::DownloadRemoved(DownloadItemImpl* download) {
if (!download)
return;
+ downloads_by_guid_.erase(download->GetGuid());
+
uint32_t download_id = download->GetId();
if (downloads_.erase(download_id) == 0)
return;
@@ -556,19 +534,18 @@ void DownloadManagerImpl::RemoveUrlDownloader(UrlDownloader* downloader) {
namespace {
-bool RemoveDownloadBetween(base::Time remove_begin,
- base::Time remove_end,
- const DownloadItemImpl* download_item) {
- return download_item->GetStartTime() >= remove_begin &&
- (remove_end.is_null() || download_item->GetStartTime() < remove_end);
+bool EmptyFilter(const GURL& url) {
+ return true;
}
-bool RemoveDownloadByOriginAndTime(const url::Origin& origin,
- base::Time remove_begin,
- base::Time remove_end,
- const DownloadItemImpl* download_item) {
- return origin.IsSameOriginWith(url::Origin(download_item->GetURL())) &&
- RemoveDownloadBetween(remove_begin, remove_end, download_item);
+bool RemoveDownloadByURLAndTime(
+ const base::Callback<bool(const GURL&)>& url_filter,
+ base::Time remove_begin,
+ base::Time remove_end,
+ const DownloadItemImpl* download_item) {
+ return url_filter.Run(download_item->GetURL()) &&
+ download_item->GetStartTime() >= remove_begin &&
+ (remove_end.is_null() || download_item->GetStartTime() < remove_end);
}
} // namespace
@@ -591,28 +568,21 @@ int DownloadManagerImpl::RemoveDownloads(const DownloadRemover& remover) {
return count;
}
-int DownloadManagerImpl::RemoveDownloadsByOriginAndTime(
- const url::Origin& origin,
+int DownloadManagerImpl::RemoveDownloadsByURLAndTime(
+ const base::Callback<bool(const GURL&)>& url_filter,
base::Time remove_begin,
base::Time remove_end) {
- return RemoveDownloads(base::Bind(&RemoveDownloadByOriginAndTime,
- base::ConstRef(origin), remove_begin,
- remove_end));
-}
-
-int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
- base::Time remove_end) {
- return RemoveDownloads(
- base::Bind(&RemoveDownloadBetween, remove_begin, remove_end));
-}
-
-int DownloadManagerImpl::RemoveDownloads(base::Time remove_begin) {
- return RemoveDownloadsBetween(remove_begin, base::Time());
+ return RemoveDownloads(base::Bind(&RemoveDownloadByURLAndTime,
+ url_filter,
+ remove_begin, remove_end));
}
int DownloadManagerImpl::RemoveAllDownloads() {
+ const base::Callback<bool(const GURL&)> empty_filter =
+ base::Bind(&EmptyFilter);
// The null times make the date range unbounded.
- int num_deleted = RemoveDownloadsBetween(base::Time(), base::Time());
+ int num_deleted = RemoveDownloadsByURLAndTime(
+ empty_filter, base::Time(), base::Time());
RecordClearAllSize(num_deleted);
return num_deleted;
}
@@ -641,6 +611,7 @@ void DownloadManagerImpl::RemoveObserver(Observer* observer) {
}
DownloadItem* DownloadManagerImpl::CreateDownloadItem(
+ const std::string& guid,
uint32_t id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -654,6 +625,7 @@ DownloadItem* DownloadManagerImpl::CreateDownloadItem(
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
@@ -662,8 +634,10 @@ DownloadItem* DownloadManagerImpl::CreateDownloadItem(
NOTREACHED();
return NULL;
}
+ DCHECK(!ContainsKey(downloads_by_guid_, guid));
DownloadItemImpl* item = item_factory_->CreatePersistedItem(
this,
+ guid,
id,
current_path,
target_path,
@@ -677,12 +651,14 @@ DownloadItem* DownloadManagerImpl::CreateDownloadItem(
last_modified,
received_bytes,
total_bytes,
+ hash,
state,
danger_type,
interrupt_reason,
opened,
net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD));
downloads_[id] = item;
+ downloads_by_guid_[guid] = item;
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, item));
DVLOG(20) << __FUNCTION__ << "() download = " << item->DebugString(true);
return item;
@@ -690,9 +666,8 @@ DownloadItem* DownloadManagerImpl::CreateDownloadItem(
int DownloadManagerImpl::InProgressCount() const {
int count = 0;
- for (DownloadMap::const_iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- if (it->second->GetState() == DownloadItem::IN_PROGRESS)
+ for (const auto& it : downloads_) {
+ if (it.second->GetState() == DownloadItem::IN_PROGRESS)
++count;
}
return count;
@@ -700,13 +675,12 @@ int DownloadManagerImpl::InProgressCount() const {
int DownloadManagerImpl::NonMaliciousInProgressCount() const {
int count = 0;
- for (DownloadMap::const_iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- if (it->second->GetState() == DownloadItem::IN_PROGRESS &&
- it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_URL &&
- it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT &&
- it->second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST &&
- it->second->GetDangerType() !=
+ for (const auto& it : downloads_) {
+ if (it.second->GetState() == DownloadItem::IN_PROGRESS &&
+ it.second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_URL &&
+ it.second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT &&
+ it.second->GetDangerType() != DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST &&
+ it.second->GetDangerType() !=
DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED) {
++count;
}
@@ -715,21 +689,26 @@ int DownloadManagerImpl::NonMaliciousInProgressCount() const {
}
DownloadItem* DownloadManagerImpl::GetDownload(uint32_t download_id) {
- return ContainsKey(downloads_, download_id) ? downloads_[download_id] : NULL;
+ return ContainsKey(downloads_, download_id) ? downloads_[download_id]
+ : nullptr;
+}
+
+DownloadItem* DownloadManagerImpl::GetDownloadByGuid(const std::string& guid) {
+ DCHECK(guid == base::ToUpperASCII(guid));
+ return ContainsKey(downloads_by_guid_, guid) ? downloads_by_guid_[guid]
+ : nullptr;
}
void DownloadManagerImpl::GetAllDownloads(DownloadVector* downloads) {
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- downloads->push_back(it->second);
+ for (const auto& it : downloads_) {
+ downloads->push_back(it.second);
}
}
void DownloadManagerImpl::OpenDownload(DownloadItemImpl* download) {
int num_unopened = 0;
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- DownloadItemImpl* item = it->second;
+ for (const auto& it : downloads_) {
+ DownloadItemImpl* item = it.second;
if ((item->GetState() == DownloadItem::COMPLETE) &&
!item->GetOpened())
++num_unopened;
diff --git a/chromium/content/browser/download/download_manager_impl.h b/chromium/content/browser/download/download_manager_impl.h
index ebac07ab081..610b76408fc 100644
--- a/chromium/content/browser/download/download_manager_impl.h
+++ b/chromium/content/browser/download/download_manager_impl.h
@@ -7,13 +7,12 @@
#include <stdint.h>
-#include <map>
#include <set>
#include <string>
+#include <unordered_map>
#include <vector>
#include "base/callback_forward.h"
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -42,7 +41,7 @@ class DownloadRequestHandleInterface;
class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
private DownloadItemImplDelegate {
public:
- typedef base::Callback<void(DownloadItemImpl*)> DownloadItemImplCreated;
+ using DownloadItemImplCreated = base::Callback<void(DownloadItemImpl*)>;
// Caller guarantees that |net_log| will remain valid
// for the lifetime of DownloadManagerImpl (until Shutdown() is called).
@@ -74,17 +73,16 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
scoped_ptr<ByteStreamReader> stream,
const DownloadUrlParameters::OnStartedCallback& on_started) override;
- int RemoveDownloadsByOriginAndTime(const url::Origin& origin,
- base::Time remove_begin,
- base::Time remove_end) override;
- int RemoveDownloadsBetween(base::Time remove_begin,
- base::Time remove_end) override;
- int RemoveDownloads(base::Time remove_begin) override;
+ int RemoveDownloadsByURLAndTime(
+ const base::Callback<bool(const GURL&)>& url_filter,
+ base::Time remove_begin,
+ base::Time remove_end) override;
int RemoveAllDownloads() override;
void DownloadUrl(scoped_ptr<DownloadUrlParameters> params) override;
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
content::DownloadItem* CreateDownloadItem(
+ const std::string& guid,
uint32_t id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -98,6 +96,7 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
content::DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
@@ -107,6 +106,7 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
BrowserContext* GetBrowserContext() const override;
void CheckForHistoryFilesRemoval() override;
DownloadItem* GetDownload(uint32_t id) override;
+ DownloadItem* GetDownloadByGuid(const std::string& guid) override;
// For testing; specifically, accessed from TestFileErrorInjector.
void SetDownloadItemFactoryForTesting(
@@ -118,10 +118,11 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
void RemoveUrlDownloader(UrlDownloader* downloader);
private:
- typedef std::set<DownloadItem*> DownloadSet;
- typedef base::hash_map<uint32_t, DownloadItemImpl*> DownloadMap;
- typedef std::vector<DownloadItemImpl*> DownloadItemImplVector;
- typedef base::Callback<bool(const DownloadItemImpl*)> DownloadRemover;
+ using DownloadSet = std::set<DownloadItem*>;
+ using DownloadMap = std::unordered_map<uint32_t, DownloadItemImpl*>;
+ using DownloadGuidMap = std::unordered_map<std::string, DownloadItemImpl*>;
+ using DownloadItemImplVector = std::vector<DownloadItemImpl*>;
+ using DownloadRemover = base::Callback<bool(const DownloadItemImpl*)>;
// For testing.
friend class DownloadManagerTest;
@@ -189,8 +190,16 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
// DownloadManager. This includes downloads started by the user in
// this session, downloads initialized from the history system, and
// "save page as" downloads.
+ // TODO(asanka): Remove this container in favor of downloads_by_guid_ as a
+ // part of http://crbug.com/593020.
DownloadMap downloads_;
+ // Same as the above, but maps from GUID to download item. Note that the
+ // container is case sensitive. Hence the key needs to be normalized to
+ // upper-case when inserting new elements here. Fortunately for us,
+ // DownloadItemImpl already normalizes the string GUID.
+ DownloadGuidMap downloads_by_guid_;
+
int history_size_;
// True if the download manager has been initialized and requires a shutdown.
diff --git a/chromium/content/browser/download/download_manager_impl_unittest.cc b/chromium/content/browser/download/download_manager_impl_unittest.cc
index 78d13863470..c72a1d07a82 100644
--- a/chromium/content/browser/download/download_manager_impl_unittest.cc
+++ b/chromium/content/browser/download/download_manager_impl_unittest.cc
@@ -6,12 +6,14 @@
#include <stddef.h>
#include <stdint.h>
+
#include <set>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
@@ -37,7 +39,6 @@
#include "content/public/test/mock_download_item.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread.h"
-#include "net/base/net_util.h"
#include "net/log/net_log.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
@@ -50,6 +51,7 @@ using ::testing::Eq;
using ::testing::Ref;
using ::testing::Return;
using ::testing::ReturnRef;
+using ::testing::ReturnRefOfCopy;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
using ::testing::_;
@@ -76,26 +78,27 @@ class MockDownloadItemImpl : public DownloadItemImpl {
public:
// Use history constructor for minimal base object.
explicit MockDownloadItemImpl(DownloadItemImplDelegate* delegate)
- : DownloadItemImpl(
- delegate,
- content::DownloadItem::kInvalidId,
- base::FilePath(),
- base::FilePath(),
- std::vector<GURL>(),
- GURL(),
- "application/octet-stream",
- "application/octet-stream",
- base::Time(),
- base::Time(),
- std::string(),
- std::string(),
- 0,
- 0,
- DownloadItem::COMPLETE,
- DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
- DOWNLOAD_INTERRUPT_REASON_NONE,
- false,
- net::BoundNetLog()) {}
+ : DownloadItemImpl(delegate,
+ std::string("7d122682-55b5-4a47-a253-36cadc3e5bee"),
+ content::DownloadItem::kInvalidId,
+ base::FilePath(),
+ base::FilePath(),
+ std::vector<GURL>(),
+ GURL(),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time(),
+ base::Time(),
+ std::string(),
+ std::string(),
+ 0,
+ 0,
+ std::string(),
+ DownloadItem::COMPLETE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_NONE,
+ false,
+ net::BoundNetLog()) {}
virtual ~MockDownloadItemImpl() {}
MOCK_METHOD4(OnDownloadTargetDetermined,
@@ -114,10 +117,13 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_METHOD3(UpdateProgress, void(int64_t, int64_t, const std::string&));
MOCK_METHOD1(Cancel, void(bool));
MOCK_METHOD0(MarkAsComplete, void());
- MOCK_METHOD1(OnAllDataSaved, void(const std::string&));
+ void OnAllDataSaved(int64_t, scoped_ptr<crypto::SecureHash>) override {
+ NOTREACHED();
+ }
MOCK_METHOD0(OnDownloadedFileRemoved, void());
void Start(scoped_ptr<DownloadFile> download_file,
- scoped_ptr<DownloadRequestHandleInterface> req_handle) override {
+ scoped_ptr<DownloadRequestHandleInterface> req_handle,
+ const DownloadCreateInfo& create_info) override {
MockStart(download_file.get(), req_handle.get());
}
@@ -153,6 +159,7 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_CONST_METHOD0(GetHashState, const std::string&());
MOCK_CONST_METHOD0(GetHash, const std::string&());
MOCK_CONST_METHOD0(GetId, uint32_t());
+ MOCK_CONST_METHOD0(GetGuid, const std::string&());
MOCK_CONST_METHOD0(GetStartTime, base::Time());
MOCK_CONST_METHOD0(GetEndTime, base::Time());
MOCK_METHOD0(GetDownloadManager, DownloadManager*());
@@ -199,7 +206,6 @@ class MockDownloadManagerDelegate : public DownloadManagerDelegate {
bool(DownloadItem*, const base::Closure&));
MOCK_METHOD2(ShouldOpenDownload,
bool(DownloadItem*, const DownloadOpenDelayedCallback&));
- MOCK_METHOD0(GenerateFileHash, bool());
MOCK_METHOD4(GetSaveDir, void(BrowserContext*,
base::FilePath*, base::FilePath*, bool*));
MOCK_METHOD5(ChooseSavePath, void(
@@ -237,6 +243,7 @@ class MockDownloadItemFactory
// Overridden methods from DownloadItemFactory.
DownloadItemImpl* CreatePersistedItem(
DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t download_id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -250,6 +257,7 @@ class MockDownloadItemFactory
const std::string& last_modofied,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
@@ -304,6 +312,7 @@ void MockDownloadItemFactory::RemoveItem(int id) {
DownloadItemImpl* MockDownloadItemFactory::CreatePersistedItem(
DownloadItemImplDelegate* delegate,
+ const std::string& guid,
uint32_t download_id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -317,6 +326,7 @@ DownloadItemImpl* MockDownloadItemFactory::CreatePersistedItem(
const std::string& last_modified,
int64_t received_bytes,
int64_t total_bytes,
+ const std::string& hash,
DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
@@ -327,6 +337,7 @@ DownloadItemImpl* MockDownloadItemFactory::CreatePersistedItem(
new StrictMock<MockDownloadItemImpl>(&item_delegate_);
EXPECT_CALL(*result, GetId())
.WillRepeatedly(Return(download_id));
+ EXPECT_CALL(*result, GetGuid()).WillRepeatedly(ReturnRefOfCopy(guid));
items_[download_id] = result;
return result;
}
@@ -342,6 +353,9 @@ DownloadItemImpl* MockDownloadItemFactory::CreateActiveItem(
new StrictMock<MockDownloadItemImpl>(&item_delegate_);
EXPECT_CALL(*result, GetId())
.WillRepeatedly(Return(download_id));
+ EXPECT_CALL(*result, GetGuid())
+ .WillRepeatedly(
+ ReturnRefOfCopy(base::ToUpperASCII(base::GenerateGUID())));
items_[download_id] = result;
// Active items are created and then immediately are called to start
@@ -378,32 +392,24 @@ class MockDownloadFileFactory
virtual ~MockDownloadFileFactory() {}
// Overridden method from DownloadFileFactory
- MOCK_METHOD8(MockCreateFile, MockDownloadFile*(
- const DownloadSaveInfo&,
- const base::FilePath&,
- const GURL&, const GURL&, bool,
- ByteStreamReader*,
- const net::BoundNetLog&,
- base::WeakPtr<DownloadDestinationObserver>));
+ MOCK_METHOD2(MockCreateFile,
+ MockDownloadFile*(const DownloadSaveInfo&, ByteStreamReader*));
virtual DownloadFile* CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
- const GURL& url,
- const GURL& referrer_url,
- bool calculate_hash,
- scoped_ptr<ByteStreamReader> stream,
+ scoped_ptr<ByteStreamReader> byte_stream,
const net::BoundNetLog& bound_net_log,
- base::WeakPtr<DownloadDestinationObserver> observer) {
- return MockCreateFile(*save_info.get(), default_download_directory, url,
- referrer_url, calculate_hash,
- stream.get(), bound_net_log, observer);
+ base::WeakPtr<DownloadDestinationObserver> observer) override {
+ return MockCreateFile(*save_info, byte_stream.get());
}
};
class MockBrowserContext : public BrowserContext {
public:
- MockBrowserContext() {}
+ MockBrowserContext() {
+ content::BrowserContext::Initialize(this, base::FilePath());
+ }
~MockBrowserContext() {}
MOCK_CONST_METHOD0(GetPath, base::FilePath());
@@ -411,8 +417,6 @@ class MockBrowserContext : public BrowserContext {
ZoomLevelDelegate*(const base::FilePath&));
MOCK_CONST_METHOD0(IsOffTheRecord, bool());
MOCK_METHOD0(GetRequestContext, net::URLRequestContextGetter*());
- MOCK_METHOD1(GetRequestContextForRenderProcess,
- net::URLRequestContextGetter*(int renderer_child_id));
MOCK_METHOD0(GetMediaRequestContext,
net::URLRequestContextGetter*());
MOCK_METHOD1(GetMediaRequestContextForRenderProcess,
@@ -429,6 +433,23 @@ class MockBrowserContext : public BrowserContext {
MOCK_METHOD0(GetPermissionManager, PermissionManager*());
MOCK_METHOD0(GetBackgroundSyncController, BackgroundSyncController*());
+ // Define these two methods to avoid a
+ // cannot access private member declared in class 'ScopedVector<net::URLRequestInterceptor>'
+ // build error if they're put in MOCK_METHOD.
+ net::URLRequestContextGetter* CreateRequestContext(
+ ProtocolHandlerMap* protocol_handlers,
+ URLRequestInterceptorScopedVector request_interceptors) override {
+ return nullptr;
+ }
+
+ net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+ const base::FilePath& partition_path,
+ bool in_memory,
+ ProtocolHandlerMap* protocol_handlers,
+ URLRequestInterceptorScopedVector request_interceptors) override {
+ return nullptr;
+ }
+
scoped_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
const base::FilePath& path) override {
return scoped_ptr<ZoomLevelDelegate>(CreateZoomLevelDelegateMock(path));
@@ -445,6 +466,14 @@ class MockDownloadManagerObserver : public DownloadManager::Observer {
MOCK_METHOD2(SelectFileDialogDisplayed, void(DownloadManager*, int32_t));
};
+class MockByteStreamReader : public ByteStreamReader {
+ public:
+ virtual ~MockByteStreamReader() {}
+ MOCK_METHOD2(Read, StreamState(scoped_refptr<net::IOBuffer>*, size_t*));
+ MOCK_CONST_METHOD0(GetStatus, int());
+ MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
+};
+
} // namespace
class DownloadManagerTest : public testing::Test {
@@ -529,7 +558,7 @@ class DownloadManagerTest : public testing::Test {
// we call Start on it immediately, so we need to set that expectation
// in the factory.
scoped_ptr<DownloadRequestHandleInterface> req_handle;
- item.Start(scoped_ptr<DownloadFile>(), std::move(req_handle));
+ item.Start(scoped_ptr<DownloadFile>(), std::move(req_handle), info);
DCHECK(id < download_urls_.size());
EXPECT_CALL(item, GetURL()).WillRepeatedly(ReturnRef(download_urls_[id]));
@@ -605,7 +634,7 @@ class DownloadManagerTest : public testing::Test {
// Confirm the appropriate invocations occur when you start a download.
TEST_F(DownloadManagerTest, StartDownload) {
scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo);
- scoped_ptr<ByteStreamReader> stream;
+ scoped_ptr<ByteStreamReader> stream(new MockByteStreamReader);
uint32_t local_id(5); // Random value
base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
@@ -618,16 +647,12 @@ TEST_F(DownloadManagerTest, StartDownload) {
// Doing nothing will set the default download directory to null.
EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _, _));
- EXPECT_CALL(GetMockDownloadManagerDelegate(), GenerateFileHash())
- .WillOnce(Return(true));
EXPECT_CALL(GetMockDownloadManagerDelegate(),
ApplicationClientIdForFileScanning())
.WillRepeatedly(Return("client-id"));
MockDownloadFile* mock_file = new MockDownloadFile;
- EXPECT_CALL(*mock_file, SetClientGuid("client-id"));
EXPECT_CALL(*mock_download_file_factory_.get(),
- MockCreateFile(Ref(*info->save_info.get()), _, _, _, true,
- stream.get(), _, _))
+ MockCreateFile(Ref(*info->save_info.get()), stream.get()))
.WillOnce(Return(mock_file));
download_manager_->StartDownload(std::move(info), std::move(stream),
@@ -707,8 +732,53 @@ TEST_F(DownloadManagerTest, RemoveAllDownloads) {
// result in them being removed from the DownloadManager list.
}
-// Confirm that only downloads with same origin are removed.
-TEST_F(DownloadManagerTest, RemoveSameOriginDownloads) {
+TEST_F(DownloadManagerTest, GetDownloadByGuid) {
+ for (uint32_t i = 0; i < 4; ++i)
+ AddItemToManager();
+
+ MockDownloadItemImpl& item = GetMockDownloadItem(0);
+ DownloadItem* result = download_manager_->GetDownloadByGuid(item.GetGuid());
+ ASSERT_TRUE(result);
+ ASSERT_EQ(static_cast<DownloadItem*>(&item), result);
+
+ ASSERT_FALSE(download_manager_->GetDownloadByGuid(""));
+
+ const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
+ DownloadItem* persisted_item = download_manager_->CreateDownloadItem(
+ kGuid,
+ 10,
+ base::FilePath(),
+ base::FilePath(),
+ std::vector<GURL>(),
+ GURL("http://example.com/a"),
+ "application/octet-stream",
+ "application/octet-stream",
+ base::Time::Now(),
+ base::Time::Now(),
+ std::string(),
+ std::string(),
+ 10,
+ 10,
+ std::string(),
+ DownloadItem::INTERRUPTED,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED,
+ false);
+ ASSERT_TRUE(persisted_item);
+
+ ASSERT_EQ(persisted_item, download_manager_->GetDownloadByGuid(kGuid));
+}
+
+namespace {
+
+base::Callback<bool(const GURL&)> GetSingleURLFilter(const GURL& url) {
+ return base::Bind(&GURL::operator==, base::Owned(new GURL(url)));
+}
+
+} // namespace
+
+// Confirm that only downloads with the specified URL are removed.
+TEST_F(DownloadManagerTest, RemoveDownloadsByURL) {
base::Time now(base::Time::Now());
for (uint32_t i = 0; i < 2; ++i) {
MockDownloadItemImpl& item(AddItemToManager());
@@ -720,9 +790,10 @@ TEST_F(DownloadManagerTest, RemoveSameOriginDownloads) {
EXPECT_CALL(GetMockDownloadItem(0), Remove());
EXPECT_CALL(GetMockDownloadItem(1), Remove()).Times(0);
- url::Origin origin_to_clear(download_urls_[0]);
- int remove_count = download_manager_->RemoveDownloadsByOriginAndTime(
- origin_to_clear, base::Time(), base::Time::Max());
+ base::Callback<bool(const GURL&)> url_filter =
+ GetSingleURLFilter(download_urls_[0]);
+ int remove_count = download_manager_->RemoveDownloadsByURLAndTime(
+ url_filter, base::Time(), base::Time::Max());
EXPECT_EQ(remove_count, 1);
}
diff --git a/chromium/content/browser/download/download_net_log_parameters.cc b/chromium/content/browser/download/download_net_log_parameters.cc
index e81c813af2f..110bc98c3b0 100644
--- a/chromium/content/browser/download/download_net_log_parameters.cc
+++ b/chromium/content/browser/download/download_net_log_parameters.cc
@@ -89,14 +89,11 @@ scoped_ptr<base::Value> ItemRenamedNetLogCallback(
scoped_ptr<base::Value> ItemInterruptedNetLogCallback(
DownloadInterruptReason reason,
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
- dict->SetString("hash_state",
- base::HexEncode(hash_state->data(), hash_state->size()));
return std::move(dict);
}
@@ -105,15 +102,12 @@ scoped_ptr<base::Value> ItemResumingNetLogCallback(
bool user_initiated,
DownloadInterruptReason reason,
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("user_initiated", user_initiated ? "true" : "false");
dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
- dict->SetString("hash_state",
- base::HexEncode(hash_state->data(), hash_state->size()));
return std::move(dict);
}
@@ -143,13 +137,10 @@ scoped_ptr<base::Value> ItemFinishedNetLogCallback(
scoped_ptr<base::Value> ItemCanceledNetLogCallback(
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
- dict->SetString("hash_state",
- base::HexEncode(hash_state->data(), hash_state->size()));
return std::move(dict);
}
diff --git a/chromium/content/browser/download/download_net_log_parameters.h b/chromium/content/browser/download/download_net_log_parameters.h
index 2f4b6a006e5..b10a345ed33 100644
--- a/chromium/content/browser/download/download_net_log_parameters.h
+++ b/chromium/content/browser/download/download_net_log_parameters.h
@@ -50,7 +50,6 @@ scoped_ptr<base::Value> ItemRenamedNetLogCallback(
scoped_ptr<base::Value> ItemInterruptedNetLogCallback(
DownloadInterruptReason reason,
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is resumed.
@@ -58,7 +57,6 @@ scoped_ptr<base::Value> ItemResumingNetLogCallback(
bool user_initiated,
DownloadInterruptReason reason,
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadItem is completing.
@@ -75,7 +73,6 @@ scoped_ptr<base::Value> ItemFinishedNetLogCallback(
// Returns NetLog parameters when a DownloadItem is canceled.
scoped_ptr<base::Value> ItemCanceledNetLogCallback(
int64_t bytes_so_far,
- const std::string* hash_state,
net::NetLogCaptureMode capture_mode);
// Returns NetLog parameters when a DownloadFile is opened.
diff --git a/chromium/content/browser/download/download_request_core.cc b/chromium/content/browser/download/download_request_core.cc
index 072ba7b0b55..3f70e956baa 100644
--- a/chromium/content/browser/download/download_request_core.cc
+++ b/chromium/content/browser/download/download_request_core.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/format_macros.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -21,41 +22,197 @@
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/download/download_request_handle.h"
#include "content/browser/download/download_stats.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager_delegate.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/power_save_blocker.h"
+#include "content/public/browser/resource_context.h"
#include "content/public/browser/web_contents.h"
+#include "net/base/elements_upload_data_stream.h"
#include "net/base/io_buffer.h"
+#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/base/upload_bytes_element_reader.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_request_context.h"
namespace content {
+namespace {
+
+// This is a UserData::Data that will be attached to a URLRequest as a
+// side-channel for passing download parameters.
+class DownloadRequestData : public base::SupportsUserData::Data {
+ public:
+ ~DownloadRequestData() override {}
+
+ static void Attach(net::URLRequest* request,
+ DownloadUrlParameters* download_parameters,
+ uint32_t download_id);
+ static DownloadRequestData* Get(net::URLRequest* request);
+ static void Detach(net::URLRequest* request);
+
+ scoped_ptr<DownloadSaveInfo> TakeSaveInfo() { return std::move(save_info_); }
+ uint32_t download_id() const { return download_id_; }
+ const DownloadUrlParameters::OnStartedCallback& callback() const {
+ return on_started_callback_;
+ }
+
+ private:
+ static const int kKey;
+
+ scoped_ptr<DownloadSaveInfo> save_info_;
+ uint32_t download_id_ = DownloadItem::kInvalidId;
+ DownloadUrlParameters::OnStartedCallback on_started_callback_;
+};
+
+// static
+const int DownloadRequestData::kKey = 0;
+
+// static
+void DownloadRequestData::Attach(net::URLRequest* request,
+ DownloadUrlParameters* parameters,
+ uint32_t download_id) {
+ DownloadRequestData* request_data = new DownloadRequestData;
+ request_data->save_info_.reset(
+ new DownloadSaveInfo(parameters->GetSaveInfo()));
+ request_data->download_id_ = download_id;
+ request_data->on_started_callback_ = parameters->callback();
+ request->SetUserData(&kKey, request_data);
+}
+
+// static
+DownloadRequestData* DownloadRequestData::Get(net::URLRequest* request) {
+ return static_cast<DownloadRequestData*>(request->GetUserData(&kKey));
+}
+
+// static
+void DownloadRequestData::Detach(net::URLRequest* request) {
+ request->RemoveUserData(&kKey);
+}
+
+} // namespace
+
const int DownloadRequestCore::kDownloadByteStreamSize = 100 * 1024;
-DownloadRequestCore::DownloadRequestCore(
- net::URLRequest* request,
- scoped_ptr<DownloadSaveInfo> save_info,
- const base::Closure& on_ready_to_read_callback)
- : on_ready_to_read_callback_(on_ready_to_read_callback),
+// static
+scoped_ptr<net::URLRequest> DownloadRequestCore::CreateRequestOnIOThread(
+ uint32_t download_id,
+ DownloadUrlParameters* params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(download_id == DownloadItem::kInvalidId ||
+ !params->content_initiated())
+ << "Content initiated downloads shouldn't specify a download ID";
+
+ // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and
+ // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so
+ // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4.
+ scoped_ptr<net::URLRequest> request(
+ params->resource_context()->GetRequestContext()->CreateRequest(
+ params->url(), net::DEFAULT_PRIORITY, nullptr));
+ request->set_method(params->method());
+
+ if (!params->post_body().empty()) {
+ const std::string& body = params->post_body();
+ scoped_ptr<net::UploadElementReader> reader(
+ net::UploadOwnedBytesElementReader::CreateWithString(body));
+ request->set_upload(
+ net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
+ }
+
+ if (params->post_id() >= 0) {
+ // The POST in this case does not have an actual body, and only works
+ // when retrieving data from cache. This is done because we don't want
+ // to do a re-POST without user consent, and currently don't have a good
+ // plan on how to display the UI for that.
+ DCHECK(params->prefer_cache());
+ DCHECK_EQ("POST", params->method());
+ std::vector<scoped_ptr<net::UploadElementReader>> element_readers;
+ request->set_upload(make_scoped_ptr(new net::ElementsUploadDataStream(
+ std::move(element_readers), params->post_id())));
+ }
+
+ int load_flags = request->load_flags();
+ if (params->prefer_cache()) {
+ // If there is upload data attached, only retrieve from cache because there
+ // is no current mechanism to prompt the user for their consent for a
+ // re-post. For GETs, try to retrieve data from the cache and skip
+ // validating the entry if present.
+ if (request->get_upload())
+ load_flags |= net::LOAD_ONLY_FROM_CACHE;
+ else
+ load_flags |= net::LOAD_PREFERRING_CACHE;
+ } else {
+ load_flags |= net::LOAD_DISABLE_CACHE;
+ }
+ request->SetLoadFlags(load_flags);
+
+ bool has_last_modified = !params->last_modified().empty();
+ bool has_etag = !params->etag().empty();
+
+ // If we've asked for a range, we want to make sure that we only get that
+ // range if our current copy of the information is good. We shouldn't be
+ // asked to continue if we don't have a verifier.
+ DCHECK(params->offset() == 0 || has_etag || has_last_modified);
+
+ // If we're not at the beginning of the file, retrieve only the remaining
+ // portion.
+ if (params->offset() > 0 && (has_etag || has_last_modified)) {
+ request->SetExtraRequestHeaderByName(
+ "Range", base::StringPrintf("bytes=%" PRId64 "-", params->offset()),
+ true);
+
+ // In accordance with RFC 2616 Section 14.27, use If-Range to specify that
+ // the server return the entire entity if the validator doesn't match.
+ // Last-Modified can be used in the absence of ETag as a validator if the
+ // response headers satisfied the HttpUtil::HasStrongValidators() predicate.
+ //
+ // This function assumes that HasStrongValidators() was true and that the
+ // ETag and Last-Modified header values supplied are valid.
+ request->SetExtraRequestHeaderByName(
+ "If-Range", has_etag ? params->etag() : params->last_modified(), true);
+ }
+
+ for (const auto& header : params->request_headers())
+ request->SetExtraRequestHeaderByName(header.first, header.second,
+ false /*overwrite*/);
+
+ DownloadRequestData::Attach(request.get(), std::move(params), download_id);
+ return request;
+}
+
+DownloadRequestCore::DownloadRequestCore(net::URLRequest* request,
+ Delegate* delegate)
+ : delegate_(delegate),
request_(request),
- save_info_(std::move(save_info)),
+ download_id_(DownloadItem::kInvalidId),
last_buffer_size_(0),
bytes_read_(0),
pause_count_(0),
- was_deferred_(false) {
+ was_deferred_(false),
+ is_partial_request_(false),
+ started_(false),
+ abort_reason_(DOWNLOAD_INTERRUPT_REASON_NONE) {
DCHECK(request_);
- DCHECK(save_info_);
- DCHECK(!on_ready_to_read_callback_.is_null());
+ DCHECK(delegate_);
RecordDownloadCount(UNTHROTTLED_COUNT);
power_save_blocker_ = PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
PowerSaveBlocker::kReasonOther, "Download in progress");
+ DownloadRequestData* request_data = DownloadRequestData::Get(request_);
+ if (request_data) {
+ save_info_ = request_data->TakeSaveInfo();
+ download_id_ = request_data->download_id();
+ on_started_callback_ = request_data->callback();
+ DownloadRequestData::Detach(request_);
+ is_partial_request_ = save_info_->offset > 0;
+ } else {
+ save_info_.reset(new DownloadSaveInfo);
+ }
}
DownloadRequestCore::~DownloadRequestCore() {
@@ -68,15 +225,41 @@ DownloadRequestCore::~DownloadRequestCore() {
base::TimeTicks::Now() - download_start_time_);
}
-// Send the download creation information to the download thread.
-void DownloadRequestCore::OnResponseStarted(
- scoped_ptr<DownloadCreateInfo>* create_info,
- scoped_ptr<ByteStreamReader>* stream_reader) {
+scoped_ptr<DownloadCreateInfo> DownloadRequestCore::CreateDownloadCreateInfo(
+ DownloadInterruptReason result) {
+ DCHECK(!started_);
+ started_ = true;
+ scoped_ptr<DownloadCreateInfo> create_info(new DownloadCreateInfo(
+ base::Time::Now(), request()->net_log(), std::move(save_info_)));
+
+ if (result == DOWNLOAD_INTERRUPT_REASON_NONE)
+ create_info->remote_address = request()->GetSocketAddress().host();
+ create_info->url_chain = request()->url_chain();
+ create_info->referrer_url = GURL(request()->referrer());
+ create_info->result = result;
+ create_info->download_id = download_id_;
+ return create_info;
+}
+
+bool DownloadRequestCore::OnResponseStarted(
+ const std::string& override_mime_type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(save_info_);
DVLOG(20) << __FUNCTION__ << "()" << DebugString();
download_start_time_ = base::TimeTicks::Now();
+ DownloadInterruptReason result =
+ request()->response_headers()
+ ? HandleSuccessfulServerResponse(*request()->response_headers(),
+ save_info_.get())
+ : DOWNLOAD_INTERRUPT_REASON_NONE;
+
+ scoped_ptr<DownloadCreateInfo> create_info = CreateDownloadCreateInfo(result);
+ if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
+ delegate_->OnStart(std::move(create_info), scoped_ptr<ByteStreamReader>(),
+ base::ResetAndReturn(&on_started_callback_));
+ return false;
+ }
+
// If it's a download, we don't want to poison the cache with it.
request()->StopCaching();
@@ -90,35 +273,21 @@ void DownloadRequestCore::OnResponseStarted(
int64_t content_length = request()->GetExpectedContentSize() > 0
? request()->GetExpectedContentSize()
: 0;
-
- // Deleted in DownloadManager.
- scoped_ptr<DownloadCreateInfo> info(
- new DownloadCreateInfo(base::Time::Now(), content_length,
- request()->net_log(), std::move(save_info_)));
+ create_info->total_bytes = content_length;
// Create the ByteStream for sending data to the download sink.
+ scoped_ptr<ByteStreamReader> stream_reader;
CreateByteStream(
base::ThreadTaskRunnerHandle::Get(),
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
- kDownloadByteStreamSize, &stream_writer_, stream_reader);
+ kDownloadByteStreamSize, &stream_writer_, &stream_reader);
stream_writer_->RegisterCallback(
base::Bind(&DownloadRequestCore::ResumeRequest, AsWeakPtr()));
- info->url_chain = request()->url_chain();
- info->referrer_url = GURL(request()->referrer());
- string mime_type;
- request()->GetMimeType(&mime_type);
- info->mime_type = mime_type;
- info->remote_address = request()->GetSocketAddress().host();
- if (request()->response_headers()) {
- // Grab the first content-disposition header. There may be more than one,
- // though as of this writing, the network stack ensures if there are, they
- // are all duplicates.
- request()->response_headers()->EnumerateHeader(
- nullptr, "Content-Disposition", &info->content_disposition);
- }
- RecordDownloadMimeType(info->mime_type);
- RecordDownloadContentDisposition(info->content_disposition);
+ if (!override_mime_type.empty())
+ create_info->mime_type = override_mime_type;
+ else
+ request()->GetMimeType(&create_info->mime_type);
// Get the last modified time and etag.
const net::HttpResponseHeaders* headers = request()->response_headers();
@@ -127,33 +296,49 @@ void DownloadRequestCore::OnResponseStarted(
// If we don't have strong validators as per RFC 2616 section 13.3.3, then
// we neither store nor use them for range requests.
if (!headers->EnumerateHeader(nullptr, "Last-Modified",
- &info->last_modified))
- info->last_modified.clear();
- if (!headers->EnumerateHeader(nullptr, "ETag", &info->etag))
- info->etag.clear();
+ &create_info->last_modified))
+ create_info->last_modified.clear();
+ if (!headers->EnumerateHeader(nullptr, "ETag", &create_info->etag))
+ create_info->etag.clear();
}
- int status = headers->response_code();
- if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) {
- // Success & not range response; if we asked for a range, we didn't
- // get it--reset the file pointers to reflect that.
- info->save_info->offset = 0;
- info->save_info->hash_state = "";
- }
+ // Grab the first content-disposition header. There may be more than one,
+ // though as of this writing, the network stack ensures if there are, they
+ // are all duplicates.
+ headers->EnumerateHeader(nullptr, "Content-Disposition",
+ &create_info->content_disposition);
- if (!headers->GetMimeType(&info->original_mime_type))
- info->original_mime_type.clear();
+ if (!headers->GetMimeType(&create_info->original_mime_type))
+ create_info->original_mime_type.clear();
}
// Blink verifies that the requester of this download is allowed to set a
- // suggested name for the security origin of the downlaod URL. However, this
+ // suggested name for the security origin of the download URL. However, this
// assumption doesn't hold if there were cross origin redirects. Therefore,
// clear the suggested_name for such requests.
- if (info->url_chain.size() > 1 &&
- info->url_chain.front().GetOrigin() != info->url_chain.back().GetOrigin())
- info->save_info->suggested_name.clear();
+ if (create_info->url_chain.size() > 1 &&
+ create_info->url_chain.front().GetOrigin() !=
+ create_info->url_chain.back().GetOrigin())
+ create_info->save_info->suggested_name.clear();
+
+ RecordDownloadMimeType(create_info->mime_type);
+ RecordDownloadContentDisposition(create_info->content_disposition);
+
+ delegate_->OnStart(std::move(create_info), std::move(stream_reader),
+ base::ResetAndReturn(&on_started_callback_));
+ return true;
+}
- info.swap(*create_info);
+bool DownloadRequestCore::OnRequestRedirected() {
+ DVLOG(20) << __FUNCTION__ << "() " << DebugString();
+ if (is_partial_request_) {
+ // A redirect while attempting a partial resumption indicates a potential
+ // middle box. Trigger another interruption so that the DownloadItem can
+ // retry.
+ abort_reason_ = DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE;
+ return false;
+ }
+ return true;
}
// Create a new buffer, which will be handed to the download thread for file
@@ -212,7 +397,13 @@ bool DownloadRequestCore::OnReadCompleted(int bytes_read, bool* defer) {
return true;
}
-DownloadInterruptReason DownloadRequestCore::OnResponseCompleted(
+void DownloadRequestCore::OnWillAbort(DownloadInterruptReason reason) {
+ DVLOG(20) << __FUNCTION__ << "() reason=" << reason << " " << DebugString();
+ DCHECK(!started_);
+ abort_reason_ = reason;
+}
+
+void DownloadRequestCore::OnResponseCompleted(
const net::URLRequestStatus& status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
int response_code = status.is_success() ? request()->GetResponseCode() : 0;
@@ -221,80 +412,27 @@ DownloadInterruptReason DownloadRequestCore::OnResponseCompleted(
<< " status.error() = " << status.error()
<< " response_code = " << response_code;
- net::Error error_code = net::OK;
- if (status.status() == net::URLRequestStatus::FAILED ||
- // Note cancels as failures too.
- status.status() == net::URLRequestStatus::CANCELED) {
- error_code = static_cast<net::Error>(status.error()); // Normal case.
- // Make sure that at least the fact of failure comes through.
- if (error_code == net::OK)
- error_code = net::ERR_FAILED;
- }
-
- // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
- // allowed since a number of servers in the wild close the connection too
- // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
- // treat downloads as complete in both cases, so we follow their lead.
- if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH ||
- error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) {
- error_code = net::OK;
- }
- DownloadInterruptReason reason = ConvertNetErrorToInterruptReason(
- error_code, DOWNLOAD_INTERRUPT_FROM_NETWORK);
-
- if (status.status() == net::URLRequestStatus::CANCELED &&
- status.error() == net::ERR_ABORTED) {
- // CANCELED + ERR_ABORTED == something outside of the network
- // stack cancelled the request. There aren't that many things that
- // could do this to a download request (whose lifetime is separated from
- // the tab from which it came). We map this to USER_CANCELLED as the
- // case we know about (system suspend because of laptop close) corresponds
- // to a user action.
- // TODO(ahendrickson) -- Find a better set of codes to use here, as
- // CANCELED/ERR_ABORTED can occur for reasons other than user cancel.
- if (net::IsCertStatusError(request()->ssl_info().cert_status))
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM;
- else
- reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
- }
-
- if (status.is_success() && reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
- request()->response_headers()) {
- // Handle server's response codes.
- switch (response_code) {
- case -1: // Non-HTTP request.
- case net::HTTP_OK:
- case net::HTTP_CREATED:
- case net::HTTP_ACCEPTED:
- case net::HTTP_NON_AUTHORITATIVE_INFORMATION:
- case net::HTTP_RESET_CONTENT:
- case net::HTTP_PARTIAL_CONTENT:
- // Expected successful codes.
- break;
- case net::HTTP_NO_CONTENT:
- case net::HTTP_NOT_FOUND:
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
- break;
- case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
- // Retry by downloading from the start automatically:
- // If we haven't received data when we get this error, we won't.
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE;
- break;
- case net::HTTP_UNAUTHORIZED:
- // Server didn't authorize this request.
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED;
- break;
- case net::HTTP_FORBIDDEN:
- // Server forbids access to this resource.
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN;
- break;
- default: // All other errors.
- // Redirection and informational codes should have been handled earlier
- // in the stack.
- DCHECK_NE(3, response_code / 100);
- DCHECK_NE(1, response_code / 100);
- reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED;
- break;
+ DownloadInterruptReason reason = HandleRequestStatus(status);
+
+ if (status.status() == net::URLRequestStatus::CANCELED) {
+ if (abort_reason_ != DOWNLOAD_INTERRUPT_REASON_NONE) {
+ // If a more specific interrupt reason was specified before the request
+ // was explicitly cancelled, then use it.
+ reason = abort_reason_;
+ } else if (status.error() == net::ERR_ABORTED) {
+ // CANCELED + ERR_ABORTED == something outside of the network
+ // stack cancelled the request. There aren't that many things that
+ // could do this to a download request (whose lifetime is separated from
+ // the tab from which it came). We map this to USER_CANCELLED as the
+ // case we know about (system suspend because of laptop close) corresponds
+ // to a user action.
+ // TODO(asanka): A lid close or other power event should result in an
+ // interruption that doesn't discard the partial state, unlike
+ // USER_CANCELLED. (https://crbug.com/166179)
+ if (net::IsCertStatusError(request()->ssl_info().cert_status))
+ reason = DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM;
+ else
+ reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
}
}
@@ -325,7 +463,16 @@ DownloadInterruptReason DownloadRequestCore::OnResponseCompleted(
stream_writer_.reset(); // We no longer need the stream.
read_buffer_ = nullptr;
- return reason;
+ if (started_)
+ return;
+
+ // OnResponseCompleted() called without OnResponseStarted(). This should only
+ // happen when the request was aborted.
+ DCHECK_NE(reason, DOWNLOAD_INTERRUPT_REASON_NONE);
+ scoped_ptr<DownloadCreateInfo> create_info = CreateDownloadCreateInfo(reason);
+ scoped_ptr<ByteStreamReader> empty_byte_stream;
+ delegate_->OnStart(std::move(create_info), std::move(empty_byte_stream),
+ base::ResetAndReturn(&on_started_callback_));
}
void DownloadRequestCore::PauseRequest() {
@@ -351,16 +498,136 @@ void DownloadRequestCore::ResumeRequest() {
last_stream_pause_time_ = base::TimeTicks();
}
- on_ready_to_read_callback_.Run();
+ delegate_->OnReadyToRead();
}
std::string DownloadRequestCore::DebugString() const {
return base::StringPrintf(
"{"
+ " this=%p "
" url_ = "
"\"%s\""
" }",
+ reinterpret_cast<const void*>(this),
request() ? request()->url().spec().c_str() : "<NULL request>");
}
+// static
+DownloadInterruptReason DownloadRequestCore::HandleRequestStatus(
+ const net::URLRequestStatus& status) {
+ net::Error error_code = net::OK;
+ if (status.status() == net::URLRequestStatus::FAILED ||
+ // Note cancels as failures too.
+ status.status() == net::URLRequestStatus::CANCELED) {
+ error_code = static_cast<net::Error>(status.error()); // Normal case.
+ // Make sure that at least the fact of failure comes through.
+ if (error_code == net::OK)
+ error_code = net::ERR_FAILED;
+ }
+
+ // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
+ // allowed since a number of servers in the wild close the connection too
+ // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
+ // treat downloads as complete in both cases, so we follow their lead.
+ if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH ||
+ error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) {
+ error_code = net::OK;
+ }
+ DownloadInterruptReason reason = ConvertNetErrorToInterruptReason(
+ error_code, DOWNLOAD_INTERRUPT_FROM_NETWORK);
+
+ return reason;
+}
+
+// static
+DownloadInterruptReason DownloadRequestCore::HandleSuccessfulServerResponse(
+ const net::HttpResponseHeaders& http_headers,
+ DownloadSaveInfo* save_info) {
+ switch (http_headers.response_code()) {
+ case -1: // Non-HTTP request.
+ case net::HTTP_OK:
+ case net::HTTP_NON_AUTHORITATIVE_INFORMATION:
+ case net::HTTP_PARTIAL_CONTENT:
+ // Expected successful codes.
+ break;
+
+ case net::HTTP_CREATED:
+ case net::HTTP_ACCEPTED:
+ // Per RFC 2616 the entity being transferred is metadata about the
+ // resource at the target URL and not the resource at that URL (or the
+ // resource that would be at the URL once processing is completed in the
+ // case of HTTP_ACCEPTED). However, we currently don't have special
+ // handling for these response and they are downloaded the same as a
+ // regular response.
+ break;
+
+ case net::HTTP_NO_CONTENT:
+ case net::HTTP_RESET_CONTENT:
+ // These two status codes don't have an entity (or rather RFC 2616
+ // requires that there be no entity). They are treated the same as the
+ // resource not being found since there is no entity to download.
+
+ case net::HTTP_NOT_FOUND:
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
+ break;
+
+ case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
+ // Retry by downloading from the start automatically:
+ // If we haven't received data when we get this error, we won't.
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE;
+ break;
+ case net::HTTP_UNAUTHORIZED:
+ case net::HTTP_PROXY_AUTHENTICATION_REQUIRED:
+ // Server didn't authorize this request.
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED;
+ break;
+ case net::HTTP_FORBIDDEN:
+ // Server forbids access to this resource.
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN;
+ break;
+ default: // All other errors.
+ // Redirection and informational codes should have been handled earlier
+ // in the stack.
+ DCHECK_NE(3, http_headers.response_code() / 100);
+ DCHECK_NE(1, http_headers.response_code() / 100);
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED;
+ }
+
+ if (save_info && save_info->offset > 0) {
+ // The caller is expecting a partial response.
+
+ if (http_headers.response_code() != net::HTTP_PARTIAL_CONTENT) {
+ // Requested a partial range, but received the entire response.
+ save_info->offset = 0;
+ save_info->hash_of_partial_file.clear();
+ save_info->hash_state.reset();
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
+ }
+
+ int64_t first_byte = -1;
+ int64_t last_byte = -1;
+ int64_t length = -1;
+ if (!http_headers.GetContentRange(&first_byte, &last_byte, &length))
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
+ DCHECK_GE(first_byte, 0);
+
+ if (first_byte != save_info->offset) {
+ // The server returned a different range than the one we requested. Assume
+ // the response is bad.
+ //
+ // In the future we should consider allowing offsets that are less than
+ // the offset we've requested, since in theory we can truncate the partial
+ // file at the offset and continue.
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
+ }
+
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
+ }
+
+ if (http_headers.response_code() == net::HTTP_PARTIAL_CONTENT)
+ return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
+
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
+}
+
} // namespace content
diff --git a/chromium/content/browser/download/download_request_core.h b/chromium/content/browser/download/download_request_core.h
index 22ca862ef85..ac9e9b6cd86 100644
--- a/chromium/content/browser/download/download_request_core.h
+++ b/chromium/content/browser/download/download_request_core.h
@@ -20,7 +20,9 @@
#include "content/public/browser/download_url_parameters.h"
namespace net {
+class HttpResponseHeaders;
class URLRequest;
+class URLRequestStatus;
} // namespace net
namespace content {
@@ -38,29 +40,29 @@ struct DownloadCreateInfo;
class CONTENT_EXPORT DownloadRequestCore
: public base::SupportsWeakPtr<DownloadRequestCore> {
public:
- // Size of the buffer used between the DownloadRequestCore and the
- // downstream receiver of its output.
- static const int kDownloadByteStreamSize;
-
- // |request| *must* outlive the DownloadRequestCore. |save_info| must be
- // valid.
- //
- // Invokes |on_ready_to_read_callback| if a previous call to OnReadCompleted()
- // resulted in |defer| being set to true, and DownloadRequestCore is now ready
- // to commence reading.
- DownloadRequestCore(net::URLRequest* request,
- scoped_ptr<DownloadSaveInfo> save_info,
- const base::Closure& on_ready_to_read_callback);
+ class Delegate {
+ public:
+ virtual void OnReadyToRead() = 0;
+ virtual void OnStart(
+ scoped_ptr<DownloadCreateInfo> download_create_info,
+ scoped_ptr<ByteStreamReader> stream_reader,
+ const DownloadUrlParameters::OnStartedCallback& callback) = 0;
+ };
+
+ // All parameters are required. |request| and |delegate| must outlive
+ // DownloadRequestCore.
+ DownloadRequestCore(net::URLRequest* request, Delegate* delegate);
~DownloadRequestCore();
// Should be called when the URLRequest::Delegate receives OnResponseStarted.
- // Constructs a DownloadCreateInfo and a ByteStreamReader that should be
- // passed into DownloadManagerImpl::StartDownload().
- //
- // Only populates the response derived fields of DownloadCreateInfo, with the
- // exception of |save_info|.
- void OnResponseStarted(scoped_ptr<DownloadCreateInfo>* info,
- scoped_ptr<ByteStreamReader>* stream_reader);
+ // Invokes Delegate::OnStart() with download start parameters. The
+ // |override_mime_type| is used as the MIME type for the download when
+ // constructing a DownloadCreateInfo object.
+ bool OnResponseStarted(const std::string& override_mime_type);
+
+ // Should be called to handle a redirect. The caller should only allow the
+ // redirect to be followed if the return value is true.
+ bool OnRequestRedirected();
// Starts a read cycle. Creates a new IOBuffer which can be passed into
// URLRequest::Read(). Call OnReadCompleted() when the Read operation
@@ -69,20 +71,22 @@ class CONTENT_EXPORT DownloadRequestCore
int* buf_size,
int min_size);
+ // Used to notify DownloadRequestCore that the caller is about to abort the
+ // outer request. |reason| will be used as the final interrupt reason when
+ // OnResponseCompleted() is called.
+ void OnWillAbort(DownloadInterruptReason reason);
+
// Should be called when the Read() operation completes. |defer| will be set
// to true if reading is to be suspended. In the latter case, once more data
// can be read, invokes the |on_ready_to_read_callback|.
bool OnReadCompleted(int bytes_read, bool* defer);
- // Called to signal that the response is complete. If the return value is
- // something other than DOWNLOAD_INTERRUPT_REASON_NONE, then the download
- // should be considered interrupted.
+ // Called to signal that the response is complete.
//
// It is expected that once this method is invoked, the DownloadRequestCore
// object will be destroyed in short order without invoking any other methods
// other than the destructor.
- DownloadInterruptReason OnResponseCompleted(
- const net::URLRequestStatus& status);
+ void OnResponseCompleted(const net::URLRequestStatus& status);
// Called if the request should suspend reading. A subsequent
// OnReadCompleted() will result in |defer| being set to true.
@@ -98,13 +102,36 @@ class CONTENT_EXPORT DownloadRequestCore
std::string DebugString() const;
+ static scoped_ptr<net::URLRequest> CreateRequestOnIOThread(
+ uint32_t download_id,
+ DownloadUrlParameters* params);
+
+ // Size of the buffer used between the DownloadRequestCore and the
+ // downstream receiver of its output.
+ static const int kDownloadByteStreamSize;
+
protected:
net::URLRequest* request() const { return request_; }
private:
- base::Closure on_ready_to_read_callback_;
+ static DownloadInterruptReason HandleRequestStatus(
+ const net::URLRequestStatus& status);
+
+ static DownloadInterruptReason HandleSuccessfulServerResponse(
+ const net::HttpResponseHeaders& http_headers,
+ DownloadSaveInfo* save_info);
+
+ scoped_ptr<DownloadCreateInfo> CreateDownloadCreateInfo(
+ DownloadInterruptReason result);
+
+ Delegate* delegate_;
net::URLRequest* request_;
+
+ // "Passthrough" fields. These are only kept here so that they can be used to
+ // populate the DownloadCreateInfo when the time comes.
scoped_ptr<DownloadSaveInfo> save_info_;
+ uint32_t download_id_;
+ DownloadUrlParameters::OnStartedCallback on_started_callback_;
// Data flow
scoped_refptr<net::IOBuffer> read_buffer_; // From URLRequest.
@@ -125,6 +152,15 @@ class CONTENT_EXPORT DownloadRequestCore
int pause_count_;
bool was_deferred_;
+ bool is_partial_request_;
+ bool started_;
+
+ // When DownloadRequestCore initiates an abort (by blocking a redirect, for
+ // example) it expects to eventually receive a OnResponseCompleted() with a
+ // status indicating that the request was aborted. When this happens, the
+ // interrupt reason in |abort_reason_| will be used instead of USER_CANCELED
+ // which is vague.
+ DownloadInterruptReason abort_reason_;
// Each successful OnWillRead will yield a buffer of this size.
static const int kReadBufSize = 32768; // bytes
diff --git a/chromium/content/browser/download/download_request_handle.cc b/chromium/content/browser/download/download_request_handle.cc
index 67dda4f5029..f5979b945ad 100644
--- a/chromium/content/browser/download/download_request_handle.cc
+++ b/chromium/content/browser/download/download_request_handle.cc
@@ -6,88 +6,39 @@
#include "base/bind.h"
#include "base/strings/stringprintf.h"
-#include "content/browser/frame_host/navigator.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/common/browser_side_navigation_policy.h"
namespace content {
DownloadRequestHandleInterface::~DownloadRequestHandleInterface() {}
+DownloadRequestHandle::DownloadRequestHandle(
+ const DownloadRequestHandle& other) = default;
+
DownloadRequestHandle::~DownloadRequestHandle() {}
-DownloadRequestHandle::DownloadRequestHandle()
- : child_id_(-1),
- render_view_id_(-1),
- request_id_(-1),
- frame_tree_node_id_(-1) {
-}
+DownloadRequestHandle::DownloadRequestHandle() {}
DownloadRequestHandle::DownloadRequestHandle(
const base::WeakPtr<DownloadResourceHandler>& handler,
- int child_id,
- int render_view_id,
- int request_id,
- int frame_tree_node_id)
- : handler_(handler),
- child_id_(child_id),
- render_view_id_(render_view_id),
- request_id_(request_id),
- frame_tree_node_id_(frame_tree_node_id) {
+ const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter)
+ : handler_(handler), web_contents_getter_(web_contents_getter) {
DCHECK(handler_.get());
}
WebContents* DownloadRequestHandle::GetWebContents() const {
- // PlzNavigate: if a FrameTreeNodeId was provided, use it to return the
- // WebContents.
- // TODO(davidben): This logic should be abstracted within the ResourceLoader
- // stack. https://crbug.com/376003
- if (IsBrowserSideNavigationEnabled()) {
- FrameTreeNode* frame_tree_node =
- FrameTreeNode::GloballyFindByID(frame_tree_node_id_);
- if (frame_tree_node) {
- return WebContentsImpl::FromFrameTreeNode(frame_tree_node);
- }
- }
-
- RenderViewHostImpl* render_view_host =
- RenderViewHostImpl::FromID(child_id_, render_view_id_);
- if (!render_view_host)
- return nullptr;
-
- return render_view_host->GetDelegate()->GetAsWebContents();
+ return web_contents_getter_.is_null() ? nullptr : web_contents_getter_.Run();
}
DownloadManager* DownloadRequestHandle::GetDownloadManager() const {
- // PlzNavigate: if a FrameTreeNodeId was provided, use it to return the
- // DownloadManager.
- // TODO(davidben): This logic should be abstracted within the ResourceLoader
- // stack. https://crbug.com/376003
- if (IsBrowserSideNavigationEnabled()) {
- FrameTreeNode* frame_tree_node =
- FrameTreeNode::GloballyFindByID(frame_tree_node_id_);
- if (frame_tree_node) {
- BrowserContext* context =
- frame_tree_node->navigator()->GetController()->GetBrowserContext();
- if (context)
- return BrowserContext::GetDownloadManager(context);
- }
- }
-
- RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(
- child_id_, render_view_id_);
- if (rvh == NULL)
- return NULL;
- RenderProcessHost* rph = rvh->GetProcess();
- if (rph == NULL)
- return NULL;
- BrowserContext* context = rph->GetBrowserContext();
- if (context == NULL)
- return NULL;
+ WebContents* web_contents = GetWebContents();
+ if (web_contents == nullptr)
+ return nullptr;
+ BrowserContext* context = web_contents->GetBrowserContext();
+ if (context == nullptr)
+ return nullptr;
return BrowserContext::GetDownloadManager(context);
}
@@ -109,15 +60,4 @@ void DownloadRequestHandle::CancelRequest() const {
base::Bind(&DownloadResourceHandler::CancelRequest, handler_));
}
-std::string DownloadRequestHandle::DebugString() const {
- return base::StringPrintf("{"
- " child_id = %d"
- " render_view_id = %d"
- " request_id = %d"
- "}",
- child_id_,
- render_view_id_,
- request_id_);
-}
-
} // namespace content
diff --git a/chromium/content/browser/download/download_request_handle.h b/chromium/content/browser/download/download_request_handle.h
index 5d047c75910..090a25bb5a6 100644
--- a/chromium/content/browser/download/download_request_handle.h
+++ b/chromium/content/browser/download/download_request_handle.h
@@ -5,12 +5,11 @@
#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_HANDLE_H_
#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_HANDLE_H_
-#include <string>
-
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/download/download_resource_handler.h"
#include "content/common/content_export.h"
+#include "content/public/browser/resource_request_info.h"
namespace content {
class DownloadManager;
@@ -36,15 +35,13 @@ class CONTENT_EXPORT DownloadRequestHandleInterface {
// Cancels the request.
virtual void CancelRequest() const = 0;
-
- // Describes the object.
- virtual std::string DebugString() const = 0;
};
class CONTENT_EXPORT DownloadRequestHandle
: public DownloadRequestHandleInterface {
public:
+ DownloadRequestHandle(const DownloadRequestHandle& other);
~DownloadRequestHandle() override;
// Create a null DownloadRequestHandle: getters will return null, and
@@ -56,12 +53,9 @@ class CONTENT_EXPORT DownloadRequestHandle
// allowing mocking of ResourceDispatcherHost in unit tests.
DownloadRequestHandle();
- // Note that |rdh| is required to be non-null.
DownloadRequestHandle(const base::WeakPtr<DownloadResourceHandler>& handler,
- int child_id,
- int render_view_id,
- int request_id,
- int frame_tree_node_id);
+ const content::ResourceRequestInfo::WebContentsGetter&
+ web_contents_getter);
// Implement DownloadRequestHandleInterface interface.
WebContents* GetWebContents() const override;
@@ -69,23 +63,10 @@ class CONTENT_EXPORT DownloadRequestHandle
void PauseRequest() const override;
void ResumeRequest() const override;
void CancelRequest() const override;
- std::string DebugString() const override;
private:
base::WeakPtr<DownloadResourceHandler> handler_;
-
- // The ID of the child process that started the download.
- int child_id_;
-
- // The ID of the render view that started the download.
- int render_view_id_;
-
- // The ID associated with the request used for the download.
- int request_id_;
-
- // PlzNavigate
- // The ID of the FrameTreeNode that started the download.
- int frame_tree_node_id_;
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter_;
};
} // namespace content
diff --git a/chromium/content/browser/download/download_resource_handler.cc b/chromium/content/browser/download/download_resource_handler.cc
index e06b3095e99..30a7c8cf029 100644
--- a/chromium/content/browser/download/download_resource_handler.cc
+++ b/chromium/content/browser/download/download_resource_handler.cc
@@ -48,11 +48,11 @@ static void StartOnUIThread(
// NULL in unittests or if the page closed right after starting the
// download.
if (!started_cb.is_null())
- started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
-
- // |stream| gets deleted on non-FILE thread, but it's ok since
- // we're not using stream_writer_ yet.
+ started_cb.Run(nullptr, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
+ if (stream)
+ BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE,
+ stream.release());
return;
}
@@ -83,19 +83,10 @@ void DeleteOnUIThread(
} // namespace
-DownloadResourceHandler::DownloadResourceHandler(
- uint32_t id,
- net::URLRequest* request,
- const DownloadUrlParameters::OnStartedCallback& started_cb,
- scoped_ptr<DownloadSaveInfo> save_info)
+DownloadResourceHandler::DownloadResourceHandler(net::URLRequest* request)
: ResourceHandler(request),
- download_id_(id),
- started_cb_(started_cb),
tab_info_(new DownloadTabInfo()),
- core_(request,
- std::move(save_info),
- base::Bind(&DownloadResourceHandler::OnCoreReadyToRead,
- base::Unretained(this))) {
+ core_(request, this) {
// Do UI thread initialization for tab_info_ asap after
// DownloadResourceHandler creation since the tab could be navigated
// before StartOnUIThread gets called. This is safe because deletion
@@ -104,20 +95,14 @@ DownloadResourceHandler::DownloadResourceHandler(
const ResourceRequestInfoImpl* request_info = GetRequestInfo();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&InitializeDownloadTabInfoOnUIThread,
- DownloadRequestHandle(AsWeakPtr(), request_info->GetChildID(),
- request_info->GetRouteID(),
- request_info->GetRequestID(),
- request_info->frame_tree_node_id()),
- tab_info_.get()));
+ base::Bind(
+ &InitializeDownloadTabInfoOnUIThread,
+ DownloadRequestHandle(AsWeakPtr(),
+ request_info->GetWebContentsGetterForRequest()),
+ tab_info_.get()));
}
DownloadResourceHandler::~DownloadResourceHandler() {
- // This won't do anything if the callback was called before.
- // If it goes through, it will likely be because OnWillStart() returned
- // false somewhere in the chain of resource handlers.
- CallStartedCB(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
-
if (tab_info_) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -129,46 +114,16 @@ bool DownloadResourceHandler::OnRequestRedirected(
const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
- return true;
+ return core_.OnRequestRedirected();
}
// Send the download creation information to the download thread.
bool DownloadResourceHandler::OnResponseStarted(
ResourceResponse* response,
bool* defer) {
- scoped_ptr<DownloadCreateInfo> create_info;
- scoped_ptr<ByteStreamReader> stream_reader;
-
- core_.OnResponseStarted(&create_info, &stream_reader);
-
- const ResourceRequestInfoImpl* request_info = GetRequestInfo();
- create_info->download_id = download_id_;
- create_info->has_user_gesture = request_info->HasUserGesture();
- create_info->transition_type = request_info->GetPageTransition();
- create_info->request_handle.reset(new DownloadRequestHandle(
- AsWeakPtr(), request_info->GetChildID(), request_info->GetRouteID(),
- request_info->GetRequestID(), request_info->frame_tree_node_id()));
-
// The MIME type in ResourceResponse is the product of
// MimeTypeResourceHandler.
- create_info->mime_type = response->head.mime_type;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&StartOnUIThread, base::Passed(&create_info),
- base::Passed(&tab_info_), base::Passed(&stream_reader),
- base::ResetAndReturn(&started_cb_)));
- return true;
-}
-
-void DownloadResourceHandler::CallStartedCB(
- DownloadInterruptReason interrupt_reason) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (started_cb_.is_null())
- return;
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(base::ResetAndReturn(&started_cb_),
- nullptr, interrupt_reason));
+ return core_.OnResponseStarted(response->head.mime_type);
}
bool DownloadResourceHandler::OnWillStart(const GURL& url, bool* defer) {
@@ -197,8 +152,7 @@ void DownloadResourceHandler::OnResponseCompleted(
const net::URLRequestStatus& status,
const std::string& security_info,
bool* defer) {
- DownloadInterruptReason result = core_.OnResponseCompleted(status);
- CallStartedCB(result);
+ core_.OnResponseCompleted(status);
}
void DownloadResourceHandler::OnDataDownloaded(int bytes_downloaded) {
@@ -213,7 +167,36 @@ void DownloadResourceHandler::ResumeRequest() {
core_.ResumeRequest();
}
-void DownloadResourceHandler::OnCoreReadyToRead() {
+void DownloadResourceHandler::OnStart(
+ scoped_ptr<DownloadCreateInfo> create_info,
+ scoped_ptr<ByteStreamReader> stream_reader,
+ const DownloadUrlParameters::OnStartedCallback& callback) {
+ // If the user cancels the download, then don't call start. Instead ignore the
+ // download entirely.
+ if (create_info->result == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED &&
+ create_info->download_id == DownloadItem::kInvalidId) {
+ if (!callback.is_null())
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, nullptr, create_info->result));
+ return;
+ }
+
+ const ResourceRequestInfoImpl* request_info = GetRequestInfo();
+ create_info->has_user_gesture = request_info->HasUserGesture();
+ create_info->transition_type = request_info->GetPageTransition();
+
+ create_info->request_handle.reset(new DownloadRequestHandle(
+ AsWeakPtr(), request_info->GetWebContentsGetterForRequest()));
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&StartOnUIThread, base::Passed(&create_info),
+ base::Passed(&tab_info_), base::Passed(&stream_reader),
+ callback));
+}
+
+void DownloadResourceHandler::OnReadyToRead() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
controller()->Resume();
}
diff --git a/chromium/content/browser/download/download_resource_handler.h b/chromium/content/browser/download/download_resource_handler.h
index 22a10a8a049..b874b9a43bb 100644
--- a/chromium/content/browser/download/download_resource_handler.h
+++ b/chromium/content/browser/download/download_resource_handler.h
@@ -33,17 +33,14 @@ struct DownloadCreateInfo;
// Forwards data to the download thread.
class CONTENT_EXPORT DownloadResourceHandler
: public ResourceHandler,
+ public DownloadRequestCore::Delegate,
public base::SupportsWeakPtr<DownloadResourceHandler> {
public:
struct DownloadTabInfo;
// started_cb will be called exactly once on the UI thread.
// |id| should be invalid if the id should be automatically assigned.
- DownloadResourceHandler(
- uint32_t id,
- net::URLRequest* request,
- const DownloadUrlParameters::OnStartedCallback& started_cb,
- scoped_ptr<DownloadSaveInfo> save_info);
+ DownloadResourceHandler(net::URLRequest* request);
bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
ResourceResponse* response,
@@ -84,18 +81,12 @@ class CONTENT_EXPORT DownloadResourceHandler
private:
~DownloadResourceHandler() override;
- // Arrange for started_cb_ to be called on the UI thread with the
- // below values, nulling out started_cb_. Should only be called
- // on the IO thread.
- void CallStartedCB(DownloadInterruptReason interrupt_reason);
-
- void OnCoreReadyToRead();
-
- uint32_t download_id_;
-
- // This is read only on the IO thread, but may only
- // be called on the UI thread.
- DownloadUrlParameters::OnStartedCallback started_cb_;
+ // DownloadRequestCore::Delegate
+ void OnStart(
+ scoped_ptr<DownloadCreateInfo> download_create_info,
+ scoped_ptr<ByteStreamReader> stream_reader,
+ const DownloadUrlParameters::OnStartedCallback& callback) override;
+ void OnReadyToRead() override;
// Stores information about the download that must be acquired on the UI
// thread before StartOnUIThread is called.
diff --git a/chromium/content/browser/download/drag_download_file.cc b/chromium/content/browser/download/drag_download_file.cc
index afb533a56bf..dc6b89c8b8f 100644
--- a/chromium/content/browser/download/drag_download_file.cc
+++ b/chromium/content/browser/download/drag_download_file.cc
@@ -97,8 +97,8 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
void OnDownloadStarted(DownloadItem* item,
DownloadInterruptReason interrupt_reason) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!item) {
- DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
+ if (!item || item->GetState() != DownloadItem::IN_PROGRESS) {
+ DCHECK(!item || item->GetLastReason() != DOWNLOAD_INTERRUPT_REASON_NONE);
on_completed_loop_->task_runner()->PostTask(
FROM_HERE, base::Bind(on_completed_, false));
return;
diff --git a/chromium/content/browser/download/mhtml_generation_manager.cc b/chromium/content/browser/download/mhtml_generation_manager.cc
index ef9202330d2..623ab53546e 100644
--- a/chromium/content/browser/download/mhtml_generation_manager.cc
+++ b/chromium/content/browser/download/mhtml_generation_manager.cc
@@ -188,9 +188,8 @@ bool MHTMLGenerationManager::Job::SendToNextRenderFrame() {
ipc_params.salt = salt_;
ipc_params.digests_of_uris_to_skip = digests_of_already_serialized_uris_;
- ipc_params.destination_file = IPC::GetFileHandleForProcess(
- browser_file_.GetPlatformFile(), rfh->GetProcess()->GetHandle(),
- false); // |close_source_handle|.
+ ipc_params.destination_file = IPC::GetPlatformFileForTransit(
+ browser_file_.GetPlatformFile(), false); // |close_source_handle|.
ipc_params.frame_routing_id_to_content_id =
CreateFrameRoutingIdToContentId(rfh->GetSiteInstance());
diff --git a/chromium/content/browser/download/mock_download_file.h b/chromium/content/browser/download/mock_download_file.h
index a0020b686c9..7109c44c157 100644
--- a/chromium/content/browser/download/mock_download_file.h
+++ b/chromium/content/browser/download/mock_download_file.h
@@ -35,23 +35,24 @@ class MockDownloadFile : public DownloadFile {
MOCK_METHOD2(RenameAndUniquify,
void(const base::FilePath& full_path,
const RenameCompletionCallback& callback));
- MOCK_METHOD2(RenameAndAnnotate,
+ MOCK_METHOD5(RenameAndAnnotate,
void(const base::FilePath& full_path,
+ const std::string& client_guid,
+ const GURL& source_url,
+ const GURL& referrer_url,
const RenameCompletionCallback& callback));
MOCK_METHOD0(Detach, void());
MOCK_METHOD0(Cancel, void());
MOCK_METHOD0(Finish, void());
- MOCK_CONST_METHOD0(FullPath, base::FilePath());
+ MOCK_CONST_METHOD0(FullPath, const base::FilePath&());
MOCK_CONST_METHOD0(InProgress, bool());
MOCK_CONST_METHOD0(BytesSoFar, int64_t());
MOCK_CONST_METHOD0(CurrentSpeed, int64_t());
MOCK_METHOD1(GetHash, bool(std::string* hash));
- MOCK_METHOD0(GetHashState, std::string());
MOCK_METHOD0(SendUpdate, void());
MOCK_CONST_METHOD0(Id, int());
MOCK_METHOD0(GetDownloadManager, DownloadManager*());
MOCK_CONST_METHOD0(DebugString, std::string());
- MOCK_METHOD1(SetClientGuid, void(const std::string&));
};
} // namespace content
diff --git a/chromium/content/browser/download/save_file.cc b/chromium/content/browser/download/save_file.cc
index 5085e477c15..2eab52b0451 100644
--- a/chromium/content/browser/download/save_file.cc
+++ b/chromium/content/browser/download/save_file.cc
@@ -14,15 +14,7 @@ namespace content {
// Unfortunately, as it is, constructors of SaveFile don't always
// have access to the SavePackage at this point.
SaveFile::SaveFile(const SaveFileCreateInfo* info, bool calculate_hash)
- : file_(base::FilePath(),
- info->url,
- GURL(),
- 0,
- calculate_hash,
- std::string(),
- base::File(),
- net::BoundNetLog()),
- info_(info) {
+ : file_(net::BoundNetLog()), info_(info) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(info);
@@ -34,7 +26,12 @@ SaveFile::~SaveFile() {
}
DownloadInterruptReason SaveFile::Initialize() {
- return file_.Initialize(base::FilePath());
+ return file_.Initialize(base::FilePath(),
+ base::FilePath(),
+ base::File(),
+ 0,
+ std::string(),
+ scoped_ptr<crypto::SecureHash>());
}
DownloadInterruptReason SaveFile::AppendDataToFile(const char* data,
@@ -61,7 +58,7 @@ void SaveFile::Finish() {
void SaveFile::AnnotateWithSourceInformation() {
// TODO(gbillock): If this method is called, it should set the
// file_.SetClientGuid() method first.
- file_.AnnotateWithSourceInformation();
+ NOTREACHED();
}
base::FilePath SaveFile::FullPath() const {
@@ -76,10 +73,6 @@ int64_t SaveFile::BytesSoFar() const {
return file_.bytes_so_far();
}
-bool SaveFile::GetHash(std::string* hash) {
- return file_.GetHash(hash);
-}
-
std::string SaveFile::DebugString() const {
return file_.DebugString();
}
diff --git a/chromium/content/browser/download/save_file.h b/chromium/content/browser/download/save_file.h
index 1dc82170ad0..69add3279da 100644
--- a/chromium/content/browser/download/save_file.h
+++ b/chromium/content/browser/download/save_file.h
@@ -38,7 +38,6 @@ class SaveFile {
base::FilePath FullPath() const;
bool InProgress() const;
int64_t BytesSoFar() const;
- bool GetHash(std::string* hash);
std::string DebugString() const;
// Accessors.
diff --git a/chromium/content/browser/download/save_file_manager.cc b/chromium/content/browser/download/save_file_manager.cc
index cf2e59ce3f1..527a7a18fbb 100644
--- a/chromium/content/browser/download/save_file_manager.cc
+++ b/chromium/content/browser/download/save_file_manager.cc
@@ -74,6 +74,10 @@ void SaveFileManager::SaveURL(SaveItemId save_item_id,
SavePackage* save_package) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Insert started saving job to tracking list.
+ DCHECK(packages_.find(save_item_id) == packages_.end());
+ packages_[save_item_id] = save_package;
+
// Register a saving job.
if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) {
DCHECK(url.is_valid());
@@ -201,19 +205,27 @@ void SaveFileManager::SaveFinished(SaveItemId save_item_id,
<< " save_package_id = " << save_package_id
<< " is_success = " << is_success;
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+
+ int64_t bytes_so_far = 0;
SaveFile* save_file = LookupSaveFile(save_item_id);
if (save_file != nullptr) {
DCHECK(save_file->InProgress());
DVLOG(20) << " " << __FUNCTION__ << "()"
<< " save_file = " << save_file->DebugString();
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&SaveFileManager::OnSaveFinished, this, save_item_id,
- save_file->BytesSoFar(), is_success));
-
+ bytes_so_far = save_file->BytesSoFar();
save_file->Finish();
save_file->Detach();
+ } else {
+ // We got called before StartSave - this should only happen if
+ // ResourceHandler failed before it got a chance to parse headers
+ // and metadata.
+ DCHECK(!is_success);
}
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&SaveFileManager::OnSaveFinished, this, save_item_id,
+ bytes_so_far, is_success));
}
// Notifications sent from the file thread and run on the UI thread.
@@ -228,10 +240,6 @@ void SaveFileManager::OnStartSave(const SaveFileCreateInfo& info) {
return;
}
- // Insert started saving job to tracking list.
- DCHECK(packages_.find(info.save_item_id) == packages_.end());
- packages_[info.save_item_id] = save_package;
-
// Forward this message to SavePackage.
save_package->StartSave(&info);
}
diff --git a/chromium/content/browser/download/save_file_manager.h b/chromium/content/browser/download/save_file_manager.h
index 3f36206f43c..e99c2a23b8a 100644
--- a/chromium/content/browser/download/save_file_manager.h
+++ b/chromium/content/browser/download/save_file_manager.h
@@ -60,8 +60,8 @@
#include <stdint.h>
#include <string>
+#include <unordered_map>
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "content/browser/download/save_types.h"
@@ -90,8 +90,10 @@ class SaveFileManager : public base::RefCountedThreadSafe<SaveFileManager> {
// Lifetime management.
CONTENT_EXPORT void Shutdown();
- // Save the specified URL. Called on the UI thread and forwarded to the
- // ResourceDispatcherHostImpl on the IO thread.
+ // Save the specified URL. Caller has to guarantee that |save_package| will
+ // be alive until the call to RemoveSaveFile. Called on the UI thread (and in
+ // case of network downloads forwarded to the ResourceDispatcherHostImpl on
+ // the IO thread).
void SaveURL(SaveItemId save_item_id,
const GURL& url,
const Referrer& referrer,
@@ -204,12 +206,14 @@ class SaveFileManager : public base::RefCountedThreadSafe<SaveFileManager> {
void ExecuteCancelSaveRequest(int render_process_id, int request_id);
// A map from save_item_id into SaveFiles.
- typedef base::hash_map<SaveItemId, SaveFile*> SaveFileMap;
+ using SaveFileMap =
+ std::unordered_map<SaveItemId, SaveFile*, SaveItemId::Hasher>;
SaveFileMap save_file_map_;
// Tracks which SavePackage to send data to, called only on UI thread.
// SavePackageMap maps save item ids to their SavePackage.
- typedef base::hash_map<SaveItemId, SavePackage*> SavePackageMap;
+ using SavePackageMap =
+ std::unordered_map<SaveItemId, SavePackage*, SaveItemId::Hasher>;
SavePackageMap packages_;
DISALLOW_COPY_AND_ASSIGN(SaveFileManager);
diff --git a/chromium/content/browser/download/save_file_resource_handler.cc b/chromium/content/browser/download/save_file_resource_handler.cc
index faf5605710a..7cba445aad5 100644
--- a/chromium/content/browser/download/save_file_resource_handler.cc
+++ b/chromium/content/browser/download/save_file_resource_handler.cc
@@ -85,7 +85,7 @@ bool SaveFileResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SaveFileManager::UpdateSaveProgress, save_manager_,
- save_item_id_, buffer, bytes_read));
+ save_item_id_, base::RetainedRef(buffer), bytes_read));
return true;
}
diff --git a/chromium/content/browser/download/save_item.cc b/chromium/content/browser/download/save_item.cc
index edea2632804..5fa262778e8 100644
--- a/chromium/content/browser/download/save_item.cc
+++ b/chromium/content/browser/download/save_item.cc
@@ -27,10 +27,12 @@ SaveItemId GetNextSaveItemId() {
SaveItem::SaveItem(const GURL& url,
const Referrer& referrer,
SavePackage* package,
- SaveFileCreateInfo::SaveFileSource save_source)
+ SaveFileCreateInfo::SaveFileSource save_source,
+ int frame_tree_node_id)
: save_item_id_(GetNextSaveItemId()),
url_(url),
referrer_(referrer),
+ frame_tree_node_id_(frame_tree_node_id),
total_bytes_(0),
received_bytes_(0),
state_(WAIT_START),
diff --git a/chromium/content/browser/download/save_item.h b/chromium/content/browser/download/save_item.h
index b0e655da71e..ef463953bf7 100644
--- a/chromium/content/browser/download/save_item.h
+++ b/chromium/content/browser/download/save_item.h
@@ -30,7 +30,8 @@ class SaveItem {
SaveItem(const GURL& url,
const Referrer& referrer,
SavePackage* package,
- SaveFileCreateInfo::SaveFileSource save_source);
+ SaveFileCreateInfo::SaveFileSource save_source,
+ int frame_tree_node_id);
~SaveItem();
@@ -61,6 +62,7 @@ class SaveItem {
const base::FilePath& file_name() const { return file_name_; }
const GURL& url() const { return url_; }
const Referrer& referrer() const { return referrer_; }
+ int frame_tree_node_id() const { return frame_tree_node_id_; }
int64_t total_bytes() const { return total_bytes_; }
int64_t received_bytes() const { return received_bytes_; }
bool has_final_name() const { return has_final_name_; }
@@ -87,6 +89,10 @@ class SaveItem {
GURL url_;
Referrer referrer_;
+ // Frame tree node id, if this save item represents a frame
+ // (otherwise FrameTreeNode::kFrameTreeNodeInvalidID).
+ int frame_tree_node_id_;
+
// Total bytes expected.
int64_t total_bytes_;
diff --git a/chromium/content/browser/download/save_package.cc b/chromium/content/browser/download/save_package.cc
index 5b7d6a6ead1..7c989856f6b 100644
--- a/chromium/content/browser/download/save_package.cc
+++ b/chromium/content/browser/download/save_package.cc
@@ -131,9 +131,6 @@ class SavePackageRequestHandle : public DownloadRequestHandleInterface {
void PauseRequest() const override {}
void ResumeRequest() const override {}
void CancelRequest() const override {}
- std::string DebugString() const override {
- return "SavePackage DownloadRequestHandle";
- }
private:
base::WeakPtr<SavePackage> save_package_;
@@ -354,10 +351,8 @@ void SavePackage::InitWithDownloadItem(
SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ?
SaveFileCreateInfo::SAVE_FILE_FROM_FILE :
SaveFileCreateInfo::SAVE_FILE_FROM_NET;
- SaveItem* save_item = new SaveItem(page_url_,
- Referrer(),
- this,
- save_source);
+ SaveItem* save_item = new SaveItem(page_url_, Referrer(), this, save_source,
+ FrameTreeNode::kFrameTreeNodeInvalidId);
// Add this item to waiting list.
waiting_item_queue_.push_back(save_item);
all_save_items_count_ = 1;
@@ -378,12 +373,10 @@ void SavePackage::OnMHTMLGenerated(int64_t size) {
// TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
// with SavePackage flow.
if (download_->GetState() == DownloadItem::IN_PROGRESS) {
- download_->SetTotalBytes(size);
- download_->DestinationUpdate(size, 0, std::string());
// Must call OnAllDataSaved here in order for
// GDataDownloadObserver::ShouldUpload() to return true.
// ShouldCompleteDownload() may depend on the gdata uploader to finish.
- download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
+ download_->OnAllDataSaved(size, scoped_ptr<crypto::SecureHash>());
}
if (!download_manager_->GetDelegate()) {
@@ -555,7 +548,7 @@ bool SavePackage::GenerateFileName(const std::string& disposition,
// We have received a message from SaveFileManager about a new saving job. We
// find a SaveItem and store it in our in_progress list.
void SavePackage::StartSave(const SaveFileCreateInfo* info) {
- DCHECK(info && !info->url.is_empty());
+ DCHECK(info);
SaveItemIdMap::iterator it = in_progress_items_.find(info->save_item_id);
if (it == in_progress_items_.end()) {
@@ -788,9 +781,9 @@ void SavePackage::Finish() {
// with SavePackage flow.
if (download_->GetState() == DownloadItem::IN_PROGRESS) {
if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) {
- download_->DestinationUpdate(
- all_save_items_count_, CurrentSpeed(), std::string());
- download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
+ download_->DestinationUpdate(all_save_items_count_, CurrentSpeed());
+ download_->OnAllDataSaved(all_save_items_count_,
+ scoped_ptr<crypto::SecureHash>());
}
download_->MarkAsComplete();
}
@@ -821,8 +814,7 @@ void SavePackage::SaveFinished(SaveItemId save_item_id,
// TODO(rdsmith/benjhayden): Integrate canceling on DownloadItem
// with SavePackage flow.
if (download_ && (download_->GetState() == DownloadItem::IN_PROGRESS)) {
- download_->DestinationUpdate(
- completed_count(), CurrentSpeed(), std::string());
+ download_->DestinationUpdate(completed_count(), CurrentSpeed());
}
if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM &&
@@ -974,18 +966,28 @@ void SavePackage::GetSerializedHtmlWithLocalLinks() {
if (successful_started_items_count != in_process_count())
return;
- // Ask all frames for their serialized data.
+ // Try to serialize all the frames gathered during GetSavableResourceLinks.
DCHECK_EQ(0, number_of_frames_pending_response_);
FrameTree* frame_tree =
static_cast<RenderFrameHostImpl*>(web_contents()->GetMainFrame())
->frame_tree_node()->frame_tree();
for (const auto& item : frame_tree_node_id_to_save_item_) {
- DCHECK(item.second); // SaveItem* != nullptr.
int frame_tree_node_id = item.first;
+ SaveItem* save_item = item.second;
+ DCHECK(save_item);
+
FrameTreeNode* frame_tree_node = frame_tree->FindByID(frame_tree_node_id);
- if (frame_tree_node) {
+ if (frame_tree_node &&
+ frame_tree_node->current_frame_host()->IsRenderFrameLive()) {
+ // Ask the frame for HTML to be written to the associated SaveItem.
GetSerializedHtmlWithLocalLinksForFrame(frame_tree_node);
number_of_frames_pending_response_++;
+ } else {
+ // Notify SaveFileManager about the failure to save this SaveItem.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&SaveFileManager::SaveFinished, file_manager_,
+ save_item->id(), id(), false));
}
}
if (number_of_frames_pending_response_ == 0) {
@@ -999,30 +1001,59 @@ void SavePackage::GetSerializedHtmlWithLocalLinksForFrame(
FrameTreeNode* target_tree_node) {
DCHECK(target_tree_node);
int target_frame_tree_node_id = target_tree_node->frame_tree_node_id();
+ RenderFrameHostImpl* target = target_tree_node->current_frame_host();
// Collect all saved success items.
// SECURITY NOTE: We don't send *all* urls / local paths, but only
// those that the given frame had access to already (because it contained
// the savable resources / subframes associated with save items).
std::map<GURL, base::FilePath> url_to_local_path;
+ std::map<int, base::FilePath> routing_id_to_local_path;
auto it = frame_tree_node_id_to_contained_save_items_.find(
target_frame_tree_node_id);
if (it != frame_tree_node_id_to_contained_save_items_.end()) {
for (SaveItem* save_item : it->second) {
- DCHECK(save_item->has_final_name());
+ // Skip items that failed to save.
+ if (!save_item->has_final_name()) {
+ DCHECK_EQ(SaveItem::SaveState::COMPLETE, save_item->state());
+ DCHECK(!save_item->success());
+ continue;
+ }
+
+ // Calculate the relative path for referring to the |save_item|.
base::FilePath local_path(base::FilePath::kCurrentDirectory);
if (target_tree_node->IsMainFrame()) {
local_path = local_path.Append(saved_main_directory_path_.BaseName());
}
local_path = local_path.Append(save_item->file_name());
- url_to_local_path[save_item->url()] = local_path;
+
+ // Insert the link into |url_to_local_path| or |routing_id_to_local_path|.
+ if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
+ DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId,
+ save_item->frame_tree_node_id());
+ url_to_local_path[save_item->url()] = local_path;
+ } else {
+ FrameTreeNode* save_item_frame_tree_node =
+ target_tree_node->frame_tree()->FindByID(
+ save_item->frame_tree_node_id());
+ if (!save_item_frame_tree_node) {
+ // crbug.com/541354: Raciness when saving a dynamically changing page.
+ continue;
+ }
+
+ int routing_id =
+ save_item_frame_tree_node->render_manager()
+ ->GetRoutingIdForSiteInstance(target->GetSiteInstance());
+ DCHECK_NE(MSG_ROUTING_NONE, routing_id);
+
+ routing_id_to_local_path[routing_id] = local_path;
+ }
}
}
// Ask target frame to serialize itself.
- RenderFrameHostImpl* target = target_tree_node->current_frame_host();
target->Send(new FrameMsg_GetSerializedHtmlWithLocalLinks(
- target->GetRoutingID(), url_to_local_path));
+ target->GetRoutingID(), url_to_local_path, routing_id_to_local_path));
}
// Process the serialized HTML content data of a specified frame
@@ -1069,7 +1100,8 @@ void SavePackage::OnSerializedHtmlWithLocalLinksResponse(
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SaveFileManager::UpdateSaveProgress, file_manager_,
- save_item->id(), new_data, static_cast<int>(data.size())));
+ save_item->id(), base::RetainedRef(new_data),
+ static_cast<int>(data.size())));
}
// Current frame is completed saving, call finish in file thread.
@@ -1150,14 +1182,14 @@ void SavePackage::OnSavableResourceLinksResponse(
SaveItem* SavePackage::CreatePendingSaveItem(
int container_frame_tree_node_id,
+ int save_item_frame_tree_node_id,
const GURL& url,
const Referrer& referrer,
SaveFileCreateInfo::SaveFileSource save_source) {
- DCHECK(url.is_valid()); // |url| should be validated by the callers.
-
SaveItem* save_item;
Referrer sanitized_referrer = Referrer::SanitizeForRequest(url, referrer);
- save_item = new SaveItem(url, sanitized_referrer, this, save_source);
+ save_item = new SaveItem(url, sanitized_referrer, this, save_source,
+ save_item_frame_tree_node_id);
waiting_item_queue_.push_back(save_item);
frame_tree_node_id_to_contained_save_items_[container_frame_tree_node_id]
@@ -1167,6 +1199,7 @@ SaveItem* SavePackage::CreatePendingSaveItem(
SaveItem* SavePackage::CreatePendingSaveItemDeduplicatingByUrl(
int container_frame_tree_node_id,
+ int save_item_frame_tree_node_id,
const GURL& url,
const Referrer& referrer,
SaveFileCreateInfo::SaveFileSource save_source) {
@@ -1182,7 +1215,8 @@ SaveItem* SavePackage::CreatePendingSaveItemDeduplicatingByUrl(
frame_tree_node_id_to_contained_save_items_[container_frame_tree_node_id]
.push_back(save_item);
} else {
- save_item = CreatePendingSaveItem(container_frame_tree_node_id, url,
+ save_item = CreatePendingSaveItem(container_frame_tree_node_id,
+ save_item_frame_tree_node_id, url,
referrer, save_source);
url_to_save_item_[url] = save_item;
}
@@ -1199,19 +1233,17 @@ void SavePackage::EnqueueSavableResource(int container_frame_tree_node_id,
SaveFileCreateInfo::SaveFileSource save_source =
url.SchemeIsFile() ? SaveFileCreateInfo::SAVE_FILE_FROM_FILE
: SaveFileCreateInfo::SAVE_FILE_FROM_NET;
- CreatePendingSaveItemDeduplicatingByUrl(container_frame_tree_node_id, url,
- referrer, save_source);
+ CreatePendingSaveItemDeduplicatingByUrl(
+ container_frame_tree_node_id, FrameTreeNode::kFrameTreeNodeInvalidId, url,
+ referrer, save_source);
}
void SavePackage::EnqueueFrame(int container_frame_tree_node_id,
int frame_tree_node_id,
const GURL& frame_original_url) {
- if (!frame_original_url.is_valid())
- return;
-
- SaveItem* save_item =
- CreatePendingSaveItem(container_frame_tree_node_id, frame_original_url,
- Referrer(), SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
+ SaveItem* save_item = CreatePendingSaveItem(
+ container_frame_tree_node_id, frame_tree_node_id, frame_original_url,
+ Referrer(), SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
DCHECK(save_item);
frame_tree_node_id_to_save_item_[frame_tree_node_id] = save_item;
}
@@ -1261,8 +1293,7 @@ void SavePackage::CompleteSavableResourceLinksResponse() {
base::FilePath SavePackage::GetSuggestedNameForSaveAs(
bool can_save_as_complete,
- const std::string& contents_mime_type,
- const std::string& accept_langs) {
+ const std::string& contents_mime_type) {
base::FilePath name_with_proper_ext = base::FilePath::FromUTF16Unsafe(title_);
// If the page's title matches its URL, use the URL. Try to use the last path
@@ -1274,7 +1305,7 @@ base::FilePath SavePackage::GetSuggestedNameForSaveAs(
// back to a URL, and if it matches the original page URL, we know the page
// had no title (or had a title equal to its URL, which is fine to treat
// similarly).
- if (title_ == url_formatter::FormatUrl(page_url_, accept_langs)) {
+ if (title_ == url_formatter::FormatUrl(page_url_)) {
std::string url_path;
if (!page_url_.SchemeIs(url::kDataScheme)) {
std::vector<std::string> url_parts = base::SplitString(
@@ -1374,23 +1405,17 @@ void SavePackage::GetSaveInfo() {
&download_save_dir, &skip_dir_check);
}
std::string mime_type = web_contents()->GetContentsMimeType();
- std::string accept_languages =
- GetContentClient()->browser()->GetAcceptLangs(
- web_contents()->GetBrowserContext());
-
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&SavePackage::CreateDirectoryOnFileThread, this,
- website_save_dir, download_save_dir, skip_dir_check,
- mime_type, accept_languages));
+ website_save_dir, download_save_dir, skip_dir_check, mime_type));
}
void SavePackage::CreateDirectoryOnFileThread(
const base::FilePath& website_save_dir,
const base::FilePath& download_save_dir,
bool skip_dir_check,
- const std::string& mime_type,
- const std::string& accept_langs) {
+ const std::string& mime_type) {
base::FilePath save_dir;
// If the default html/websites save folder doesn't exist...
// We skip the directory check for gdata directories on ChromeOS.
@@ -1408,7 +1433,7 @@ void SavePackage::CreateDirectoryOnFileThread(
bool can_save_as_complete = CanSaveAsComplete(mime_type);
base::FilePath suggested_filename = GetSuggestedNameForSaveAs(
- can_save_as_complete, mime_type, accept_langs);
+ can_save_as_complete, mime_type);
base::FilePath::StringType pure_file_name =
suggested_filename.RemoveExtension().BaseName().value();
base::FilePath::StringType file_name_ext = suggested_filename.Extension();
diff --git a/chromium/content/browser/download/save_package.h b/chromium/content/browser/download/save_package.h
index eabf65717a0..5b0e958c3a0 100644
--- a/chromium/content/browser/download/save_package.h
+++ b/chromium/content/browser/download/save_package.h
@@ -12,9 +12,9 @@
#include <map>
#include <set>
#include <string>
+#include <unordered_map>
#include <vector>
-#include "base/containers/hash_tables.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
@@ -206,6 +206,7 @@ class CONTENT_EXPORT SavePackage
// Helper for finding or creating a SaveItem with the given parameters.
SaveItem* CreatePendingSaveItem(
int container_frame_tree_node_id,
+ int save_item_frame_tree_node_id,
const GURL& url,
const Referrer& referrer,
SaveFileCreateInfo::SaveFileSource save_source);
@@ -214,6 +215,7 @@ class CONTENT_EXPORT SavePackage
// creating a SaveItem with the given parameters.
SaveItem* CreatePendingSaveItemDeduplicatingByUrl(
int container_frame_tree_node_id,
+ int save_item_frame_tree_node_id,
const GURL& url,
const Referrer& referrer,
SaveFileCreateInfo::SaveFileSource save_source);
@@ -263,8 +265,7 @@ class CONTENT_EXPORT SavePackage
void CreateDirectoryOnFileThread(const base::FilePath& website_save_dir,
const base::FilePath& download_save_dir,
bool skip_dir_check,
- const std::string& mime_type,
- const std::string& accept_langs);
+ const std::string& mime_type);
void ContinueGetSaveInfo(const base::FilePath& suggested_path,
bool can_save_as_complete);
void OnPathPicked(
@@ -273,7 +274,8 @@ class CONTENT_EXPORT SavePackage
const SavePackageDownloadCreatedCallback& cb);
// Map from SaveItem::id() (aka save_item_id) into a SaveItem.
- typedef base::hash_map<SaveItemId, SaveItem*> SaveItemIdMap;
+ using SaveItemIdMap =
+ std::unordered_map<SaveItemId, SaveItem*, SaveItemId::Hasher>;
// in_progress_items_ is map of all saving job in in-progress state.
SaveItemIdMap in_progress_items_;
// saved_failed_items_ is map of all saving job which are failed.
@@ -302,8 +304,7 @@ class CONTENT_EXPORT SavePackage
// suggested name is determined by the web document's title.
base::FilePath GetSuggestedNameForSaveAs(
bool can_save_as_complete,
- const std::string& contents_mime_type,
- const std::string& accept_langs);
+ const std::string& contents_mime_type);
// Ensures that the file name has a proper extension for HTML by adding ".htm"
// if necessary.
@@ -319,7 +320,7 @@ class CONTENT_EXPORT SavePackage
static const base::FilePath::CharType* ExtensionForMimeType(
const std::string& contents_mime_type);
- typedef std::deque<SaveItem*> SaveItemQueue;
+ using SaveItemQueue = std::deque<SaveItem*>;
// A queue for items we are about to start saving.
SaveItemQueue waiting_item_queue_;
@@ -333,21 +334,22 @@ class CONTENT_EXPORT SavePackage
// OnSerializedHtmlWithLocalLinksResponse) to the right SaveItem.
// Note that |frame_tree_node_id_to_save_item_| does NOT own SaveItems - they
// remain owned by waiting_item_queue_, in_progress_items_, etc.
- base::hash_map<int, SaveItem*> frame_tree_node_id_to_save_item_;
+ std::unordered_map<int, SaveItem*> frame_tree_node_id_to_save_item_;
// Used to limit which local paths get exposed to which frames
// (i.e. to prevent information disclosure to oop frames).
// Note that |frame_tree_node_id_to_contained_save_items_| does NOT own
// SaveItems - they remain owned by waiting_item_queue_, in_progress_items_,
// etc.
- base::hash_map<int, std::vector<SaveItem*>>
+ std::unordered_map<int, std::vector<SaveItem*>>
frame_tree_node_id_to_contained_save_items_;
// Number of frames that we still need to get a response from.
int number_of_frames_pending_response_;
// saved_success_items_ is map of all saving job which are successfully saved.
- base::hash_map<SaveItemId, SaveItem*> saved_success_items_;
+ std::unordered_map<SaveItemId, SaveItem*, SaveItemId::Hasher>
+ saved_success_items_;
// Non-owning pointer for handling file writing on the file thread.
SaveFileManager* file_manager_;
@@ -392,7 +394,8 @@ class CONTENT_EXPORT SavePackage
// This set is used to eliminate duplicated file names in saving directory.
FileNameSet file_name_set_;
- typedef base::hash_map<base::FilePath::StringType, uint32_t> FileNameCountMap;
+ using FileNameCountMap =
+ std::unordered_map<base::FilePath::StringType, uint32_t>;
// This map is used to track serial number for specified filename.
FileNameCountMap file_name_count_map_;
diff --git a/chromium/content/browser/download/save_package_unittest.cc b/chromium/content/browser/download/save_package_unittest.cc
index fc89b6d1806..c426772a820 100644
--- a/chromium/content/browser/download/save_package_unittest.cc
+++ b/chromium/content/browser/download/save_package_unittest.cc
@@ -406,8 +406,7 @@ TEST_F(SavePackageTest, MAYBE_TestSuggestedSaveNames) {
save_package->title_ = kSuggestedSaveNames[i].page_title;
base::FilePath save_name = save_package->GetSuggestedNameForSaveAs(
- kSuggestedSaveNames[i].ensure_html_extension,
- std::string(), std::string());
+ kSuggestedSaveNames[i].ensure_html_extension, std::string());
EXPECT_EQ(kSuggestedSaveNames[i].expected_name, save_name.value()) <<
"Test case " << i;
}
diff --git a/chromium/content/browser/download/save_types.cc b/chromium/content/browser/download/save_types.cc
index 9c4972a8854..0dd760562c1 100644
--- a/chromium/content/browser/download/save_types.cc
+++ b/chromium/content/browser/download/save_types.cc
@@ -45,6 +45,9 @@ SaveFileCreateInfo::SaveFileCreateInfo(const GURL& url,
total_bytes(total_bytes),
save_source(SaveFileCreateInfo::SAVE_FILE_FROM_NET) {}
+SaveFileCreateInfo::SaveFileCreateInfo(const SaveFileCreateInfo& other) =
+ default;
+
SaveFileCreateInfo::~SaveFileCreateInfo() {}
} // namespace content
diff --git a/chromium/content/browser/download/save_types.h b/chromium/content/browser/download/save_types.h
index 83d890b8dc9..9d61a9a70a0 100644
--- a/chromium/content/browser/download/save_types.h
+++ b/chromium/content/browser/download/save_types.h
@@ -13,16 +13,16 @@
#include <vector>
#include "base/files/file_path.h"
-#include "content/common/id_type.h"
+#include "gpu/command_buffer/common/id_type.h"
#include "url/gurl.h"
namespace content {
class SavePackage;
-using SavePackageId = IdType32<SavePackage>;
+using SavePackageId = gpu::IdType32<SavePackage>;
class SaveItem;
-using SaveItemId = IdType32<SaveItem>;
+using SaveItemId = gpu::IdType32<SaveItem>;
// Map from save_item_id into final file path.
using FinalNamesMap = std::map<SaveItemId, base::FilePath>;
@@ -63,6 +63,8 @@ struct SaveFileCreateInfo {
const std::string& content_disposition,
int64_t total_bytes);
+ SaveFileCreateInfo(const SaveFileCreateInfo& other);
+
~SaveFileCreateInfo();
// SaveItem fields.
diff --git a/chromium/content/browser/download/url_downloader.cc b/chromium/content/browser/download/url_downloader.cc
index b178a1d4b26..274de905d8c 100644
--- a/chromium/content/browser/download/url_downloader.cc
+++ b/chromium/content/browser/download/url_downloader.cc
@@ -60,7 +60,6 @@ class UrlDownloader::RequestHandle : public DownloadRequestHandleInterface {
downloader_task_runner_->PostTask(
FROM_HERE, base::Bind(&UrlDownloader::CancelRequest, downloader_));
}
- std::string DebugString() const override { return std::string(); }
private:
base::WeakPtr<UrlDownloader> downloader_;
@@ -74,62 +73,32 @@ class UrlDownloader::RequestHandle : public DownloadRequestHandleInterface {
scoped_ptr<UrlDownloader> UrlDownloader::BeginDownload(
base::WeakPtr<DownloadManagerImpl> download_manager,
scoped_ptr<net::URLRequest> request,
- const Referrer& referrer,
- bool prefer_cache,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadUrlParameters::OnStartedCallback& started_callback) {
+ const Referrer& referrer) {
if (!referrer.url.is_valid())
request->SetReferrer(std::string());
else
request->SetReferrer(referrer.url.spec());
- int extra_load_flags = net::LOAD_NORMAL;
- if (prefer_cache) {
- // If there is upload data attached, only retrieve from cache because there
- // is no current mechanism to prompt the user for their consent for a
- // re-post. For GETs, try to retrieve data from the cache and skip
- // validating the entry if present.
- if (request->get_upload() != NULL)
- extra_load_flags |= net::LOAD_ONLY_FROM_CACHE;
- else
- extra_load_flags |= net::LOAD_PREFERRING_CACHE;
- } else {
- extra_load_flags |= net::LOAD_DISABLE_CACHE;
- }
- request->SetLoadFlags(request->load_flags() | extra_load_flags);
-
if (request->url().SchemeIs(url::kBlobScheme))
return nullptr;
// From this point forward, the |UrlDownloader| is responsible for
// |started_callback|.
scoped_ptr<UrlDownloader> downloader(
- new UrlDownloader(std::move(request), download_manager,
- std::move(save_info), download_id, started_callback));
+ new UrlDownloader(std::move(request), download_manager));
downloader->Start();
return downloader;
}
-UrlDownloader::UrlDownloader(
- scoped_ptr<net::URLRequest> request,
- base::WeakPtr<DownloadManagerImpl> manager,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadUrlParameters::OnStartedCallback& on_started_callback)
+UrlDownloader::UrlDownloader(scoped_ptr<net::URLRequest> request,
+ base::WeakPtr<DownloadManagerImpl> manager)
: request_(std::move(request)),
manager_(manager),
- download_id_(download_id),
- on_started_callback_(on_started_callback),
- handler_(
- request_.get(),
- std::move(save_info),
- base::Bind(&UrlDownloader::ResumeReading, base::Unretained(this))),
+ core_(request_.get(), this),
weak_ptr_factory_(this) {}
UrlDownloader::~UrlDownloader() {
- CallStartedCallbackOnFailure(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
}
void UrlDownloader::Start() {
@@ -146,7 +115,15 @@ void UrlDownloader::OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& redirect_info,
bool* defer_redirect) {
DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
- request_->CancelWithError(net::ERR_ABORTED);
+
+ // We are going to block redirects even if DownloadRequestCore allows it. No
+ // redirects are expected for download requests that are made without a
+ // renderer, which are currently exclusively resumption requests. Since there
+ // is no security policy being applied here, it's safer to block redirects and
+ // revisit if some previously unknown legitimate use case arises for redirects
+ // while resuming.
+ core_.OnWillAbort(DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE);
+ request_->CancelWithError(net::ERR_UNSAFE_REDIRECT);
}
void UrlDownloader::OnResponseStarted(net::URLRequest* request) {
@@ -157,22 +134,7 @@ void UrlDownloader::OnResponseStarted(net::URLRequest* request) {
return;
}
- scoped_ptr<DownloadCreateInfo> create_info;
- scoped_ptr<ByteStreamReader> stream_reader;
-
- handler_.OnResponseStarted(&create_info, &stream_reader);
-
- create_info->download_id = download_id_;
- create_info->request_handle.reset(
- new RequestHandle(weak_ptr_factory_.GetWeakPtr(), manager_,
- base::SequencedTaskRunnerHandle::Get()));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DownloadManagerImpl::StartDownload, manager_,
- base::Passed(&create_info), base::Passed(&stream_reader),
- base::ResetAndReturn(&on_started_callback_)));
-
- if (request_->status().is_success())
+ if (core_.OnResponseStarted(std::string()))
StartReading(false); // Read the first chunk.
else
ResponseCompleted();
@@ -186,7 +148,7 @@ void UrlDownloader::StartReading(bool is_continuation) {
// doesn't use the buffer.
scoped_refptr<net::IOBuffer> buf;
int buf_size;
- if (!handler_.OnWillRead(&buf, &buf_size, -1)) {
+ if (!core_.OnWillRead(&buf, &buf_size, -1)) {
request_->CancelWithError(net::ERR_ABORTED);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&UrlDownloader::ResponseCompleted,
@@ -229,7 +191,7 @@ void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) {
DCHECK(request_->status().is_success());
bool defer = false;
- if (!handler_.OnReadCompleted(bytes_read, &defer)) {
+ if (!core_.OnReadCompleted(bytes_read, &defer)) {
request_->CancelWithError(net::ERR_ABORTED);
return;
} else if (defer) {
@@ -251,38 +213,43 @@ void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) {
void UrlDownloader::ResponseCompleted() {
DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
- handler_.OnResponseCompleted(request_->status());
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DownloadManagerImpl::RemoveUrlDownloader, manager_, this));
+ core_.OnResponseCompleted(request_->status());
+ Destroy();
}
-void UrlDownloader::ResumeReading() {
- if (request_->status().is_success()) {
- StartReading(false); // Read the next chunk (OK to complete synchronously).
- } else {
- ResponseCompleted();
- }
+void UrlDownloader::OnStart(
+ scoped_ptr<DownloadCreateInfo> create_info,
+ scoped_ptr<ByteStreamReader> stream_reader,
+ const DownloadUrlParameters::OnStartedCallback& callback) {
+ create_info->request_handle.reset(
+ new RequestHandle(weak_ptr_factory_.GetWeakPtr(), manager_,
+ base::SequencedTaskRunnerHandle::Get()));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&DownloadManagerImpl::StartDownload,
+ manager_, base::Passed(&create_info),
+ base::Passed(&stream_reader), callback));
}
-void UrlDownloader::CallStartedCallbackOnFailure(
- DownloadInterruptReason result) {
- if (on_started_callback_.is_null())
- return;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(base::ResetAndReturn(&on_started_callback_), nullptr, result));
+void UrlDownloader::OnReadyToRead() {
+ if (request_->status().is_success())
+ StartReading(false); // Read the next chunk (OK to complete synchronously).
+ else
+ ResponseCompleted();
}
void UrlDownloader::PauseRequest() {
- handler_.PauseRequest();
+ core_.PauseRequest();
}
void UrlDownloader::ResumeRequest() {
- handler_.ResumeRequest();
+ core_.ResumeRequest();
}
void UrlDownloader::CancelRequest() {
+ Destroy();
+}
+
+void UrlDownloader::Destroy() {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&DownloadManagerImpl::RemoveUrlDownloader, manager_, this));
diff --git a/chromium/content/browser/download/url_downloader.h b/chromium/content/browser/download/url_downloader.h
index 787feb4c91b..475d97bfbc6 100644
--- a/chromium/content/browser/download/url_downloader.h
+++ b/chromium/content/browser/download/url_downloader.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/download/download_request_core.h"
+#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_save_info.h"
#include "content/public/browser/download_url_parameters.h"
#include "content/public/common/referrer.h"
@@ -17,26 +18,26 @@
#include "net/url_request/url_request.h"
namespace content {
+class ByteStreamReader;
+struct DownloadCreateInfo;
class DownloadManagerImpl;
-class UrlDownloader : public net::URLRequest::Delegate {
+class UrlDownloader : public net::URLRequest::Delegate,
+ public DownloadRequestCore::Delegate {
public:
- UrlDownloader(
- scoped_ptr<net::URLRequest> request,
- base::WeakPtr<DownloadManagerImpl> manager,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadUrlParameters::OnStartedCallback& on_started_callback);
+ UrlDownloader(scoped_ptr<net::URLRequest> request,
+ base::WeakPtr<DownloadManagerImpl> manager);
~UrlDownloader() override;
static scoped_ptr<UrlDownloader> BeginDownload(
base::WeakPtr<DownloadManagerImpl> download_manager,
scoped_ptr<net::URLRequest> request,
- const Referrer& referrer,
- bool prefer_cache,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadUrlParameters::OnStartedCallback& started_callback);
+ const Referrer& referrer);
+
+ private:
+ class RequestHandle;
+
+ void Start();
// URLRequest::Delegate:
void OnReceivedRedirect(net::URLRequest* request,
@@ -48,24 +49,25 @@ class UrlDownloader : public net::URLRequest::Delegate {
void StartReading(bool is_continuation);
void ResponseCompleted();
- void Start();
- void ResumeReading();
-
- void CallStartedCallbackOnFailure(DownloadInterruptReason result);
-
- private:
- class RequestHandle;
+ // DownloadRequestCore::Delegate
+ void OnStart(
+ scoped_ptr<DownloadCreateInfo> download_create_info,
+ scoped_ptr<ByteStreamReader> stream_reader,
+ const DownloadUrlParameters::OnStartedCallback& callback) override;
+ void OnReadyToRead() override;
void PauseRequest();
void ResumeRequest();
void CancelRequest();
+ // Called when the UrlDownloader is done with the request. Posts a task to
+ // remove itself from its download manager, which in turn would cause the
+ // UrlDownloader to be freed.
+ void Destroy();
+
scoped_ptr<net::URLRequest> request_;
base::WeakPtr<DownloadManagerImpl> manager_;
- uint32_t download_id_;
- DownloadUrlParameters::OnStartedCallback on_started_callback_;
-
- DownloadRequestCore handler_;
+ DownloadRequestCore core_;
base::WeakPtrFactory<UrlDownloader> weak_ptr_factory_;
};
diff --git a/chromium/content/browser/fileapi/blob_reader_unittest.cc b/chromium/content/browser/fileapi/blob_reader_unittest.cc
index d16b552d392..1c0ae10a593 100644
--- a/chromium/content/browser/fileapi/blob_reader_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_reader_unittest.cc
@@ -327,8 +327,7 @@ class BlobReaderTest : public ::testing::Test {
void InitializeReader(BlobDataBuilder* builder) {
blob_handle_ = builder ? context_.AddFinishedBlob(builder) : nullptr;
provider_ = new MockFileStreamReaderProvider();
- scoped_ptr<BlobReader::FileStreamReaderProvider> temp_ptr(provider_);
- reader_.reset(new BlobReader(blob_handle_.get(), std::move(temp_ptr),
+ reader_.reset(new BlobReader(blob_handle_.get(), make_scoped_ptr(provider_),
message_loop_.task_runner().get()));
}
@@ -395,8 +394,6 @@ class BlobReaderTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(BlobReaderTest);
};
-namespace {
-
TEST_F(BlobReaderTest, BasicMemory) {
BlobDataBuilder b("uuid");
const std::string kData("Hello!!!");
@@ -1113,5 +1110,52 @@ TEST_F(BlobReaderTest, RangeError) {
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
}
-} // namespace
+TEST_F(BlobReaderTest, HandleBeforeAsyncCancel) {
+ const std::string kUuid("uuid1");
+
+ context_.CreatePendingBlob(kUuid, "", "");
+ blob_handle_ = context_.GetBlobDataFromUUID(kUuid);
+ provider_ = new MockFileStreamReaderProvider();
+ reader_.reset(new BlobReader(blob_handle_.get(), make_scoped_ptr(provider_),
+ message_loop_.task_runner().get()));
+ int size_result = -1;
+ EXPECT_EQ(BlobReader::Status::IO_PENDING,
+ reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
+ context_.CancelPendingBlob(kUuid, IPCBlobCreationCancelCode::UNKNOWN);
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(net::ERR_FAILED, size_result);
+}
+
+TEST_F(BlobReaderTest, ReadFromIncompleteBlob) {
+ const std::string kUuid("uuid1");
+ const std::string kData("Hello!!!");
+ const size_t kDataSize = 8ul;
+
+ BlobDataBuilder b(kUuid);
+ b.AppendData(kData);
+ context_.CreatePendingBlob(kUuid, "", "");
+ blob_handle_ = context_.GetBlobDataFromUUID(kUuid);
+ provider_ = new MockFileStreamReaderProvider();
+ reader_.reset(new BlobReader(blob_handle_.get(), make_scoped_ptr(provider_),
+ message_loop_.task_runner().get()));
+ int size_result = -1;
+ EXPECT_EQ(BlobReader::Status::IO_PENDING,
+ reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
+ context_.CompletePendingBlob(b);
+ message_loop_.RunUntilIdle();
+ CheckSizeCalculatedAsynchronously(kDataSize, size_result);
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize));
+
+ int bytes_read = 0;
+ int async_bytes_read = 0;
+ EXPECT_EQ(BlobReader::Status::DONE,
+ reader_->Read(buffer.get(), kDataSize, &bytes_read,
+ base::Bind(&SetValue<int>, &async_bytes_read)));
+ EXPECT_EQ(net::OK, reader_->net_error());
+ EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
+ EXPECT_EQ(0, async_bytes_read);
+ EXPECT_EQ(kData, std::string(buffer->data(), kDataSize));
+ EXPECT_EQ(net::OK, size_result);
+}
+
} // namespace storage
diff --git a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc b/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
index 72df9841708..74e10d0493a 100644
--- a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
@@ -9,32 +9,37 @@
#include <limits>
#include <string>
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/time/time.h"
-#include "content/browser/fileapi/blob_storage_host.h"
+#include "content/browser/blob_storage/blob_dispatcher_host.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/public/test/test_browser_context.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/disk_cache.h"
+#include "storage/browser/blob/blob_async_builder_host.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_data_item.h"
#include "storage/browser/blob/blob_data_snapshot.h"
+#include "storage/browser/blob/blob_transport_result.h"
+#include "storage/common/blob_storage/blob_item_bytes_request.h"
+#include "storage/common/blob_storage/blob_item_bytes_response.h"
#include "testing/gtest/include/gtest/gtest.h"
-using storage::BlobDataBuilder;
-using storage::BlobDataHandle;
-using storage::BlobDataItem;
-using storage::BlobDataSnapshot;
-using storage::BlobStorageContext;
-using storage::DataElement;
+using RequestMemoryCallback =
+ storage::BlobAsyncBuilderHost::RequestMemoryCallback;
-namespace content {
+namespace storage {
namespace {
+const char kContentType[] = "text/plain";
+const char kContentDisposition[] = "content_disposition";
const int kTestDiskCacheStreamIndex = 0;
// Our disk cache tests don't need a real data handle since the tests themselves
@@ -74,97 +79,89 @@ disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache,
return entry;
}
-void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
- EXPECT_TRUE(host->StartBuildingBlob(id));
- DataElement item;
- item.SetToBytes("1", 1);
- EXPECT_TRUE(host->AppendBlobDataItem(id, item));
- EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
- EXPECT_FALSE(host->StartBuildingBlob(id));
-}
} // namespace
-TEST(BlobStorageContextTest, IncrementDecrementRef) {
- BlobStorageContext context;
- BlobStorageHost host(&context);
+class BlobStorageContextTest : public testing::Test {
+ protected:
+ BlobStorageContextTest() {}
+ ~BlobStorageContextTest() override {}
+
+ scoped_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) {
+ BlobDataBuilder builder(id);
+ builder.AppendData("1", 1);
+ builder.set_content_type("text/plain");
+ return context_.AddFinishedBlob(builder);
+ }
+
+ BlobStorageContext context_;
+};
+
+TEST_F(BlobStorageContextTest, IncrementDecrementRef) {
base::MessageLoop fake_io_message_loop;
// Build up a basic blob.
const std::string kId("id");
- SetupBasicBlob(&host, kId);
+ scoped_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId);
- // Make sure it's there, finish building implies a ref of one.
- scoped_ptr<BlobDataHandle> blob_data_handle;
- blob_data_handle = context.GetBlobDataFromUUID(kId);
+ // Do an extra increment to keep it around after we kill the handle.
+ context_.IncrementBlobRefCount(kId);
+ context_.IncrementBlobRefCount(kId);
+ context_.DecrementBlobRefCount(kId);
+ blob_data_handle = context_.GetBlobDataFromUUID(kId);
EXPECT_TRUE(blob_data_handle);
blob_data_handle.reset();
base::RunLoop().RunUntilIdle();
- // Make sure its still there after inc/dec.
- EXPECT_TRUE(host.IncrementBlobRefCount(kId));
- EXPECT_TRUE(host.DecrementBlobRefCount(kId));
- blob_data_handle = context.GetBlobDataFromUUID(kId);
- EXPECT_TRUE(blob_data_handle);
- blob_data_handle.reset();
- base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(context_.registry().HasEntry(kId));
+ context_.DecrementBlobRefCount(kId);
+ EXPECT_FALSE(context_.registry().HasEntry(kId));
// Make sure it goes away in the end.
- EXPECT_TRUE(host.DecrementBlobRefCount(kId));
- blob_data_handle = context.GetBlobDataFromUUID(kId);
+ blob_data_handle = context_.GetBlobDataFromUUID(kId);
EXPECT_FALSE(blob_data_handle);
- EXPECT_FALSE(host.DecrementBlobRefCount(kId));
- EXPECT_FALSE(host.IncrementBlobRefCount(kId));
}
-TEST(BlobStorageContextTest, CancelBuildingBlob) {
- BlobStorageContext context;
- BlobStorageHost host(&context);
+TEST_F(BlobStorageContextTest, OnCancelBuildingBlob) {
base::MessageLoop fake_io_message_loop;
// Build up a basic blob.
const std::string kId("id");
- EXPECT_TRUE(host.StartBuildingBlob(kId));
- DataElement item;
- item.SetToBytes("1", 1);
- EXPECT_TRUE(host.AppendBlobDataItem(kId, item));
- EXPECT_TRUE(host.CancelBuildingBlob(kId));
- EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
- EXPECT_TRUE(host.StartBuildingBlob(kId));
+ context_.CreatePendingBlob(kId, std::string(kContentType),
+ std::string(kContentDisposition));
+ EXPECT_TRUE(context_.IsBeingBuilt(kId));
+ context_.CancelPendingBlob(kId, IPCBlobCreationCancelCode::OUT_OF_MEMORY);
+ EXPECT_TRUE(context_.registry().HasEntry(kId));
+ EXPECT_FALSE(context_.IsBeingBuilt(kId));
+ EXPECT_TRUE(context_.IsBroken(kId));
}
-TEST(BlobStorageContextTest, BlobDataHandle) {
- BlobStorageContext context;
- BlobStorageHost host(&context);
+TEST_F(BlobStorageContextTest, BlobDataHandle) {
base::MessageLoop fake_io_message_loop;
// Build up a basic blob.
const std::string kId("id");
- SetupBasicBlob(&host, kId);
-
- // Get a handle to it.
- scoped_ptr<BlobDataHandle> blob_data_handle =
- context.GetBlobDataFromUUID(kId);
+ scoped_ptr<BlobDataHandle> blob_data_handle = SetupBasicBlob(kId);
EXPECT_TRUE(blob_data_handle);
- // Drop the host's ref to it.
- EXPECT_TRUE(host.DecrementBlobRefCount(kId));
-
- // Should still be there due to the handle.
- scoped_ptr<BlobDataHandle> another_handle =
- context.GetBlobDataFromUUID(kId);
+ // Get another handle
+ scoped_ptr<BlobDataHandle> another_handle = context_.GetBlobDataFromUUID(kId);
EXPECT_TRUE(another_handle);
// Should disappear after dropping both handles.
blob_data_handle.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(context_.registry().HasEntry(kId));
+
another_handle.reset();
base::RunLoop().RunUntilIdle();
- blob_data_handle = context.GetBlobDataFromUUID(kId);
+ blob_data_handle = context_.GetBlobDataFromUUID(kId);
EXPECT_FALSE(blob_data_handle);
}
-TEST(BlobStorageContextTest, MemoryUsage) {
+TEST_F(BlobStorageContextTest, MemoryUsage) {
const std::string kId1("id1");
const std::string kId2("id2");
@@ -181,27 +178,30 @@ TEST(BlobStorageContextTest, MemoryUsage) {
builder2.AppendBlob(kId1);
builder2.AppendBlob(kId1);
- BlobStorageContext context;
- EXPECT_EQ(0lu, context.memory_usage());
+ EXPECT_EQ(0lu, context_.memory_usage());
scoped_ptr<BlobDataHandle> blob_data_handle =
- context.AddFinishedBlob(&builder1);
- EXPECT_EQ(10lu, context.memory_usage());
+ context_.AddFinishedBlob(&builder1);
+ EXPECT_EQ(10lu, context_.memory_usage());
scoped_ptr<BlobDataHandle> blob_data_handle2 =
- context.AddFinishedBlob(&builder2);
- EXPECT_EQ(10lu, context.memory_usage());
+ context_.AddFinishedBlob(&builder2);
+ EXPECT_EQ(10lu, context_.memory_usage());
+
+ EXPECT_EQ(2u, context_.registry().blob_count());
blob_data_handle.reset();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(10lu, context.memory_usage());
+ EXPECT_EQ(10lu, context_.memory_usage());
+ EXPECT_EQ(1u, context_.registry().blob_count());
blob_data_handle2.reset();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0lu, context.memory_usage());
+ EXPECT_EQ(0lu, context_.memory_usage());
+ EXPECT_EQ(0u, context_.registry().blob_count());
}
-TEST(BlobStorageContextTest, AddFinishedBlob) {
+TEST_F(BlobStorageContextTest, AddFinishedBlob) {
const std::string kId1("id1");
const std::string kId2("id12");
const std::string kId2Prime("id2.prime");
@@ -222,9 +222,9 @@ TEST(BlobStorageContextTest, AddFinishedBlob) {
BlobStorageContext context;
scoped_ptr<BlobDataHandle> blob_data_handle =
- context.AddFinishedBlob(&builder1);
+ context_.AddFinishedBlob(&builder1);
scoped_ptr<BlobDataHandle> blob_data_handle2 =
- context.AddFinishedBlob(&builder2);
+ context_.AddFinishedBlob(&builder2);
ASSERT_TRUE(blob_data_handle);
ASSERT_TRUE(blob_data_handle2);
@@ -237,7 +237,7 @@ TEST(BlobStorageContextTest, AddFinishedBlob) {
base::RunLoop().RunUntilIdle();
- blob_data_handle = context.GetBlobDataFromUUID(kId1);
+ blob_data_handle = context_.GetBlobDataFromUUID(kId1);
EXPECT_FALSE(blob_data_handle);
EXPECT_TRUE(blob_data_handle2);
data2 = blob_data_handle2->CreateSnapshot();
@@ -248,11 +248,11 @@ TEST(BlobStorageContextTest, AddFinishedBlob) {
builder3.AppendBlob(kId2);
builder3.AppendBlob(kId2);
scoped_ptr<BlobDataHandle> blob_data_handle3 =
- context.AddFinishedBlob(&builder3);
+ context_.AddFinishedBlob(&builder3);
blob_data_handle2.reset();
base::RunLoop().RunUntilIdle();
- blob_data_handle2 = context.GetBlobDataFromUUID(kId2);
+ blob_data_handle2 = context_.GetBlobDataFromUUID(kId2);
EXPECT_FALSE(blob_data_handle2);
EXPECT_TRUE(blob_data_handle3);
scoped_ptr<BlobDataSnapshot> data3 = blob_data_handle3->CreateSnapshot();
@@ -270,7 +270,7 @@ TEST(BlobStorageContextTest, AddFinishedBlob) {
base::RunLoop().RunUntilIdle();
}
-TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
+TEST_F(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
// A value which does not fit in a 4-byte data type. Used to confirm that
// large values are supported on 32-bit Chromium builds. Regression test for:
// crbug.com/458122.
@@ -287,11 +287,10 @@ TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
BlobDataBuilder builder2(kId2);
builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
- BlobStorageContext context;
scoped_ptr<BlobDataHandle> blob_data_handle1 =
- context.AddFinishedBlob(&builder1);
+ context_.AddFinishedBlob(&builder1);
scoped_ptr<BlobDataHandle> blob_data_handle2 =
- context.AddFinishedBlob(&builder2);
+ context_.AddFinishedBlob(&builder2);
ASSERT_TRUE(blob_data_handle1);
ASSERT_TRUE(blob_data_handle2);
@@ -306,14 +305,13 @@ TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
base::RunLoop().RunUntilIdle();
}
-TEST(BlobStorageContextTest, BuildDiskCacheBlob) {
+TEST_F(BlobStorageContextTest, BuildDiskCacheBlob) {
base::MessageLoop fake_io_message_loop;
scoped_refptr<BlobDataBuilder::DataHandle>
data_handle = new EmptyDataHandle();
{
- scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
- BlobStorageHost host(context.get());
+ BlobStorageContext context;
scoped_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
ASSERT_TRUE(cache);
@@ -333,7 +331,7 @@ TEST(BlobStorageContextTest, BuildDiskCacheBlob) {
data_handle, entry.get(), kTestDiskCacheStreamIndex);
scoped_ptr<BlobDataHandle> blob_data_handle =
- context->AddFinishedBlob(&builder);
+ context.AddFinishedBlob(&builder);
scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
EXPECT_EQ(*data, builder);
EXPECT_FALSE(data_handle->HasOneRef())
@@ -344,7 +342,7 @@ TEST(BlobStorageContextTest, BuildDiskCacheBlob) {
base::RunLoop().RunUntilIdle();
}
-TEST(BlobStorageContextTest, CompoundBlobs) {
+TEST_F(BlobStorageContextTest, CompoundBlobs) {
const std::string kId1("id1");
const std::string kId2("id2");
const std::string kId3("id3");
@@ -390,7 +388,7 @@ TEST(BlobStorageContextTest, CompoundBlobs) {
scoped_ptr<BlobDataHandle> blob_data_handle;
// Test a blob referring to only data and a file.
- blob_data_handle = context.AddFinishedBlob(&blob_data1);
+ blob_data_handle = context_.AddFinishedBlob(&blob_data1);
ASSERT_TRUE(blob_data_handle);
scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
@@ -398,14 +396,14 @@ TEST(BlobStorageContextTest, CompoundBlobs) {
EXPECT_EQ(*data, blob_data1);
// Test a blob composed in part with another blob.
- blob_data_handle = context.AddFinishedBlob(&blob_data2);
+ blob_data_handle = context_.AddFinishedBlob(&blob_data2);
data = blob_data_handle->CreateSnapshot();
ASSERT_TRUE(blob_data_handle);
ASSERT_TRUE(data);
EXPECT_EQ(*data, canonicalized_blob_data2);
// Test a blob referring to only data and a disk cache entry.
- blob_data_handle = context.AddFinishedBlob(&blob_data3);
+ blob_data_handle = context_.AddFinishedBlob(&blob_data3);
data = blob_data_handle->CreateSnapshot();
ASSERT_TRUE(blob_data_handle);
EXPECT_EQ(*data, blob_data3);
@@ -414,79 +412,85 @@ TEST(BlobStorageContextTest, CompoundBlobs) {
base::RunLoop().RunUntilIdle();
}
-TEST(BlobStorageContextTest, PublicBlobUrls) {
- BlobStorageContext context;
- BlobStorageHost host(&context);
+TEST_F(BlobStorageContextTest, PublicBlobUrls) {
base::MessageLoop fake_io_message_loop;
// Build up a basic blob.
const std::string kId("id");
- SetupBasicBlob(&host, kId);
+ scoped_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId);
// Now register a url for that blob.
GURL kUrl("blob:id");
- EXPECT_TRUE(host.RegisterPublicBlobURL(kUrl, kId));
+ context_.RegisterPublicBlobURL(kUrl, kId);
scoped_ptr<BlobDataHandle> blob_data_handle =
- context.GetBlobDataFromPublicURL(kUrl);
+ context_.GetBlobDataFromPublicURL(kUrl);
ASSERT_TRUE(blob_data_handle.get());
EXPECT_EQ(kId, blob_data_handle->uuid());
scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
blob_data_handle.reset();
+ first_handle.reset();
base::RunLoop().RunUntilIdle();
// The url registration should keep the blob alive even after
// explicit references are dropped.
- EXPECT_TRUE(host.DecrementBlobRefCount(kId));
- blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
+ blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl);
EXPECT_TRUE(blob_data_handle);
blob_data_handle.reset();
base::RunLoop().RunUntilIdle();
// Finally get rid of the url registration and the blob.
- EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
- blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
- EXPECT_TRUE(!blob_data_handle.get());
- EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
-}
-
-TEST(BlobStorageContextTest, HostCleanup) {
- BlobStorageContext context;
- scoped_ptr<BlobStorageHost> host(new BlobStorageHost(&context));
- base::MessageLoop fake_io_message_loop;
-
- // Build up a basic blob and register a url
- const std::string kId("id");
- GURL kUrl("blob:id");
- SetupBasicBlob(host.get(), kId);
- EXPECT_TRUE(host->RegisterPublicBlobURL(kUrl, kId));
-
- // All should disappear upon host deletion.
- host.reset();
- scoped_ptr<BlobDataHandle> handle = context.GetBlobDataFromPublicURL(kUrl);
- EXPECT_TRUE(!handle.get());
- handle = context.GetBlobDataFromUUID(kId);
- EXPECT_TRUE(!handle.get());
+ context_.RevokePublicBlobURL(kUrl);
+ blob_data_handle = context_.GetBlobDataFromPublicURL(kUrl);
+ EXPECT_FALSE(blob_data_handle.get());
+ EXPECT_FALSE(context_.registry().HasEntry(kId));
}
-TEST(BlobStorageContextTest, EarlyContextDeletion) {
- scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
- BlobStorageHost host(context.get());
+TEST_F(BlobStorageContextTest, TestUnknownBrokenAndBuildingBlobReference) {
base::MessageLoop fake_io_message_loop;
-
- // Deleting the context should not induce crashes.
- context.reset();
-
- const std::string kId("id");
- GURL kUrl("blob:id");
- EXPECT_FALSE(host.StartBuildingBlob(kId));
- DataElement item;
- item.SetToBytes("1", 1);
- EXPECT_FALSE(host.AppendBlobDataItem(kId, item));
- EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
- EXPECT_FALSE(host.RegisterPublicBlobURL(kUrl, kId));
- EXPECT_FALSE(host.IncrementBlobRefCount(kId));
- EXPECT_FALSE(host.DecrementBlobRefCount(kId));
- EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
+ const std::string kBrokenId("broken_id");
+ const std::string kBuildingId("building_id");
+ const std::string kReferencingId("referencing_id");
+ const std::string kUnknownId("unknown_id");
+
+ // Create a broken blob and a building blob.
+ context_.CreatePendingBlob(kBuildingId, "", "");
+ context_.CreatePendingBlob(kBrokenId, "", "");
+ context_.CancelPendingBlob(kBrokenId, IPCBlobCreationCancelCode::UNKNOWN);
+ EXPECT_TRUE(context_.IsBroken(kBrokenId));
+ EXPECT_TRUE(context_.registry().HasEntry(kBrokenId));
+
+ // Try to create a blob with a reference to an unknown blob.
+ BlobDataBuilder builder(kReferencingId);
+ builder.AppendData("data");
+ builder.AppendBlob(kUnknownId);
+ scoped_ptr<BlobDataHandle> handle = context_.AddFinishedBlob(builder);
+ EXPECT_TRUE(handle->IsBroken());
+ EXPECT_TRUE(context_.registry().HasEntry(kReferencingId));
+ handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_.registry().HasEntry(kReferencingId));
+
+ // Try to create a blob with a reference to the broken blob.
+ BlobDataBuilder builder2(kReferencingId);
+ builder2.AppendData("data");
+ builder2.AppendBlob(kBrokenId);
+ handle = context_.AddFinishedBlob(builder2);
+ EXPECT_TRUE(handle->IsBroken());
+ EXPECT_TRUE(context_.registry().HasEntry(kReferencingId));
+ handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_.registry().HasEntry(kReferencingId));
+
+ // Try to create a blob with a reference to the building blob.
+ BlobDataBuilder builder3(kReferencingId);
+ builder3.AppendData("data");
+ builder3.AppendBlob(kBuildingId);
+ handle = context_.AddFinishedBlob(builder3);
+ EXPECT_TRUE(handle->IsBroken());
+ EXPECT_TRUE(context_.registry().HasEntry(kReferencingId));
+ handle.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(context_.registry().HasEntry(kReferencingId));
}
// TODO(michaeln): tests for the depcrecated url stuff
diff --git a/chromium/content/browser/fileapi/blob_storage_host.cc b/chromium/content/browser/fileapi/blob_storage_host.cc
deleted file mode 100644
index faf81010dd3..00000000000
--- a/chromium/content/browser/fileapi/blob_storage_host.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/fileapi/blob_storage_host.h"
-
-#include "base/sequenced_task_runner.h"
-#include "base/strings/string_util.h"
-#include "storage/browser/blob/blob_storage_context.h"
-#include "url/gurl.h"
-
-using storage::BlobStorageContext;
-
-namespace content {
-
-BlobStorageHost::BlobStorageHost(BlobStorageContext* context)
- : context_(context->AsWeakPtr()) {
-}
-
-BlobStorageHost::~BlobStorageHost() {
- if (!context_.get())
- return;
- for (std::set<GURL>::iterator iter = public_blob_urls_.begin();
- iter != public_blob_urls_.end(); ++iter) {
- context_->RevokePublicBlobURL(*iter);
- }
- for (BlobReferenceMap::iterator iter = blobs_inuse_map_.begin();
- iter != blobs_inuse_map_.end(); ++iter) {
- for (int i = 0; i < iter->second; ++i)
- context_->DecrementBlobRefCount(iter->first);
- }
-}
-
-bool BlobStorageHost::StartBuildingBlob(const std::string& uuid) {
- if (!context_.get() || uuid.empty() || context_->IsInUse(uuid))
- return false;
- context_->StartBuildingBlob(uuid);
- blobs_inuse_map_[uuid] = 1;
- return true;
-}
-
-bool BlobStorageHost::AppendBlobDataItem(
- const std::string& uuid,
- const storage::DataElement& data_item) {
- if (!context_.get() || !IsBeingBuiltInHost(uuid))
- return false;
- context_->AppendBlobDataItem(uuid, data_item);
- return true;
-}
-
-bool BlobStorageHost::CancelBuildingBlob(const std::string& uuid) {
- if (!context_.get() || !IsBeingBuiltInHost(uuid))
- return false;
- blobs_inuse_map_.erase(uuid);
- context_->CancelBuildingBlob(uuid);
- return true;
-}
-
-bool BlobStorageHost::FinishBuildingBlob(
- const std::string& uuid, const std::string& content_type) {
- if (!context_.get() || !IsBeingBuiltInHost(uuid))
- return false;
- context_->FinishBuildingBlob(uuid, content_type);
- return true;
-}
-
-bool BlobStorageHost::IncrementBlobRefCount(const std::string& uuid) {
- if (!context_.get() || !context_->IsInUse(uuid) ||
- context_->IsBeingBuilt(uuid))
- return false;
- context_->IncrementBlobRefCount(uuid);
- blobs_inuse_map_[uuid] += 1;
- return true;
-}
-
-bool BlobStorageHost::DecrementBlobRefCount(const std::string& uuid) {
- if (!context_.get() || !IsInUseInHost(uuid))
- return false;
- context_->DecrementBlobRefCount(uuid);
- blobs_inuse_map_[uuid] -= 1;
- if (blobs_inuse_map_[uuid] == 0)
- blobs_inuse_map_.erase(uuid);
- return true;
-}
-
-bool BlobStorageHost::RegisterPublicBlobURL(
- const GURL& blob_url, const std::string& uuid) {
- if (!context_.get() || !IsInUseInHost(uuid) ||
- context_->IsUrlRegistered(blob_url))
- return false;
- context_->RegisterPublicBlobURL(blob_url, uuid);
- public_blob_urls_.insert(blob_url);
- return true;
-}
-
-bool BlobStorageHost::RevokePublicBlobURL(const GURL& blob_url) {
- if (!context_.get() || !IsUrlRegisteredInHost(blob_url))
- return false;
- context_->RevokePublicBlobURL(blob_url);
- public_blob_urls_.erase(blob_url);
- return true;
-}
-
-bool BlobStorageHost::IsInUseInHost(const std::string& uuid) {
- return blobs_inuse_map_.find(uuid) != blobs_inuse_map_.end();
-}
-
-bool BlobStorageHost::IsBeingBuiltInHost(const std::string& uuid) {
- return IsInUseInHost(uuid) && context_->IsBeingBuilt(uuid);
-}
-
-bool BlobStorageHost::IsUrlRegisteredInHost(const GURL& blob_url) {
- return public_blob_urls_.find(blob_url) != public_blob_urls_.end();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/fileapi/blob_storage_host.h b/chromium/content/browser/fileapi/blob_storage_host.h
deleted file mode 100644
index ecfbc569262..00000000000
--- a/chromium/content/browser/fileapi/blob_storage_host.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
-#define CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
-#include "storage/common/data_element.h"
-
-class GURL;
-
-namespace storage {
-class BlobDataHandle;
-class BlobStorageHost;
-class BlobStorageContext;
-}
-
-namespace content {
-
-// This class handles the logistics of blob storage for a single child process.
-// There is one instance per child process. When the child process
-// terminates all blob references attibutable to that process go away upon
-// destruction of the instance. The class is single threaded and should
-// only be used on the IO thread.
-class CONTENT_EXPORT BlobStorageHost {
- public:
- explicit BlobStorageHost(storage::BlobStorageContext* context);
- ~BlobStorageHost();
-
- // Methods to support the IPC message protocol.
- // A false return indicates a problem with the inputs
- // like a non-existent or pre-existent uuid or url.
- bool StartBuildingBlob(const std::string& uuid) WARN_UNUSED_RESULT;
- bool AppendBlobDataItem(const std::string& uuid,
- const storage::DataElement& data_item)
- WARN_UNUSED_RESULT;
- bool CancelBuildingBlob(const std::string& uuid) WARN_UNUSED_RESULT;
- bool FinishBuildingBlob(const std::string& uuid,
- const std::string& type) WARN_UNUSED_RESULT;
- bool IncrementBlobRefCount(const std::string& uuid) WARN_UNUSED_RESULT;
- bool DecrementBlobRefCount(const std::string& uuid) WARN_UNUSED_RESULT;
- bool RegisterPublicBlobURL(const GURL& blob_url,
- const std::string& uuid) WARN_UNUSED_RESULT;
- bool RevokePublicBlobURL(const GURL& blob_url) WARN_UNUSED_RESULT;
-
- private:
- typedef std::map<std::string, int> BlobReferenceMap;
-
- bool IsInUseInHost(const std::string& uuid);
- bool IsBeingBuiltInHost(const std::string& uuid);
- bool IsUrlRegisteredInHost(const GURL& blob_url);
-
- // Collection of blob ids and a count of how many usages
- // of that id are attributable to this consumer.
- BlobReferenceMap blobs_inuse_map_;
-
- // The set of public blob urls coined by this consumer.
- std::set<GURL> public_blob_urls_;
-
- base::WeakPtr<storage::BlobStorageContext> context_;
-
- DISALLOW_COPY_AND_ASSIGN(BlobStorageHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_FILEAPI_BLOB_STORAGE_HOST_H_
diff --git a/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc b/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
index 782a1e581db..bdb430fe14a 100644
--- a/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
@@ -534,7 +534,7 @@ TEST_F(BlobURLRequestJobTest, TestExtraHeaders) {
std::string content_type;
EXPECT_TRUE(request_->response_headers()->GetMimeType(&content_type));
EXPECT_EQ(kTestContentType, content_type);
- void* iter = NULL;
+ size_t iter = 0;
std::string content_disposition;
EXPECT_TRUE(request_->response_headers()->EnumerateHeader(
&iter, "Content-Disposition", &content_disposition));
diff --git a/chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc b/chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
index 055b8f2c97f..6e2fcca758c 100644
--- a/chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
@@ -619,8 +619,10 @@ TEST(LocalFileSystemCopyOrMoveOperationTest,
ASSERT_TRUE(helper.DirectoryExists(src));
ASSERT_TRUE(helper.DirectoryExists(dest));
+ // In the move operation, [file 0, file 2, file 3] are processed as LIFO.
+ // After file 3 is processed, file 2 is rejected by the validator and the
+ // operation fails. That is, only file 3 should be in dest.
FileSystemTestCaseRecord kMoveDirResultCases[] = {
- {false, FILE_PATH_LITERAL("file 0"), 38},
{false, FILE_PATH_LITERAL("file 3"), 0},
};
diff --git a/chromium/content/browser/fileapi/dragged_file_util_unittest.cc b/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
index 07c983bad4a..63ba54abae4 100644
--- a/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
@@ -15,6 +15,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "build/build_config.h"
diff --git a/chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
index 15f376ce44b..8a535bbdd06 100644
--- a/chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
@@ -22,7 +22,6 @@
#include "content/public/test/test_file_system_backend.h"
#include "content/public/test/test_file_system_context.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
#include "net/base/request_priority.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
@@ -252,9 +251,11 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
const std::string& url,
bool is_directory,
int64_t size) {
+#define NUMBER "([0-9-]*)"
#define STR "([^\"]*)"
icu::UnicodeString pattern("^<script>addRow\\(\"" STR "\",\"" STR
- "\",(0|1),\"" STR "\",\"" STR "\"\\);</script>");
+ "\",(0|1)," NUMBER ",\"" STR "\"," NUMBER ",\"" STR "\"\\);</script>");
+#undef NUMBER
#undef STR
icu::UnicodeString input(entry_line.c_str());
@@ -262,7 +263,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
icu::RegexMatcher match(pattern, input, 0, status);
EXPECT_TRUE(match.find());
- EXPECT_EQ(5, match.groupCount());
+ EXPECT_EQ(7, match.groupCount());
EXPECT_EQ(icu::UnicodeString(name.c_str()), match.group(1, status));
EXPECT_EQ(icu::UnicodeString(url.c_str()), match.group(2, status));
EXPECT_EQ(icu::UnicodeString(is_directory ? "1" : "0"),
@@ -270,10 +271,10 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
if (size >= 0) {
icu::UnicodeString size_string(
base::FormatBytesUnlocalized(size).c_str());
- EXPECT_EQ(size_string, match.group(4, status));
+ EXPECT_EQ(size_string, match.group(5, status));
}
- icu::UnicodeString date_ustr(match.group(5, status));
+ icu::UnicodeString date_ustr(match.group(7, status));
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
UErrorCode parse_status = U_ZERO_ERROR;
diff --git a/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc b/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
index e3a24c20151..a1e4f8d05bb 100644
--- a/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
@@ -8,6 +8,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
diff --git a/chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc b/chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc
index 4b2715c29ab..58ab33b6ea4 100644
--- a/chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc
@@ -27,7 +27,6 @@
#include "net/base/load_flags.h"
#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
#include "net/base/request_priority.h"
#include "net/http/http_byte_range.h"
#include "net/http/http_request_headers.h"
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.cc b/chromium/content/browser/fileapi/fileapi_message_filter.cc
index 8594aef48bd..318d9566448 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.cc
@@ -20,7 +20,6 @@
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/fileapi/blob_storage_host.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/streams/stream_registry.h"
@@ -56,9 +55,7 @@ namespace content {
namespace {
-const uint32_t kFilteredMessageClasses[] = {
- BlobMsgStart, FileSystemMsgStart,
-};
+const uint32_t kFilteredMessageClasses[] = {FileSystemMsgStart, BlobMsgStart};
void RevokeFilePermission(int child_id, const base::FilePath& path) {
ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
@@ -118,18 +115,13 @@ void FileAPIMessageFilter::OnChannelConnected(int32_t peer_pid) {
DCHECK(request_context_);
}
- blob_storage_host_.reset(
- new BlobStorageHost(blob_storage_context_->context()));
-
operation_runner_ = context_->CreateFileSystemOperationRunner();
}
void FileAPIMessageFilter::OnChannelClosing() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Unregister all the blob and stream URLs that are previously registered in
- // this process.
- blob_storage_host_.reset();
+ // Unregister all stream URLs that are previously registered in this process.
for (base::hash_set<std::string>::const_iterator iter = stream_urls_.begin();
iter != stream_urls_.end(); ++iter) {
stream_context_->registry()->UnregisterStream(GURL(*iter));
@@ -171,19 +163,6 @@ bool FileAPIMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnDidReceiveSnapshotFile)
IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
OnSyncGetPlatformPath)
- IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob)
- IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem,
- OnAppendBlobDataItemToBlob)
- IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory,
- OnAppendSharedMemoryToBlob)
- IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob)
- IPC_MESSAGE_HANDLER(BlobHostMsg_IncrementRefCount,
- OnIncrementBlobRefCount)
- IPC_MESSAGE_HANDLER(BlobHostMsg_DecrementRefCount,
- OnDecrementBlobRefCount)
- IPC_MESSAGE_HANDLER(BlobHostMsg_RegisterPublicURL,
- OnRegisterPublicBlobURL)
- IPC_MESSAGE_HANDLER(BlobHostMsg_RevokePublicURL, OnRevokePublicBlobURL)
IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream)
IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem,
OnAppendBlobDataItemToStream)
@@ -514,90 +493,6 @@ void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
in_transit_snapshot_files_.erase(request_id);
}
-void FileAPIMessageFilter::OnStartBuildingBlob(const std::string& uuid) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->StartBuildingBlob(uuid));
-}
-
-void FileAPIMessageFilter::OnAppendBlobDataItemToBlob(
- const std::string& uuid,
- const storage::DataElement& item) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (item.type() == storage::DataElement::TYPE_FILE_FILESYSTEM) {
- FileSystemURL filesystem_url(context_->CrackURL(item.filesystem_url()));
- if (!FileSystemURLIsValid(context_, filesystem_url) ||
- !security_policy_->CanReadFileSystemFile(process_id_, filesystem_url)) {
- ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
- return;
- }
- }
- if (item.type() == storage::DataElement::TYPE_FILE &&
- !security_policy_->CanReadFile(process_id_, item.path())) {
- ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
- return;
- }
- if (item.length() == 0) {
- bad_message::ReceivedBadMessage(this,
- bad_message::FAMF_APPEND_ITEM_TO_BLOB);
- return;
- }
- ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
-}
-
-void FileAPIMessageFilter::OnAppendSharedMemoryToBlob(
- const std::string& uuid,
- base::SharedMemoryHandle handle,
- size_t buffer_size) {
- DCHECK(base::SharedMemory::IsHandleValid(handle));
- if (!buffer_size) {
- bad_message::ReceivedBadMessage(
- this, bad_message::FAMF_APPEND_SHARED_MEMORY_TO_BLOB);
- return;
- }
-#if defined(OS_WIN)
- base::SharedMemory shared_memory(handle, true, PeerHandle());
-#else
- base::SharedMemory shared_memory(handle, true);
-#endif
- if (!shared_memory.Map(buffer_size)) {
- ignore_result(blob_storage_host_->CancelBuildingBlob(uuid));
- return;
- }
-
- storage::DataElement item;
- item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()),
- buffer_size);
- ignore_result(blob_storage_host_->AppendBlobDataItem(uuid, item));
-}
-
-void FileAPIMessageFilter::OnFinishBuildingBlob(
- const std::string& uuid, const std::string& content_type) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->FinishBuildingBlob(uuid, content_type));
- // TODO(michaeln): check return values once blink has migrated, crbug/174200
-}
-
-void FileAPIMessageFilter::OnIncrementBlobRefCount(const std::string& uuid) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->IncrementBlobRefCount(uuid));
-}
-
-void FileAPIMessageFilter::OnDecrementBlobRefCount(const std::string& uuid) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->DecrementBlobRefCount(uuid));
-}
-
-void FileAPIMessageFilter::OnRegisterPublicBlobURL(
- const GURL& public_url, const std::string& uuid) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->RegisterPublicBlobURL(public_url, uuid));
-}
-
-void FileAPIMessageFilter::OnRevokePublicBlobURL(const GURL& public_url) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- ignore_result(blob_storage_host_->RevokePublicBlobURL(public_url));
-}
-
void FileAPIMessageFilter::OnStartBuildingStream(
const GURL& url, const std::string& content_type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -638,18 +533,15 @@ void FileAPIMessageFilter::OnAppendBlobDataItemToStream(
}
void FileAPIMessageFilter::OnAppendSharedMemoryToStream(
- const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) {
+ const GURL& url, base::SharedMemoryHandle handle,
+ uint32_t buffer_size) {
DCHECK(base::SharedMemory::IsHandleValid(handle));
if (!buffer_size) {
bad_message::ReceivedBadMessage(
this, bad_message::FAMF_APPEND_SHARED_MEMORY_TO_STREAM);
return;
}
-#if defined(OS_WIN)
- base::SharedMemory shared_memory(handle, true, PeerHandle());
-#else
base::SharedMemory shared_memory(handle, true);
-#endif
if (!shared_memory.Map(buffer_size)) {
OnRemoveStream(url);
return;
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.h b/chromium/content/browser/fileapi/fileapi_message_filter.h
index 74d056fef8e..7f0a20f340f 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.h
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.h
@@ -46,10 +46,6 @@ class URLRequestContext;
class URLRequestContextGetter;
} // namespace net
-namespace content {
-class BlobStorageHost;
-}
-
namespace storage {
class ShareableFileReference;
class DataElement;
@@ -128,21 +124,6 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
const GURL& path);
void OnDidReceiveSnapshotFile(int request_id);
- // Handlers for BlobHostMsg_ family messages.
-
- void OnStartBuildingBlob(const std::string& uuid);
- void OnAppendBlobDataItemToBlob(const std::string& uuid,
- const storage::DataElement& item);
- void OnAppendSharedMemoryToBlob(const std::string& uuid,
- base::SharedMemoryHandle handle,
- size_t buffer_size);
- void OnFinishBuildingBlob(const std::string& uuid,
- const std::string& content_type);
- void OnIncrementBlobRefCount(const std::string& uuid);
- void OnDecrementBlobRefCount(const std::string& uuid);
- void OnRegisterPublicBlobURL(const GURL& public_url, const std::string& uuid);
- void OnRevokePublicBlobURL(const GURL& public_url);
-
// Handlers for StreamHostMsg_ family messages.
//
// TODO(tyoshino): Consider renaming BlobData to more generic one as it's now
@@ -155,7 +136,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
void OnAppendBlobDataItemToStream(const GURL& url,
const storage::DataElement& item);
void OnAppendSharedMemoryToStream(
- const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size);
+ const GURL& url, base::SharedMemoryHandle handle, uint32_t buffer_size);
void OnFlushStream(const GURL& url);
void OnFinishBuildingStream(const GURL& url);
void OnAbortBuildingStream(const GURL& url);
@@ -229,10 +210,6 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
scoped_ptr<storage::FileSystemOperationRunner> operation_runner_;
- // Keeps track of blobs used in this process and cleans up
- // when the renderer process dies.
- scoped_ptr<BlobStorageHost> blob_storage_host_;
-
// Keep track of stream URLs registered in this process. Need to unregister
// all of them when the renderer process dies.
base::hash_set<std::string> stream_urls_;
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
index 1fe224e38ec..b7d61e389d7 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
@@ -249,7 +249,7 @@ TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
ASSERT_TRUE(shared_memory->CreateAndMapAnonymous(kFakeData.size()));
memcpy(shared_memory->memory(), kFakeData.data(), kFakeData.size());
StreamHostMsg_SyncAppendSharedMemory append_message(
- kUrl, shared_memory->handle(), kFakeData.size());
+ kUrl, shared_memory->handle(), static_cast<uint32_t>(kFakeData.size()));
EXPECT_TRUE(filter_->OnMessageReceived(append_message));
StreamHostMsg_FinishBuilding finish_message(kUrl);
diff --git a/chromium/content/browser/fileapi/local_file_util_unittest.cc b/chromium/content/browser/fileapi/local_file_util_unittest.cc
index 28ff6b3ba9d..071a122279a 100644
--- a/chromium/content/browser/fileapi/local_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/local_file_util_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/content/browser/fileapi/native_file_util_unittest.cc b/chromium/content/browser/fileapi/native_file_util_unittest.cc
index 210f8b9cca5..5a91454bbfc 100644
--- a/chromium/content/browser/fileapi/native_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/native_file_util_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "storage/browser/fileapi/native_file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc b/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc
index abcdf54e65b..8c00f0c7c31 100644
--- a/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
diff --git a/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc b/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
index 8338304e6a6..ce89ae6b8e7 100644
--- a/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
@@ -15,6 +15,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "content/browser/fileapi/sandbox_database_test_helper.h"
#include "storage/browser/fileapi/sandbox_origin_database.h"
diff --git a/chromium/content/browser/fileapi/upload_file_system_file_element_reader.h b/chromium/content/browser/fileapi/upload_file_system_file_element_reader.h
index 5510ce540b6..cba9fa795d8 100644
--- a/chromium/content/browser/fileapi/upload_file_system_file_element_reader.h
+++ b/chromium/content/browser/fileapi/upload_file_system_file_element_reader.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/frame_host/OWNERS b/chromium/content/browser/frame_host/OWNERS
index 2d5011da465..cb3028c329e 100644
--- a/chromium/content/browser/frame_host/OWNERS
+++ b/chromium/content/browser/frame_host/OWNERS
@@ -1 +1,2 @@
+alexmos@chromium.org
clamy@chromium.org
diff --git a/chromium/content/browser/frame_host/PRESUBMIT.py b/chromium/content/browser/frame_host/PRESUBMIT.py
new file mode 100644
index 00000000000..d3afe71d89e
--- /dev/null
+++ b/chromium/content/browser/frame_host/PRESUBMIT.py
@@ -0,0 +1,53 @@
+# 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.
+"""Presubmit script for //content/browser/frame_host.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+import re
+
+
+def _GetTryMasters(project, change):
+ return {
+ 'tryserver.chromium.linux': {
+ 'linux_site_isolation': [],
+ },
+ }
+
+
+def GetPreferredTryMasters(project, change):
+ # TODO(nick, dcheng): Using the value of _GetTryMasters() instead of an empty
+ # value here would cause 'git cl try' to include the site isolation trybots,
+ # which would be nice. But it has the side effect of replacing, rather than
+ # augmenting, the default set of try servers. Re-enable this when we figure
+ # out a way to augment the default set.
+ return {}
+
+
+def PostUploadHook(cl, change, output_api):
+ """git cl upload will call this hook after the issue is created/modified.
+
+ This hook adds extra try bots to the CL description in order to run site
+ isolation tests in addition to CQ try bots.
+ """
+ rietveld_obj = cl.RpcServer()
+ issue = cl.issue
+ description = rietveld_obj.get_description(issue)
+ if re.search(r'^CQ_INCLUDE_TRYBOTS=.*', description, re.M | re.I):
+ return []
+
+ masters = _GetTryMasters(None, change)
+ results = []
+ new_description = description
+ new_description += '\nCQ_INCLUDE_TRYBOTS=%s' % ';'.join(
+ '%s:%s' % (master, ','.join(bots))
+ for master, bots in masters.iteritems())
+ results.append(output_api.PresubmitNotifyResult(
+ 'Automatically added site isolation trybots to run tests on CQ.'))
+
+ rietveld_obj.update_description(issue, new_description)
+
+ return results
diff --git a/chromium/content/browser/frame_host/cross_process_frame_connector.cc b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
index 1d8b23c0411..b5e415ced16 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
@@ -17,7 +17,7 @@
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/frame_messages.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
namespace content {
@@ -38,10 +38,6 @@ bool CrossProcessFrameConnector::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CrossProcessFrameConnector, msg)
- IPC_MESSAGE_HANDLER(FrameHostMsg_CompositorFrameSwappedACK,
- OnCompositorFrameSwappedACK)
- IPC_MESSAGE_HANDLER(FrameHostMsg_ReclaimCompositorResources,
- OnReclaimCompositorResources)
IPC_MESSAGE_HANDLER(FrameHostMsg_ForwardInputEvent, OnForwardInputEvent)
IPC_MESSAGE_HANDLER(FrameHostMsg_FrameRectChanged, OnFrameRectChanged)
IPC_MESSAGE_HANDLER(FrameHostMsg_VisibilityChanged, OnVisibilityChanged)
@@ -67,7 +63,7 @@ void CrossProcessFrameConnector::set_view(
if (view_) {
view_->set_cross_process_frame_connector(this);
SetDeviceScaleFactor(device_scale_factor_);
- SetSize(child_frame_rect_);
+ SetRect(child_frame_rect_);
}
}
@@ -76,20 +72,6 @@ void CrossProcessFrameConnector::RenderProcessGone() {
frame_proxy_in_parent_renderer_->GetRoutingID()));
}
-void CrossProcessFrameConnector::ChildFrameCompositorFrameSwapped(
- uint32_t output_surface_id,
- int host_id,
- int route_id,
- scoped_ptr<cc::CompositorFrame> frame) {
- FrameMsg_CompositorFrameSwapped_Params params;
- frame->AssignTo(&params.frame);
- params.output_surface_id = output_surface_id;
- params.producing_route_id = route_id;
- params.producing_host_id = host_id;
- frame_proxy_in_parent_renderer_->Send(new FrameMsg_CompositorFrameSwapped(
- frame_proxy_in_parent_renderer_->GetRoutingID(), params));
-}
-
void CrossProcessFrameConnector::SetChildFrameSurface(
const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
@@ -120,29 +102,13 @@ void CrossProcessFrameConnector::OnRequireSequence(
surface->AddDestructionDependency(sequence);
}
-void CrossProcessFrameConnector::OnCompositorFrameSwappedACK(
- const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
- params.output_surface_id,
- params.producing_host_id,
- params.ack);
-}
-
-void CrossProcessFrameConnector::OnReclaimCompositorResources(
- const FrameHostMsg_ReclaimCompositorResources_Params& params) {
- RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
- params.output_surface_id,
- params.renderer_host_id,
- params.ack);
-}
-
void CrossProcessFrameConnector::OnInitializeChildFrame(gfx::Rect frame_rect,
float scale_factor) {
if (scale_factor != device_scale_factor_)
SetDeviceScaleFactor(scale_factor);
if (!frame_rect.size().IsEmpty())
- SetSize(frame_rect);
+ SetRect(frame_rect);
}
gfx::Rect CrossProcessFrameConnector::ChildFrameRect() {
@@ -150,20 +116,10 @@ gfx::Rect CrossProcessFrameConnector::ChildFrameRect() {
}
void CrossProcessFrameConnector::GetScreenInfo(blink::WebScreenInfo* results) {
- // Inner WebContents's root FrameTreeNode does not have a parent(), so
- // GetRenderWidgetHostView() call below will fail.
- // TODO(lazyboy): Fix this.
- if (frame_proxy_in_parent_renderer_->frame_tree_node()
- ->render_manager()
- ->ForInnerDelegate()) {
- DCHECK(frame_proxy_in_parent_renderer_->frame_tree_node()->IsMainFrame());
- return;
+ auto parent_view = GetParentRenderWidgetHostView();
+ if (parent_view) {
+ parent_view->GetScreenInfo(results);
}
-
- RenderWidgetHostView* rwhv =
- frame_proxy_in_parent_renderer_->GetRenderWidgetHostView();
- if (rwhv)
- static_cast<RenderWidgetHostViewBase*>(rwhv)->GetScreenInfo(results);
}
void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) {
@@ -172,15 +128,23 @@ void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) {
root_view->UpdateCursor(cursor);
}
-void CrossProcessFrameConnector::TransformPointToRootCoordSpace(
+gfx::Point CrossProcessFrameConnector::TransformPointToRootCoordSpace(
const gfx::Point& point,
- cc::SurfaceId surface_id,
- gfx::Point* transformed_point) {
+ cc::SurfaceId surface_id) {
+ gfx::Point transformed_point = point;
RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView();
- *transformed_point = point;
if (root_view)
root_view->TransformPointToLocalCoordSpace(point, surface_id,
- transformed_point);
+ &transformed_point);
+ return transformed_point;
+}
+
+void CrossProcessFrameConnector::ForwardProcessAckedTouchEvent(
+ const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) {
+ auto main_view = GetRootRenderWidgetHostView();
+ if (main_view)
+ main_view->ProcessAckedTouchEvent(touch, ack_result);
}
bool CrossProcessFrameConnector::HasFocus() {
@@ -190,6 +154,12 @@ bool CrossProcessFrameConnector::HasFocus() {
return false;
}
+void CrossProcessFrameConnector::FocusRootView() {
+ RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView();
+ if (root_view)
+ root_view->Focus();
+}
+
void CrossProcessFrameConnector::OnForwardInputEvent(
const blink::WebInputEvent* event) {
if (!view_)
@@ -202,6 +172,10 @@ void CrossProcessFrameConnector::OnForwardInputEvent(
? manager->GetOuterRenderWidgetHostForKeyboardInput()
: frame_proxy_in_parent_renderer_->GetRenderViewHost()->GetWidget();
+ // TODO(wjmaclean): We should remove these forwarding functions, since they
+ // are directly target using RenderWidgetHostInputEventRouter. But neither
+ // pathway is currently handling gesture events, so that needs to be fixed
+ // in a subsequent CL.
if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
if (!parent_widget->GetLastKeyboardEvent())
return;
@@ -226,13 +200,26 @@ void CrossProcessFrameConnector::OnForwardInputEvent(
void CrossProcessFrameConnector::OnFrameRectChanged(
const gfx::Rect& frame_rect) {
if (!frame_rect.size().IsEmpty())
- SetSize(frame_rect);
+ SetRect(frame_rect);
}
void CrossProcessFrameConnector::OnVisibilityChanged(bool visible) {
if (!view_)
return;
+ // If there is an inner WebContents, it should be notified of the change in
+ // the visibility. The Show/Hide methods will not be called if an inner
+ // WebContents exists since the corresponding WebContents will itself call
+ // Show/Hide on all the RenderWidgetHostViews (including this) one.
+ if (frame_proxy_in_parent_renderer_->frame_tree_node()
+ ->render_manager()
+ ->ForInnerDelegate()) {
+ RenderWidgetHostImpl::From(view_->GetRenderWidgetHost())
+ ->delegate()
+ ->OnRenderFrameProxyVisibilityChanged(visible);
+ return;
+ }
+
if (visible)
view_->Show();
else
@@ -249,10 +236,27 @@ void CrossProcessFrameConnector::SetDeviceScaleFactor(float scale_factor) {
}
}
-void CrossProcessFrameConnector::SetSize(gfx::Rect frame_rect) {
+void CrossProcessFrameConnector::SetRect(const gfx::Rect& frame_rect) {
+ gfx::Rect old_rect = child_frame_rect_;
child_frame_rect_ = frame_rect;
- if (view_)
- view_->SetSize(frame_rect.size());
+ if (view_) {
+ view_->SetBounds(frame_rect);
+
+ // Out-of-process iframes nested underneath this one implicitly have their
+ // view rects changed when their ancestor is repositioned, and therefore
+ // need to have their screen rects updated.
+ FrameTreeNode* proxy_node =
+ frame_proxy_in_parent_renderer_->frame_tree_node();
+ if (old_rect.x() != child_frame_rect_.x() ||
+ old_rect.y() != child_frame_rect_.y()) {
+ for (FrameTreeNode* node :
+ proxy_node->frame_tree()->SubtreeNodes(proxy_node)) {
+ if (node != proxy_node &&
+ node->current_frame_host()->GetRenderWidgetHost())
+ node->current_frame_host()->GetRenderWidgetHost()->SendScreenRects();
+ }
+ }
+ }
}
RenderWidgetHostViewBase*
@@ -270,4 +274,27 @@ CrossProcessFrameConnector::GetRootRenderWidgetHostView() {
return static_cast<RenderWidgetHostViewBase*>(top_host->GetView());
}
+RenderWidgetHostViewBase*
+CrossProcessFrameConnector::GetParentRenderWidgetHostView() {
+ FrameTreeNode* parent =
+ frame_proxy_in_parent_renderer_->frame_tree_node()->parent();
+
+ if (!parent &&
+ frame_proxy_in_parent_renderer_->frame_tree_node()
+ ->render_manager()
+ ->GetOuterDelegateNode()) {
+ parent = frame_proxy_in_parent_renderer_->frame_tree_node()
+ ->render_manager()
+ ->GetOuterDelegateNode()
+ ->parent();
+ }
+
+ if (parent) {
+ return static_cast<RenderWidgetHostViewBase*>(
+ parent->current_frame_host()->GetView());
+ }
+
+ return nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/cross_process_frame_connector.h b/chromium/content/browser/frame_host/cross_process_frame_connector.h
index 6f31ec606fa..0eebdbb5158 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.h
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.h
@@ -8,7 +8,9 @@
#include <stdint.h>
#include "cc/output/compositor_frame.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/common/content_export.h"
+#include "content/common/input/input_event_ack_state.h"
#include "ui/gfx/geometry/rect.h"
namespace blink {
@@ -25,9 +27,6 @@ namespace IPC {
class Message;
}
-struct FrameHostMsg_CompositorFrameSwappedACK_Params;
-struct FrameHostMsg_ReclaimCompositorResources_Params;
-
namespace content {
class RenderFrameProxyHost;
class RenderWidgetHostImpl;
@@ -87,11 +86,6 @@ class CONTENT_EXPORT CrossProcessFrameConnector {
void RenderProcessGone();
- virtual void ChildFrameCompositorFrameSwapped(
- uint32_t output_surface_id,
- int host_id,
- int route_id,
- scoped_ptr<cc::CompositorFrame> frame);
virtual void SetChildFrameSurface(const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
float scale_factor,
@@ -101,20 +95,31 @@ class CONTENT_EXPORT CrossProcessFrameConnector {
float device_scale_factor() const { return device_scale_factor_; }
void GetScreenInfo(blink::WebScreenInfo* results);
void UpdateCursor(const WebCursor& cursor);
- void TransformPointToRootCoordSpace(const gfx::Point& point,
- cc::SurfaceId surface_id,
- gfx::Point* transformed_point);
+ gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point,
+ cc::SurfaceId surface_id);
+ // Pass acked touch events to the root view for gesture processing.
+ void ForwardProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result);
// Determines whether the root RenderWidgetHostView (and thus the current
// page) has focus.
bool HasFocus();
+ // Focuses the root RenderWidgetHostView.
+ void FocusRootView();
+
+ // Returns the parent RenderWidgetHostView or nullptr it it doesn't have one.
+ RenderWidgetHostViewBase* GetParentRenderWidgetHostView();
+
+ // Returns the view for the top-level frame under the same WebContents.
+ RenderWidgetHostViewBase* GetRootRenderWidgetHostView();
+
+ // Exposed for tests.
+ RenderWidgetHostViewBase* GetRootRenderWidgetHostViewForTesting() {
+ return GetRootRenderWidgetHostView();
+ }
private:
// Handlers for messages received from the parent frame.
- void OnCompositorFrameSwappedACK(
- const FrameHostMsg_CompositorFrameSwappedACK_Params& params);
- void OnReclaimCompositorResources(
- const FrameHostMsg_ReclaimCompositorResources_Params& params);
void OnForwardInputEvent(const blink::WebInputEvent* event);
void OnFrameRectChanged(const gfx::Rect& frame_rect);
void OnVisibilityChanged(bool visible);
@@ -124,10 +129,7 @@ class CONTENT_EXPORT CrossProcessFrameConnector {
const cc::SurfaceSequence& sequence);
void SetDeviceScaleFactor(float scale_factor);
- void SetSize(gfx::Rect frame_rect);
-
- // Retrieve the view for the top-level frame under the same WebContents.
- RenderWidgetHostViewBase* GetRootRenderWidgetHostView();
+ void SetRect(const gfx::Rect& frame_rect);
// The RenderFrameProxyHost that routes messages to the parent frame's
// renderer process.
diff --git a/chromium/content/browser/frame_host/debug_urls.cc b/chromium/content/browser/frame_host/debug_urls.cc
index f3190a74acb..833b0063ab4 100644
--- a/chromium/content/browser/frame_host/debug_urls.cc
+++ b/chromium/content/browser/frame_host/debug_urls.cc
@@ -31,6 +31,11 @@
namespace content {
+class ScopedAllowWaitForDebugURL {
+ private:
+ base::ThreadRestrictions::ScopedAllowWait wait;
+};
+
namespace {
// Define the Asan debug URLs.
@@ -164,14 +169,13 @@ bool HandleAsanDebugURL(const GURL& url) {
return true;
}
+void HangCurrentThread() {
+ ScopedAllowWaitForDebugURL allow_wait;
+ base::WaitableEvent(false, false).Wait();
+}
} // namespace
-class ScopedAllowWaitForDebugURL {
- private:
- base::ThreadRestrictions::ScopedAllowWait wait;
-};
-
bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
// Ensure that the user explicitly navigated to this URL, unless
// kEnableGpuBenchmarking is enabled by Telemetry.
@@ -199,8 +203,16 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
}
if (url == GURL(kChromeUIBrowserUIHang)) {
- ScopedAllowWaitForDebugURL allow_wait;
- base::WaitableEvent(false, false).Wait();
+ HangCurrentThread();
+ return true;
+ }
+
+ if (url == GURL(kChromeUIDelayedBrowserUIHang)) {
+ // Webdriver-safe url to hang the ui thread. Webdriver waits for the onload
+ // event in javascript which needs a little more time to fire.
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&HangCurrentThread),
+ base::TimeDelta::FromSeconds(2));
return true;
}
diff --git a/chromium/content/browser/frame_host/frame_mojo_shell.cc b/chromium/content/browser/frame_host/frame_mojo_shell.cc
index ece035648f4..556bfc9152f 100644
--- a/chromium/content/browser/frame_host/frame_mojo_shell.cc
+++ b/chromium/content/browser/frame_host/frame_mojo_shell.cc
@@ -9,12 +9,15 @@
#include "build/build_config.h"
#include "content/browser/mojo/mojo_shell_context.h"
#include "content/common/mojo/service_registry_impl.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/common/content_client.h"
+#include "mojo/common/url_type_converters.h"
-#if defined(OS_ANDROID) && defined(ENABLE_MOJO_MEDIA)
+#if defined(OS_ANDROID) && defined(ENABLE_MOJO_CDM)
#include "content/browser/media/android/provision_fetcher_impl.h"
#endif
@@ -24,7 +27,7 @@ namespace {
void RegisterFrameMojoShellServices(ServiceRegistry* registry,
RenderFrameHost* render_frame_host) {
-#if defined(OS_ANDROID) && defined(ENABLE_MOJO_MEDIA)
+#if defined(OS_ANDROID) && defined(ENABLE_MOJO_CDM)
registry->AddService(
base::Bind(&ProvisionFetcherImpl::Create, render_frame_host));
#endif
@@ -39,35 +42,32 @@ FrameMojoShell::FrameMojoShell(RenderFrameHost* frame_host)
FrameMojoShell::~FrameMojoShell() {
}
-void FrameMojoShell::BindRequest(
- mojo::InterfaceRequest<mojo::Shell> shell_request) {
- bindings_.AddBinding(this, std::move(shell_request));
+void FrameMojoShell::BindRequest(mojo::shell::mojom::ConnectorRequest request) {
+ connectors_.AddBinding(this, std::move(request));
}
// TODO(xhwang): Currently no callers are exposing |exposed_services|. So we
// drop it and replace it with services we provide in the browser. In the
// future we may need to support both.
-void FrameMojoShell::ConnectToApplication(
- mojo::URLRequestPtr application_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr /* exposed_services */,
- mojo::CapabilityFilterPtr filter,
- const ConnectToApplicationCallback& callback) {
- mojo::ServiceProviderPtr frame_services;
+void FrameMojoShell::Connect(
+ mojo::shell::mojom::IdentityPtr target,
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr /* exposed_services */,
+ mojo::shell::mojom::ClientProcessConnectionPtr client_process_connection,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback) {
+ mojo::shell::mojom::InterfaceProviderPtr frame_services;
service_provider_bindings_.AddBinding(GetServiceRegistry(),
GetProxy(&frame_services));
-
- mojo::shell::CapabilityFilter capability_filter =
- mojo::shell::GetPermissiveCapabilityFilter();
- if (!filter.is_null())
- capability_filter = filter->filter.To<mojo::shell::CapabilityFilter>();
+ std::string mojo_user_id = BrowserContext::GetMojoUserIdFor(
+ frame_host_->GetProcess()->GetBrowserContext());
MojoShellContext::ConnectToApplication(
- GURL(application_url->url), frame_host_->GetSiteInstance()->GetSiteURL(),
- std::move(services), std::move(frame_services), capability_filter,
- callback);
+ mojo_user_id, target->name,
+ frame_host_->GetSiteInstance()->GetSiteURL().spec(), std::move(services),
+ std::move(frame_services), callback);
}
-void FrameMojoShell::QuitApplication() {
+void FrameMojoShell::Clone(mojo::shell::mojom::ConnectorRequest request) {
+ connectors_.AddBinding(this, std::move(request));
}
ServiceRegistryImpl* FrameMojoShell::GetServiceRegistry() {
diff --git a/chromium/content/browser/frame_host/frame_mojo_shell.h b/chromium/content/browser/frame_host/frame_mojo_shell.h
index 08a60e9b831..893ade427f4 100644
--- a/chromium/content/browser/frame_host/frame_mojo_shell.h
+++ b/chromium/content/browser/frame_host/frame_mojo_shell.h
@@ -7,42 +7,44 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "mojo/common/weak_binding_set.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/shell/public/interfaces/shell.mojom.h"
+#include "mojo/shell/public/interfaces/connector.mojom.h"
namespace content {
class RenderFrameHost;
class ServiceRegistryImpl;
-// This provides the |mojo::Shell| service interface to each frame's
-// ServiceRegistry, giving frames the ability to connect to Mojo applications.
-class FrameMojoShell : public mojo::Shell {
+// This provides the |mojo::shell::mojom::Shell| service interface to each
+// frame's ServiceRegistry, giving frames the ability to connect to Mojo
+// applications.
+class FrameMojoShell : public mojo::shell::mojom::Connector {
public:
explicit FrameMojoShell(RenderFrameHost* frame_host);
~FrameMojoShell() override;
- void BindRequest(mojo::InterfaceRequest<mojo::Shell> shell_request);
+ void BindRequest(mojo::shell::mojom::ConnectorRequest request);
private:
- // mojo::Shell:
- void ConnectToApplication(
- mojo::URLRequestPtr application_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr exposed_services,
- mojo::CapabilityFilterPtr filter,
- const ConnectToApplicationCallback& callback) override;
- void QuitApplication() override;
+ // mojo::Connector:
+ void Connect(
+ mojo::shell::mojom::IdentityPtr target,
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ mojo::shell::mojom::ClientProcessConnectionPtr client_process_connection,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback) override;
+ void Clone(mojo::shell::mojom::ConnectorRequest request) override;
ServiceRegistryImpl* GetServiceRegistry();
RenderFrameHost* frame_host_;
- mojo::WeakBindingSet<mojo::Shell> bindings_;
+ mojo::BindingSet<mojo::shell::mojom::Connector> connectors_;
// ServiceRegistry providing browser services to connected applications.
scoped_ptr<ServiceRegistryImpl> service_registry_;
- mojo::WeakBindingSet<mojo::ServiceProvider> service_provider_bindings_;
+ mojo::BindingSet<mojo::shell::mojom::InterfaceProvider>
+ service_provider_bindings_;
DISALLOW_COPY_AND_ASSIGN(FrameMojoShell);
};
diff --git a/chromium/content/browser/frame_host/frame_navigation_entry.cc b/chromium/content/browser/frame_host/frame_navigation_entry.cc
index a7a414e85a3..fe8809c8fc6 100644
--- a/chromium/content/browser/frame_host/frame_navigation_entry.cc
+++ b/chromium/content/browser/frame_host/frame_navigation_entry.cc
@@ -4,6 +4,8 @@
#include "content/browser/frame_host/frame_navigation_entry.h"
+#include <utility>
+
namespace content {
FrameNavigationEntry::FrameNavigationEntry(int frame_tree_node_id)
@@ -12,18 +14,19 @@ FrameNavigationEntry::FrameNavigationEntry(int frame_tree_node_id)
document_sequence_number_(-1) {
}
-FrameNavigationEntry::FrameNavigationEntry(int frame_tree_node_id,
- const std::string& frame_unique_name,
- int64_t item_sequence_number,
- int64_t document_sequence_number,
- SiteInstanceImpl* site_instance,
- const GURL& url,
- const Referrer& referrer)
+FrameNavigationEntry::FrameNavigationEntry(
+ int frame_tree_node_id,
+ const std::string& frame_unique_name,
+ int64_t item_sequence_number,
+ int64_t document_sequence_number,
+ scoped_refptr<SiteInstanceImpl> site_instance,
+ const GURL& url,
+ const Referrer& referrer)
: frame_tree_node_id_(frame_tree_node_id),
frame_unique_name_(frame_unique_name),
item_sequence_number_(item_sequence_number),
document_sequence_number_(document_sequence_number),
- site_instance_(site_instance),
+ site_instance_(std::move(site_instance)),
url_(url),
referrer_(referrer) {}
diff --git a/chromium/content/browser/frame_host/frame_navigation_entry.h b/chromium/content/browser/frame_host/frame_navigation_entry.h
index 67a27063700..8527c4aed41 100644
--- a/chromium/content/browser/frame_host/frame_navigation_entry.h
+++ b/chromium/content/browser/frame_host/frame_navigation_entry.h
@@ -33,7 +33,7 @@ class CONTENT_EXPORT FrameNavigationEntry
const std::string& frame_unique_name,
int64_t item_sequence_number,
int64_t document_sequence_number,
- SiteInstanceImpl* site_instance,
+ scoped_refptr<SiteInstanceImpl> site_instance,
const GURL& url,
const Referrer& referrer);
@@ -88,8 +88,8 @@ class CONTENT_EXPORT FrameNavigationEntry
// a SiteInstance must live in the same process. This is a refcounted pointer
// that keeps the SiteInstance (not necessarily the process) alive as long as
// this object remains in the session history.
- void set_site_instance(SiteInstanceImpl* site_instance) {
- site_instance_ = site_instance;
+ void set_site_instance(scoped_refptr<SiteInstanceImpl> site_instance) {
+ site_instance_ = std::move(site_instance);
}
SiteInstanceImpl* site_instance() const { return site_instance_.get(); }
diff --git a/chromium/content/browser/frame_host/frame_tree.cc b/chromium/content/browser/frame_host/frame_tree.cc
index e92d28f80be..388c878ba3b 100644
--- a/chromium/content/browser/frame_host/frame_tree.cc
+++ b/chromium/content/browser/frame_host/frame_tree.cc
@@ -28,84 +28,60 @@ namespace content {
namespace {
-// Used with FrameTree::ForEach() to search for the FrameTreeNode
-// corresponding to |frame_tree_node_id| within a specific FrameTree.
-bool FrameTreeNodeForId(int frame_tree_node_id,
- FrameTreeNode** out_node,
- FrameTreeNode* node) {
- if (node->frame_tree_node_id() == frame_tree_node_id) {
- *out_node = node;
- // Terminate iteration once the node has been found.
- return false;
- }
- return true;
+// Helper function to collect SiteInstances involved in rendering a single
+// FrameTree (which is a subset of SiteInstances in main frame's proxy_hosts_
+// because of openers).
+std::set<SiteInstance*> CollectSiteInstances(FrameTree* tree) {
+ std::set<SiteInstance*> instances;
+ for (FrameTreeNode* node : tree->Nodes())
+ instances.insert(node->current_frame_host()->GetSiteInstance());
+ return instances;
}
-// Used with FrameTree::ForEach() to search for the FrameTreeNode with the given
-// |name| within a specific FrameTree.
-bool FrameTreeNodeForName(const std::string& name,
- FrameTreeNode** out_node,
- FrameTreeNode* node) {
- if (node->frame_name() == name) {
- *out_node = node;
- // Terminate iteration once the node has been found.
- return false;
+} // namespace
+
+FrameTree::NodeIterator::NodeIterator(const NodeIterator& other) = default;
+
+FrameTree::NodeIterator::~NodeIterator() {}
+
+FrameTree::NodeIterator& FrameTree::NodeIterator::operator++() {
+ for (size_t i = 0; i < current_node_->child_count(); ++i) {
+ FrameTreeNode* child = current_node_->child_at(i);
+ if (child == node_to_skip_)
+ continue;
+ queue_.push(child);
}
- return true;
-}
-bool CreateProxyForSiteInstance(const scoped_refptr<SiteInstance>& instance,
- FrameTreeNode* node) {
- // If a new frame is created in the current SiteInstance, other frames in
- // that SiteInstance don't need a proxy for the new frame.
- SiteInstance* current_instance =
- node->render_manager()->current_frame_host()->GetSiteInstance();
- if (current_instance != instance.get())
- node->render_manager()->CreateRenderFrameProxy(instance.get());
- return true;
-}
+ if (!queue_.empty()) {
+ current_node_ = queue_.front();
+ queue_.pop();
+ } else {
+ current_node_ = nullptr;
+ }
-// Helper function used with FrameTree::ForEach() for retrieving the total
-// loading progress and number of frames in a frame tree.
-bool CollectLoadProgress(double* progress,
- int* frame_count,
- FrameTreeNode* node) {
- // Ignore the current frame if it has not started loading.
- if (!node->has_started_loading())
- return true;
-
- // Collect progress.
- *progress += node->loading_progress();
- (*frame_count)++;
- return true;
+ return *this;
}
-// Helper function used with FrameTree::ForEach() to reset the load progress.
-bool ResetNodeLoadProgress(FrameTreeNode* node) {
- node->reset_loading_progress();
- return true;
+bool FrameTree::NodeIterator::operator==(const NodeIterator& rhs) const {
+ return current_node_ == rhs.current_node_;
}
-// Helper function used with FrameTree::ForEach() to check if at least one of
-// the nodes is loading.
-bool IsNodeLoading(bool* is_loading, FrameTreeNode* node) {
- if (node->IsLoading()) {
- // There is at least one node loading, so abort traversal.
- *is_loading = true;
- return false;
- }
- return true;
+FrameTree::NodeIterator::NodeIterator(FrameTreeNode* starting_node,
+ FrameTreeNode* node_to_skip)
+ : current_node_(starting_node != node_to_skip ? starting_node : nullptr),
+ node_to_skip_(node_to_skip) {}
+
+FrameTree::NodeIterator FrameTree::NodeRange::begin() {
+ return NodeIterator(root_, node_to_skip_);
}
-// Helper function used with FrameTree::ForEach to collect SiteInstances
-// involved in rendering a single FrameTree (which is a subset of SiteInstances
-// in main frame's proxy_hosts_ because of openers).
-bool CollectSiteInstances(std::set<SiteInstance*>* set, FrameTreeNode* node) {
- set->insert(node->current_frame_host()->GetSiteInstance());
- return true;
+FrameTree::NodeIterator FrameTree::NodeRange::end() {
+ return NodeIterator(nullptr, nullptr);
}
-} // namespace
+FrameTree::NodeRange::NodeRange(FrameTreeNode* root,
+ FrameTreeNode* node_to_skip)
+ : root_(root), node_to_skip_(node_to_skip) {}
FrameTree::FrameTree(Navigator* navigator,
RenderFrameHostDelegate* render_frame_delegate,
@@ -126,7 +102,7 @@ FrameTree::FrameTree(Navigator* navigator,
// document scope.
blink::WebTreeScopeType::Document,
std::string(),
- blink::WebSandboxFlags::None,
+ std::string(),
blink::WebFrameOwnerProperties())),
focused_frame_tree_node_id_(-1),
load_progress_(0.0) {}
@@ -137,9 +113,11 @@ FrameTree::~FrameTree() {
}
FrameTreeNode* FrameTree::FindByID(int frame_tree_node_id) {
- FrameTreeNode* node = nullptr;
- ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
- return node;
+ for (FrameTreeNode* node : Nodes()) {
+ if (node->frame_tree_node_id() == frame_tree_node_id)
+ return node;
+ }
+ return nullptr;
}
FrameTreeNode* FrameTree::FindByRoutingID(int process_id, int routing_id) {
@@ -166,34 +144,24 @@ FrameTreeNode* FrameTree::FindByName(const std::string& name) {
if (name.empty())
return root_;
- FrameTreeNode* node = nullptr;
- ForEach(base::Bind(&FrameTreeNodeForName, name, &node));
- return node;
-}
+ for (FrameTreeNode* node : Nodes()) {
+ if (node->frame_name() == name)
+ return node;
+ }
-void FrameTree::ForEach(
- const base::Callback<bool(FrameTreeNode*)>& on_node) const {
- ForEach(on_node, nullptr);
+ return nullptr;
}
-void FrameTree::ForEach(
- const base::Callback<bool(FrameTreeNode*)>& on_node,
- FrameTreeNode* skip_this_subtree) const {
- std::queue<FrameTreeNode*> queue;
- queue.push(root_);
-
- while (!queue.empty()) {
- FrameTreeNode* node = queue.front();
- queue.pop();
- if (skip_this_subtree == node)
- continue;
+FrameTree::NodeRange FrameTree::Nodes() {
+ return NodesExcept(nullptr);
+}
- if (!on_node.Run(node))
- break;
+FrameTree::NodeRange FrameTree::SubtreeNodes(FrameTreeNode* subtree_root) {
+ return NodeRange(subtree_root, nullptr);
+}
- for (size_t i = 0; i < node->child_count(); ++i)
- queue.push(node->child_at(i));
- }
+FrameTree::NodeRange FrameTree::NodesExcept(FrameTreeNode* node_to_skip) {
+ return NodeRange(root_, node_to_skip);
}
bool FrameTree::AddFrame(
@@ -202,6 +170,7 @@ bool FrameTree::AddFrame(
int new_routing_id,
blink::WebTreeScopeType scope,
const std::string& frame_name,
+ const std::string& frame_unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) {
CHECK_NE(new_routing_id, MSG_ROUTING_NONE);
@@ -218,9 +187,14 @@ bool FrameTree::AddFrame(
make_scoped_ptr(new FrameTreeNode(
this, parent->navigator(), render_frame_delegate_,
render_view_delegate_, render_widget_delegate_, manager_delegate_,
- scope, frame_name, sandbox_flags, frame_owner_properties)),
+ scope, frame_name, frame_unique_name, frame_owner_properties)),
process_id, new_routing_id);
+ // Set sandbox flags and make them effective immediately, since initial
+ // sandbox flags should apply to the initial empty document in the frame.
+ added_node->SetPendingSandboxFlags(sandbox_flags);
+ added_node->CommitPendingSandboxFlags();
+
// Now that the new node is part of the FrameTree and has a RenderFrameHost,
// we can announce the creation of the initial RenderFrame which already
// exists in the renderer process.
@@ -241,30 +215,28 @@ void FrameTree::RemoveFrame(FrameTreeNode* child) {
void FrameTree::CreateProxiesForSiteInstance(
FrameTreeNode* source,
SiteInstance* site_instance) {
- // Create the swapped out RVH for the new SiteInstance. This will create
- // a top-level swapped out RFH as well, which will then be wrapped by a
- // RenderFrameProxyHost.
+ // Create the RenderFrameProxyHost for the new SiteInstance.
if (!source || !source->IsMainFrame()) {
RenderViewHostImpl* render_view_host = GetRenderViewHost(site_instance);
if (!render_view_host) {
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- root()->render_manager()->CreateRenderFrameProxy(site_instance);
- } else {
- root()->render_manager()->CreateRenderFrame(
- site_instance, CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
- }
+ root()->render_manager()->CreateRenderFrameProxy(site_instance);
} else {
root()->render_manager()->EnsureRenderViewInitialized(render_view_host,
site_instance);
}
}
- scoped_refptr<SiteInstance> instance(site_instance);
-
// Proxies are created in the FrameTree in response to a node navigating to a
// new SiteInstance. Since |source|'s navigation will replace the currently
// loaded document, the entire subtree under |source| will be removed.
- ForEach(base::Bind(&CreateProxyForSiteInstance, instance), source);
+ for (FrameTreeNode* node : NodesExcept(source)) {
+ // If a new frame is created in the current SiteInstance, other frames in
+ // that SiteInstance don't need a proxy for the new frame.
+ SiteInstance* current_instance =
+ node->render_manager()->current_frame_host()->GetSiteInstance();
+ if (current_instance != site_instance)
+ node->render_manager()->CreateRenderFrameProxy(site_instance);
+ }
}
RenderFrameHostImpl* FrameTree::GetMainFrame() const {
@@ -279,8 +251,8 @@ void FrameTree::SetFocusedFrame(FrameTreeNode* node, SiteInstance* source) {
if (node == GetFocusedFrame())
return;
- std::set<SiteInstance*> frame_tree_site_instances;
- ForEach(base::Bind(&CollectSiteInstances, &frame_tree_site_instances));
+ std::set<SiteInstance*> frame_tree_site_instances =
+ CollectSiteInstances(this);
SiteInstance* current_instance =
node->current_frame_host()->GetSiteInstance();
@@ -311,6 +283,11 @@ void FrameTree::SetFocusedFrame(FrameTreeNode* node, SiteInstance* source) {
focused_frame_tree_node_id_ = node->frame_tree_node_id();
node->DidFocus();
+
+ // The accessibility tree data for the root of the frame tree keeps
+ // track of the focused frame too, so update that every time the
+ // focused frame changes.
+ root()->current_frame_host()->UpdateAXTreeData();
}
void FrameTree::SetFrameRemoveListener(
@@ -333,7 +310,7 @@ RenderViewHostImpl* FrameTree::CreateRenderViewHost(
// SiteInstance. Note that if swapped-out is forbidden, the
// RenderViewHost's main frame has already been cleared, so we cannot rely
// on checking whether the main frame is pending deletion.
- if (iter->second->is_pending_deletion()) {
+ if (root_->render_manager()->IsViewPendingDeletion(iter->second)) {
render_view_host_pending_shutdown_map_.insert(
std::make_pair(site_instance->GetId(), iter->second));
render_view_host_map_.erase(iter);
@@ -353,9 +330,12 @@ RenderViewHostImpl* FrameTree::CreateRenderViewHost(
RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
RenderViewHostMap::iterator iter =
render_view_host_map_.find(site_instance->GetId());
- if (iter == render_view_host_map_.end())
- return nullptr;
- return iter->second;
+ // Don't return the RVH if it is pending deletion.
+ if (iter != render_view_host_map_.end() &&
+ !root_->render_manager()->IsViewPendingDeletion(iter->second)) {
+ return iter->second;
+ }
+ return nullptr;
}
void FrameTree::AddRenderViewHostRef(RenderViewHostImpl* render_view_host) {
@@ -428,7 +408,16 @@ void FrameTree::UpdateLoadProgress() {
double progress = 0.0;
int frame_count = 0;
- ForEach(base::Bind(&CollectLoadProgress, &progress, &frame_count));
+ for (FrameTreeNode* node : Nodes()) {
+ // Ignore the current frame if it has not started loading.
+ if (!node->has_started_loading())
+ continue;
+
+ // Collect progress.
+ progress += node->loading_progress();
+ frame_count++;
+ }
+
if (frame_count != 0)
progress /= frame_count;
@@ -441,19 +430,22 @@ void FrameTree::UpdateLoadProgress() {
}
void FrameTree::ResetLoadProgress() {
- ForEach(base::Bind(&ResetNodeLoadProgress));
+ for (FrameTreeNode* node : Nodes())
+ node->reset_loading_progress();
load_progress_ = 0.0;
}
-bool FrameTree::IsLoading() {
- bool is_loading = false;
- ForEach(base::Bind(&IsNodeLoading, &is_loading));
- return is_loading;
+bool FrameTree::IsLoading() const {
+ for (const FrameTreeNode* node : const_cast<FrameTree*>(this)->Nodes()) {
+ if (node->IsLoading())
+ return true;
+ }
+ return false;
}
void FrameTree::ReplicatePageFocus(bool is_focused) {
- std::set<SiteInstance*> frame_tree_site_instances;
- ForEach(base::Bind(&CollectSiteInstances, &frame_tree_site_instances));
+ std::set<SiteInstance*> frame_tree_site_instances =
+ CollectSiteInstances(this);
// Send the focus update to main frame's proxies in all SiteInstances of
// other frames in this FrameTree. Note that the main frame might also know
diff --git a/chromium/content/browser/frame_host/frame_tree.h b/chromium/content/browser/frame_host/frame_tree.h
index 6fc21f61cb0..840228d412d 100644
--- a/chromium/content/browser/frame_host/frame_tree.h
+++ b/chromium/content/browser/frame_host/frame_tree.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <iterator>
#include <string>
#include "base/callback.h"
@@ -18,7 +19,6 @@
namespace content {
-class FrameTreeNode;
class Navigator;
class RenderFrameHostDelegate;
class RenderProcessHost;
@@ -41,6 +41,45 @@ class RenderWidgetHostDelegate;
// This object is only used on the UI thread.
class CONTENT_EXPORT FrameTree {
public:
+ class NodeRange;
+
+ class CONTENT_EXPORT NodeIterator
+ : public std::iterator<std::forward_iterator_tag, FrameTreeNode> {
+ public:
+ NodeIterator(const NodeIterator& other);
+ ~NodeIterator();
+
+ NodeIterator& operator++();
+
+ bool operator==(const NodeIterator& rhs) const;
+ bool operator!=(const NodeIterator& rhs) const { return !(*this == rhs); }
+
+ FrameTreeNode* operator*() { return current_node_; }
+
+ private:
+ friend class NodeRange;
+
+ NodeIterator(FrameTreeNode* starting_node, FrameTreeNode* node_to_skip);
+
+ FrameTreeNode* current_node_;
+ FrameTreeNode* const node_to_skip_;
+ std::queue<FrameTreeNode*> queue_;
+ };
+
+ class CONTENT_EXPORT NodeRange {
+ public:
+ NodeIterator begin();
+ NodeIterator end();
+
+ private:
+ friend class FrameTree;
+
+ NodeRange(FrameTreeNode* root, FrameTreeNode* node_to_skip);
+
+ FrameTreeNode* const root_;
+ FrameTreeNode* const node_to_skip_;
+ };
+
// Each FrameTreeNode will default to using the given |navigator| for
// navigation tasks in the frame.
// A set of delegates are remembered here so that we can create
@@ -69,12 +108,13 @@ class CONTENT_EXPORT FrameTree {
// nor searching other FrameTrees (unlike blink::WebView::findFrameByName).
FrameTreeNode* FindByName(const std::string& name);
- // Executes |on_node| on each node in the frame tree. If |on_node| returns
- // false, terminates the iteration immediately. Returning false is useful
- // if |on_node| is just doing a search over the tree. The iteration proceeds
- // top-down and visits a node before adding its children to the queue, making
- // it safe to remove children during the callback.
- void ForEach(const base::Callback<bool(FrameTreeNode*)>& on_node) const;
+ // Returns a range to iterate over all FrameTreeNodes in the frame tree in
+ // breadth-first traversal order.
+ NodeRange Nodes();
+
+ // Returns a range to iterate over all FrameTreeNodes in a subtree of the
+ // frame tree, starting from |subtree_root|.
+ NodeRange SubtreeNodes(FrameTreeNode* subtree_root);
// Adds a new child frame to the frame tree. |process_id| is required to
// disambiguate |new_routing_id|, and it must match the process of the
@@ -84,6 +124,7 @@ class CONTENT_EXPORT FrameTree {
int new_routing_id,
blink::WebTreeScopeType scope,
const std::string& frame_name,
+ const std::string& frame_unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties);
@@ -154,7 +195,7 @@ class CONTENT_EXPORT FrameTree {
void ResetLoadProgress();
// Returns true if at least one of the nodes in this FrameTree is loading.
- bool IsLoading();
+ bool IsLoading() const;
// Set page-level focus in all SiteInstances involved in rendering
// this FrameTree, not including the current main frame's
@@ -167,14 +208,15 @@ class CONTENT_EXPORT FrameTree {
void SetPageFocus(SiteInstance* instance, bool is_focused);
private:
+ friend class FrameTreeTest;
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
typedef base::hash_map<int, RenderViewHostImpl*> RenderViewHostMap;
typedef std::multimap<int, RenderViewHostImpl*> RenderViewHostMultiMap;
- // A variation to the public ForEach method with a difference that the subtree
- // starting at |skip_this_subtree| will not be recursed into.
- void ForEach(const base::Callback<bool(FrameTreeNode*)>& on_node,
- FrameTreeNode* skip_this_subtree) const;
+ // Returns a range to iterate over all FrameTreeNodes in the frame tree in
+ // breadth-first traversal order, skipping the subtree rooted at
+ // |node_to_skip|.
+ NodeRange NodesExcept(FrameTreeNode* node_to_skip);
// These delegates are installed into all the RenderViewHosts and
// RenderFrameHosts that we create.
diff --git a/chromium/content/browser/frame_host/frame_tree_browsertest.cc b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
index 1ffdd0a21d2..782234f5a02 100644
--- a/chromium/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
@@ -464,30 +464,29 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
// which resets both SandboxFlags::Scripts and
// SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
// third frame has "allow-scripts allow-same-origin".
- EXPECT_EQ(root->current_replication_state().sandbox_flags,
- blink::WebSandboxFlags::None);
- EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
- blink::WebSandboxFlags::All);
- EXPECT_EQ(root->child_at(1)->current_replication_state().sandbox_flags,
- blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
- ~blink::WebSandboxFlags::AutomaticFeatures);
- EXPECT_EQ(root->child_at(2)->current_replication_state().sandbox_flags,
- blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ EXPECT_EQ(blink::WebSandboxFlags::None, root->effective_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::All,
+ root->child_at(0)->effective_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ ~blink::WebSandboxFlags::AutomaticFeatures,
+ root->child_at(1)->effective_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
~blink::WebSandboxFlags::AutomaticFeatures &
- ~blink::WebSandboxFlags::Origin);
+ ~blink::WebSandboxFlags::Origin,
+ root->child_at(2)->effective_sandbox_flags());
// Sandboxed frames should set a unique origin unless they have the
// "allow-same-origin" directive.
- EXPECT_EQ(root->child_at(0)->current_origin().Serialize(), "null");
- EXPECT_EQ(root->child_at(1)->current_origin().Serialize(), "null");
- EXPECT_EQ(root->child_at(2)->current_origin().Serialize() + "/",
- main_url.GetOrigin().spec());
+ EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
+ EXPECT_EQ("null", root->child_at(1)->current_origin().Serialize());
+ EXPECT_EQ(main_url.GetOrigin().spec(),
+ root->child_at(2)->current_origin().Serialize() + "/");
// Navigating to a different URL should not clear sandbox flags.
GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
NavigateFrameToURL(root->child_at(0), frame_url);
- EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
- blink::WebSandboxFlags::All);
+ EXPECT_EQ(blink::WebSandboxFlags::All,
+ root->child_at(0)->effective_sandbox_flags());
}
// Ensure that a popup opened from a subframe sets its opener to the subframe's
diff --git a/chromium/content/browser/frame_host/frame_tree_node.cc b/chromium/content/browser/frame_host/frame_tree_node.cc
index b975a051106..7f1d2f57ad9 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.cc
+++ b/chromium/content/browser/frame_host/frame_tree_node.cc
@@ -14,11 +14,13 @@
#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/traced_frame_tree_node.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/common/frame_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/browser_side_navigation_policy.h"
+#include "third_party/WebKit/public/web/WebSandboxFlags.h"
namespace content {
@@ -77,7 +79,7 @@ FrameTreeNode::FrameTreeNode(
RenderFrameHostManager::Delegate* manager_delegate,
blink::WebTreeScopeType scope,
const std::string& name,
- blink::WebSandboxFlags sandbox_flags,
+ const std::string& unique_name,
const blink::WebFrameOwnerProperties& frame_owner_properties)
: frame_tree_(frame_tree),
navigator_(navigator),
@@ -94,17 +96,23 @@ FrameTreeNode::FrameTreeNode(
replication_state_(
scope,
name,
- sandbox_flags,
- false /* should enforce strict mixed content checking */),
- // Effective sandbox flags also need to be set, since initial sandbox
- // flags should apply to the initial empty document in the frame.
- effective_sandbox_flags_(sandbox_flags),
+ unique_name,
+ blink::WebSandboxFlags::None,
+ false /* should enforce strict mixed content checking */,
+ false /* is a potentially trustworthy unique origin */),
+ pending_sandbox_flags_(blink::WebSandboxFlags::None),
frame_owner_properties_(frame_owner_properties),
loading_progress_(kLoadingProgressNotStarted) {
std::pair<FrameTreeNodeIdMap::iterator, bool> result =
g_frame_tree_node_id_map.Get().insert(
std::make_pair(frame_tree_node_id_, this));
CHECK(result.second);
+
+ TRACE_EVENT_OBJECT_CREATED_WITH_ID(
+ "navigation", "FrameTreeNode",
+ TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_));
+ // Don't TraceSnapshot() until the RenderFrameHostManager is initialized and
+ // calls SetCurrentURL().
}
FrameTreeNode::~FrameTreeNode() {
@@ -116,6 +124,10 @@ FrameTreeNode::~FrameTreeNode() {
opener_->RemoveObserver(opener_observer_.get());
g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
+
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ "navigation", "FrameTreeNode",
+ TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_));
}
void FrameTreeNode::AddObserver(Observer* observer) {
@@ -171,7 +183,8 @@ void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
}
void FrameTreeNode::ResetForNewProcess() {
- current_url_ = GURL();
+ current_frame_host()->set_last_committed_url(GURL());
+ TraceSnapshot();
// Remove child nodes from the tree, then delete them. This destruction
// operation will notify observers.
@@ -196,19 +209,34 @@ void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
void FrameTreeNode::SetCurrentURL(const GURL& url) {
if (!has_committed_real_load_ && url != GURL(url::kAboutBlankURL))
has_committed_real_load_ = true;
- current_url_ = url;
+ current_frame_host()->set_last_committed_url(url);
+ TraceSnapshot();
}
-void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
- if (!origin.IsSameOriginWith(replication_state_.origin))
- render_manager_.OnDidUpdateOrigin(origin);
+void FrameTreeNode::SetCurrentOrigin(
+ const url::Origin& origin,
+ bool is_potentially_trustworthy_unique_origin) {
+ if (!origin.IsSameOriginWith(replication_state_.origin) ||
+ replication_state_.has_potentially_trustworthy_unique_origin !=
+ is_potentially_trustworthy_unique_origin) {
+ render_manager_.OnDidUpdateOrigin(origin,
+ is_potentially_trustworthy_unique_origin);
+ }
replication_state_.origin = origin;
+ replication_state_.has_potentially_trustworthy_unique_origin =
+ is_potentially_trustworthy_unique_origin;
}
-void FrameTreeNode::SetFrameName(const std::string& name) {
- if (name != replication_state_.name)
- render_manager_.OnDidUpdateName(name);
+void FrameTreeNode::SetFrameName(const std::string& name,
+ const std::string& unique_name) {
+ if (name == replication_state_.name) {
+ // |unique_name| shouldn't change unless |name| changes.
+ DCHECK_EQ(unique_name, replication_state_.unique_name);
+ return;
+ }
+ render_manager_.OnDidUpdateName(name, unique_name);
replication_state_.name = name;
+ replication_state_.unique_name = unique_name;
}
void FrameTreeNode::SetEnforceStrictMixedContentChecking(bool should_enforce) {
@@ -221,6 +249,15 @@ void FrameTreeNode::SetEnforceStrictMixedContentChecking(bool should_enforce) {
should_enforce;
}
+void FrameTreeNode::SetPendingSandboxFlags(
+ blink::WebSandboxFlags sandbox_flags) {
+ pending_sandbox_flags_ = sandbox_flags;
+
+ // Subframes should always inherit their parent's sandbox flags.
+ if (parent())
+ pending_sandbox_flags_ |= parent()->effective_sandbox_flags();
+}
+
bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
if (!other || !other->child_count())
return false;
@@ -271,48 +308,68 @@ bool FrameTreeNode::IsLoading() const {
bool FrameTreeNode::CommitPendingSandboxFlags() {
bool did_change_flags =
- effective_sandbox_flags_ != replication_state_.sandbox_flags;
- effective_sandbox_flags_ = replication_state_.sandbox_flags;
+ pending_sandbox_flags_ != replication_state_.sandbox_flags;
+ replication_state_.sandbox_flags = pending_sandbox_flags_;
return did_change_flags;
}
void FrameTreeNode::CreatedNavigationRequest(
scoped_ptr<NavigationRequest> navigation_request) {
CHECK(IsBrowserSideNavigationEnabled());
- ResetNavigationRequest(false);
+
+ bool was_previously_loading = frame_tree()->IsLoading();
+
+ // There's no need to reset the state: there's still an ongoing load, and the
+ // RenderFrameHostManager will take care of updates to the speculative
+ // RenderFrameHost in DidCreateNavigationRequest below.
+ if (was_previously_loading)
+ ResetNavigationRequest(true);
+
+ navigation_request_ = std::move(navigation_request);
+ render_manager()->DidCreateNavigationRequest(navigation_request_.get());
// Force the throbber to start to keep it in sync with what is happening in
// the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
// is not done here either.
- if (!navigation_request->common_params().url.SchemeIs(
+ if (!navigation_request_->common_params().url.SchemeIs(
url::kJavaScriptScheme)) {
// TODO(fdegans): Check if this is a same-document navigation and set the
// proper argument.
- DidStartLoading(true);
+ DidStartLoading(true, was_previously_loading);
}
-
- navigation_request_ = std::move(navigation_request);
-
- render_manager()->DidCreateNavigationRequest(*navigation_request_);
}
-void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
+void FrameTreeNode::ResetNavigationRequest(bool keep_state) {
CHECK(IsBrowserSideNavigationEnabled());
if (!navigation_request_)
return;
+ bool was_renderer_initiated = !navigation_request_->browser_initiated();
+ NavigationRequest::AssociatedSiteInstanceType site_instance_type =
+ navigation_request_->associated_site_instance_type();
navigation_request_.reset();
- // During commit, the clean up of a speculative RenderFrameHost is done in
- // RenderFrameHostManager::DidNavigateFrame. The load is also still being
- // tracked.
- if (is_commit)
+ if (keep_state)
return;
- // If the reset corresponds to a cancelation, the RenderFrameHostManager
- // should clean up any speculative RenderFrameHost it created for the
- // navigation.
+ // The RenderFrameHostManager should clean up any speculative RenderFrameHost
+ // it created for the navigation. Also register that the load stopped.
DidStopLoading();
render_manager_.CleanUpNavigation();
+
+ // When reusing the same SiteInstance, a pending WebUI may have been created
+ // on behalf of the navigation in the current RenderFrameHost. Clear it.
+ if (site_instance_type ==
+ NavigationRequest::AssociatedSiteInstanceType::CURRENT) {
+ current_frame_host()->ClearPendingWebUI();
+ }
+
+ // If the navigation is renderer-initiated, the renderer should also be
+ // informed that the navigation stopped.
+ if (was_renderer_initiated) {
+ current_frame_host()->Send(
+ new FrameMsg_Stop(current_frame_host()->GetRoutingID()));
+ }
+
}
bool FrameTreeNode::has_started_loading() const {
@@ -323,7 +380,8 @@ void FrameTreeNode::reset_loading_progress() {
loading_progress_ = kLoadingProgressNotStarted;
}
-void FrameTreeNode::DidStartLoading(bool to_different_document) {
+void FrameTreeNode::DidStartLoading(bool to_different_document,
+ bool was_previously_loading) {
// Any main frame load to a new document should reset the load progress since
// it will replace the current page and any frames. The WebContents will
// be notified when DidChangeLoadProgress is called.
@@ -331,7 +389,7 @@ void FrameTreeNode::DidStartLoading(bool to_different_document) {
frame_tree_->ResetLoadProgress();
// Notify the WebContents.
- if (!frame_tree_->IsLoading())
+ if (!was_previously_loading)
navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
// Set initial load progress and update overall progress. This will notify
@@ -398,4 +456,36 @@ void FrameTreeNode::DidFocus() {
FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeFocused(this));
}
+void FrameTreeNode::BeforeUnloadCanceled() {
+ // TODO(clamy): Support BeforeUnload in subframes.
+ if (!IsMainFrame())
+ return;
+
+ RenderFrameHostImpl* current_frame_host =
+ render_manager_.current_frame_host();
+ DCHECK(current_frame_host);
+ current_frame_host->ResetLoadingState();
+
+ if (IsBrowserSideNavigationEnabled()) {
+ RenderFrameHostImpl* speculative_frame_host =
+ render_manager_.speculative_frame_host();
+ if (speculative_frame_host)
+ speculative_frame_host->ResetLoadingState();
+ } else {
+ RenderFrameHostImpl* pending_frame_host =
+ render_manager_.pending_frame_host();
+ if (pending_frame_host)
+ pending_frame_host->ResetLoadingState();
+ }
+}
+
+void FrameTreeNode::TraceSnapshot() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ "navigation", "FrameTreeNode",
+ TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_),
+ scoped_ptr<base::trace_event::ConvertableToTraceFormat>(
+ new TracedFrameTreeNode(*this)));
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_tree_node.h b/chromium/content/browser/frame_host/frame_tree_node.h
index 9103b63aa70..044764b9144 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.h
+++ b/chromium/content/browser/frame_host/frame_tree_node.h
@@ -51,6 +51,8 @@ class CONTENT_EXPORT FrameTreeNode {
// regardless of which FrameTree it is in.
static FrameTreeNode* GloballyFindByID(int frame_tree_node_id);
+ // Callers are are expected to initialize sandbox flags separately after
+ // calling the constructor.
FrameTreeNode(FrameTree* frame_tree,
Navigator* navigator,
RenderFrameHostDelegate* render_frame_delegate,
@@ -59,7 +61,7 @@ class CONTENT_EXPORT FrameTreeNode {
RenderFrameHostManager::Delegate* manager_delegate,
blink::WebTreeScopeType scope,
const std::string& name,
- blink::WebSandboxFlags sandbox_flags,
+ const std::string& unique_name,
const blink::WebFrameOwnerProperties& frame_owner_properties);
~FrameTreeNode();
@@ -97,8 +99,6 @@ class CONTENT_EXPORT FrameTreeNode {
return replication_state_.name;
}
- const url::Origin& frame_origin() const { return replication_state_.origin; }
-
size_t child_count() const {
return children_.size();
}
@@ -116,9 +116,9 @@ class CONTENT_EXPORT FrameTreeNode {
return children_[index].get();
}
- // Returns the URL of the last committed page in this frame.
+ // Returns the URL of the last committed page in the current frame.
const GURL& current_url() const {
- return current_url_;
+ return current_frame_host()->last_committed_url();
}
// Sets the last committed URL for this frame and updates
@@ -136,25 +136,43 @@ class CONTENT_EXPORT FrameTreeNode {
}
// Set the current origin and notify proxies about the update.
- void SetCurrentOrigin(const url::Origin& origin);
+ void SetCurrentOrigin(const url::Origin& origin,
+ bool is_potentially_trustworthy_unique_origin);
// Set the current name and notify proxies about the update.
- void SetFrameName(const std::string& name);
+ void SetFrameName(const std::string& name, const std::string& unique_name);
// Sets the current enforcement of strict mixed content checking and
// notifies proxies about the update.
void SetEnforceStrictMixedContentChecking(bool should_enforce);
- blink::WebSandboxFlags effective_sandbox_flags() {
- return effective_sandbox_flags_;
+ // Returns the currently active sandbox flags for this frame. This includes
+ // flags inherited from parent frames and the currently active flags from the
+ // <iframe> element hosting this frame. This does not include flags that
+ // have been updated in an <iframe> element but have not taken effect yet;
+ // use pending_sandbox_flags() for those.
+ blink::WebSandboxFlags effective_sandbox_flags() const {
+ return replication_state_.sandbox_flags;
}
- void set_sandbox_flags(blink::WebSandboxFlags sandbox_flags) {
- replication_state_.sandbox_flags = sandbox_flags;
+ // Returns the latest sandbox flags for this frame. This includes flags
+ // inherited from parent frames and the latest flags from the <iframe>
+ // element hosting this frame. The returned flags may not yet have taken
+ // effect, since sandbox flag updates in an <iframe> element take effect on
+ // next navigation. To retrieve the currently active sandbox flags for this
+ // frame, use effective_sandbox_flags().
+ blink::WebSandboxFlags pending_sandbox_flags() const {
+ return pending_sandbox_flags_;
}
- // Transfer any pending sandbox flags into |effective_sandbox_flags_|, and
- // return true if the sandbox flags were changed.
+ // Update this frame's sandbox flags. This is used when a parent frame
+ // updates sandbox flags in the <iframe> element for this frame. These flags
+ // won't take effect until next navigation. If this frame's parent is itself
+ // sandboxed, the parent's sandbox flags are combined with |sandbox_flags|.
+ void SetPendingSandboxFlags(blink::WebSandboxFlags sandbox_flags);
+
+ // Set any pending sandbox flags as active, and return true if the sandbox
+ // flags were changed.
bool CommitPendingSandboxFlags();
const blink::WebFrameOwnerProperties& frame_owner_properties() {
@@ -202,9 +220,10 @@ class CONTENT_EXPORT FrameTreeNode {
scoped_ptr<NavigationRequest> navigation_request);
// PlzNavigate
- // Resets the current navigation request. |is_commit| is true if the reset is
- // due to the commit of the navigation.
- void ResetNavigationRequest(bool is_commit);
+ // Resets the current navigation request. If |keep_state| is true, any state
+ // created by the NavigationRequest (e.g. speculative RenderFrameHost,
+ // loading state) will not be reset by the function.
+ void ResetNavigationRequest(bool keep_state);
// Returns true if this node is in a state where the loading progress is being
// tracked.
@@ -216,7 +235,11 @@ class CONTENT_EXPORT FrameTreeNode {
// A RenderFrameHost in this node started loading.
// |to_different_document| will be true unless the load is a fragment
// navigation, or triggered by history.pushState/replaceState.
- void DidStartLoading(bool to_different_document);
+ // |was_previously_loading| is false if the FrameTree was not loading before.
+ // The caller is required to provide this boolean as the delegate should only
+ // be notified if the FrameTree went from non-loading to loading state.
+ // However, when it is called, the FrameTree should be in a loading state.
+ void DidStartLoading(bool to_different_document, bool was_previously_loading);
// A RenderFrameHost in this node stopped loading.
void DidStopLoading();
@@ -238,11 +261,18 @@ class CONTENT_EXPORT FrameTreeNode {
// time and notifies observers.
void DidFocus();
+ // Called when the user closed the modal dialogue for BeforeUnload and
+ // cancelled the navigation. This should stop any load happening in the
+ // FrameTreeNode.
+ void BeforeUnloadCanceled();
+
private:
class OpenerDestroyedObserver;
void set_parent(FrameTreeNode* parent) { parent_ = parent; }
+ void TraceSnapshot() const;
+
// The next available browser-global FrameTreeNode ID.
static int next_frame_tree_node_id_;
@@ -282,11 +312,6 @@ class CONTENT_EXPORT FrameTreeNode {
// The immediate children of this specific frame.
std::vector<scoped_ptr<FrameTreeNode>> children_;
- // Track the current frame's last committed URL.
- // TODO(creis): Consider storing a reference to the last committed
- // FrameNavigationEntry here once those are created in all modes.
- GURL current_url_;
-
// Whether this frame has committed any real load, replacing its initial
// about:blank page.
bool has_committed_real_load_;
@@ -295,15 +320,12 @@ class CONTENT_EXPORT FrameTreeNode {
// proxies for this frame.
FrameReplicationState replication_state_;
- // Track the effective sandbox flags for this frame. When a parent frame
- // dynamically updates sandbox flags for a child frame, the child's updated
- // sandbox flags are stored in replication_state_.sandbox_flags. However, the
- // update only takes effect on the next frame navigation, so the effective
- // sandbox flags are tracked separately here. When enforcing sandbox flags
- // directives in the browser process, |effective_sandbox_flags_| should be
- // used. |effective_sandbox_flags_| is updated with any pending sandbox
- // flags when a navigation for this frame commits.
- blink::WebSandboxFlags effective_sandbox_flags_;
+ // Track the pending sandbox flags for this frame. When a parent frame
+ // dynamically updates sandbox flags in the <iframe> element for a child
+ // frame, these updated flags are stored here and are transferred into
+ // replication_state_.sandbox_flags when they take effect on the next frame
+ // navigation.
+ blink::WebSandboxFlags pending_sandbox_flags_;
// Tracks the scrolling and margin properties for this frame. These
// properties affect the child renderer but are stored on its parent's
diff --git a/chromium/content/browser/frame_host/frame_tree_unittest.cc b/chromium/content/browser/frame_host/frame_tree_unittest.cc
index 93d481684fd..73861575da4 100644
--- a/chromium/content/browser/frame_host/frame_tree_unittest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_unittest.cc
@@ -120,6 +120,17 @@ class FrameTreeTest : public RenderViewHostImplTestHarness {
AppendTreeNodeState(frame_tree->root(), &result);
return result;
}
+
+ std::string GetTraversalOrder(FrameTree* frame_tree,
+ FrameTreeNode* node_to_skip) {
+ std::string result;
+ for (FrameTreeNode* node : frame_tree->NodesExcept(node_to_skip)) {
+ if (!result.empty())
+ result += " ";
+ result += base::Int64ToString(node->current_frame_host()->GetRoutingID());
+ }
+ return result;
+ }
};
// Exercise tree manipulation routines.
@@ -145,26 +156,29 @@ TEST_F(FrameTreeTest, Shape) {
// Simulate attaching a series of frames to build the frame tree.
frame_tree->AddFrame(root, process_id, 14, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0",
+ blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(root, process_id, 15, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName1",
+ blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(root, process_id, 16, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName2",
+ blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(root->child_at(0), process_id, 244,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName3", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(root->child_at(1), process_id, 255,
blink::WebTreeScopeType::Document, no_children_node,
- blink::WebSandboxFlags::None,
+ "uniqueName4", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(root->child_at(0), process_id, 245,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName5", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
EXPECT_EQ(
@@ -176,42 +190,42 @@ TEST_F(FrameTreeTest, Shape) {
FrameTreeNode* child_16 = root->child_at(2);
frame_tree->AddFrame(child_16, process_id, 264,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName6", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_16, process_id, 265,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName7", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_16, process_id, 266,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName8", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_16, process_id, 267,
blink::WebTreeScopeType::Document, deep_subtree,
- blink::WebSandboxFlags::None,
+ "uniqueName9", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_16, process_id, 268,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName10", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
FrameTreeNode* child_267 = child_16->child_at(3);
frame_tree->AddFrame(child_267, process_id, 365,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName11", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_267->child_at(0), process_id, 455,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName12", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0),
- process_id, 655, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ "uniqueName13", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
+ frame_tree->AddFrame(
+ child_267->child_at(0)->child_at(0)->child_at(0), process_id, 655,
+ blink::WebTreeScopeType::Document, std::string(), "uniqueName14",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
// Now that's it's fully built, verify the tree structure is as expected.
EXPECT_EQ(
@@ -222,7 +236,31 @@ TEST_F(FrameTreeTest, Shape) {
"[365: [455: [555: [655: []]]]], 268: []]]",
GetTreeState(frame_tree));
+ // Verify that traversal order is breadth first, even if we skip a subtree.
+ FrameTreeNode* child_14 = root->child_at(0);
+ FrameTreeNode* child_15 = root->child_at(1);
+ FrameTreeNode* child_244 = child_14->child_at(0);
+ FrameTreeNode* child_245 = child_14->child_at(1);
FrameTreeNode* child_555 = child_267->child_at(0)->child_at(0)->child_at(0);
+ FrameTreeNode* child_655 = child_555->child_at(0);
+ EXPECT_EQ("2 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655",
+ GetTraversalOrder(frame_tree, nullptr));
+ EXPECT_EQ("", GetTraversalOrder(frame_tree, root));
+ EXPECT_EQ("2 15 16 255 264 265 266 267 268 365 455 555 655",
+ GetTraversalOrder(frame_tree, child_14));
+ EXPECT_EQ("2 14 15 16 245 255 264 265 266 267 268 365 455 555 655",
+ GetTraversalOrder(frame_tree, child_244));
+ EXPECT_EQ("2 14 15 16 244 255 264 265 266 267 268 365 455 555 655",
+ GetTraversalOrder(frame_tree, child_245));
+ EXPECT_EQ("2 14 16 244 245 264 265 266 267 268 365 455 555 655",
+ GetTraversalOrder(frame_tree, child_15));
+ EXPECT_EQ("2 14 15 16 244 245 255 264 265 266 268",
+ GetTraversalOrder(frame_tree, child_267));
+ EXPECT_EQ("2 14 15 16 244 245 255 264 265 266 267 268 365 455",
+ GetTraversalOrder(frame_tree, child_555));
+ EXPECT_EQ("2 14 15 16 244 245 255 264 265 266 267 268 365 455 555",
+ GetTraversalOrder(frame_tree, child_655));
+
frame_tree->RemoveFrame(child_555);
EXPECT_EQ(
"2: [14: [244: [], 245: []], "
@@ -258,16 +296,15 @@ TEST_F(FrameTreeTest, FindFrames) {
FrameTree* frame_tree = contents()->GetFrameTree();
FrameTreeNode* root = frame_tree->root();
- main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
- "child0", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
- "child1", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- main_test_rfh()->OnCreateChildFrame(24, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 22, blink::WebTreeScopeType::Document, "child0", "uniqueName0",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 23, blink::WebTreeScopeType::Document, "child1", "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 24, blink::WebTreeScopeType::Document, std::string(), "uniqueName2",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* child0 = root->child_at(0);
FrameTreeNode* child1 = root->child_at(1);
@@ -275,7 +312,7 @@ TEST_F(FrameTreeTest, FindFrames) {
// Add one grandchild frame.
child1->current_frame_host()->OnCreateChildFrame(
- 33, blink::WebTreeScopeType::Document, "grandchild",
+ 33, blink::WebTreeScopeType::Document, "grandchild", "uniqueName3",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* grandchild = child1->child_at(0);
@@ -312,22 +349,22 @@ TEST_F(FrameTreeTest, PreviousSibling) {
// Add a few child frames to the main frame.
FrameTree* frame_tree = contents()->GetFrameTree();
FrameTreeNode* root = frame_tree->root();
- main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
- "child0", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
- "child1", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- main_test_rfh()->OnCreateChildFrame(24, blink::WebTreeScopeType::Document,
- "child2", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 22, blink::WebTreeScopeType::Document, "child0", "uniqueName0",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 23, blink::WebTreeScopeType::Document, "child1", "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 24, blink::WebTreeScopeType::Document, "child2", "uniqueName2",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* child0 = root->child_at(0);
FrameTreeNode* child1 = root->child_at(1);
FrameTreeNode* child2 = root->child_at(2);
// Add one grandchild frame.
child1->current_frame_host()->OnCreateChildFrame(
- 33, blink::WebTreeScopeType::Document, "grandchild",
+ 33, blink::WebTreeScopeType::Document, "grandchild", "uniqueName3",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* grandchild = child1->child_at(0);
@@ -349,18 +386,16 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
FrameTreeNode* root = frame_tree->root();
// Simulate attaching a series of frames to build the frame tree.
- main_test_rfh()->OnCreateChildFrame(14, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 14, blink::WebTreeScopeType::Document, std::string(), "uniqueName0",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
EXPECT_EQ(
"RenderFrameHostChanged(new)(14) -> 2: []\n"
"RenderFrameCreated(14) -> 2: [14: []]",
activity.GetLog());
- main_test_rfh()->OnCreateChildFrame(18, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 18, blink::WebTreeScopeType::Document, std::string(), "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
EXPECT_EQ(
"RenderFrameHostChanged(new)(18) -> 2: [14: []]\n"
"RenderFrameCreated(18) -> 2: [14: [], 18: []]",
@@ -378,18 +413,16 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
contents()->NavigateAndCommit(GURL("http://www.google.com"));
EXPECT_EQ("RenderFrameCreated(2) -> 2: []", activity.GetLog());
- main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 22, blink::WebTreeScopeType::Document, std::string(), "uniqueName0",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
EXPECT_EQ(
"RenderFrameHostChanged(new)(22) -> 2: []\n"
"RenderFrameCreated(22) -> 2: [22: []]",
activity.GetLog());
- main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 23, blink::WebTreeScopeType::Document, std::string(), "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
EXPECT_EQ(
"RenderFrameHostChanged(new)(23) -> 2: [22: []]\n"
"RenderFrameCreated(23) -> 2: [22: [], 23: []]",
@@ -418,7 +451,8 @@ TEST_F(FrameTreeTest, FailAddFrameWithWrongProcessId) {
// Simulate attaching a frame from mismatched process id.
ASSERT_FALSE(frame_tree->AddFrame(
root, process_id + 1, 1, blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties()));
+ "uniqueName0", blink::WebSandboxFlags::None,
+ blink::WebFrameOwnerProperties()));
ASSERT_EQ("2: []", GetTreeState(frame_tree));
}
@@ -430,20 +464,18 @@ TEST_F(FrameTreeTest, ProcessCrashClearsGlobalMap) {
// Add a couple child frames to the main frame.
FrameTreeNode* root = contents()->GetFrameTree()->root();
- main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
- main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
- std::string(),
- blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 22, blink::WebTreeScopeType::Document, std::string(), "uniqueName0",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
+ main_test_rfh()->OnCreateChildFrame(
+ 23, blink::WebTreeScopeType::Document, std::string(), "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
// Add one grandchild frame.
RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
- child1_rfh->OnCreateChildFrame(33, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ child1_rfh->OnCreateChildFrame(
+ 33, blink::WebTreeScopeType::Document, std::string(), "uniqueName2",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
// Ensure they can be found by id.
int id1 = root->child_at(0)->frame_tree_node_id();
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.cc b/chromium/content/browser/frame_host/interstitial_page_impl.cc
index 251e3bc642f..784c9b481d5 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.cc
@@ -53,28 +53,6 @@ using blink::WebDragOperation;
using blink::WebDragOperationsMask;
namespace content {
-namespace {
-
-void ResourceRequestHelper(ResourceDispatcherHostImpl* rdh,
- int process_id,
- int render_view_host_id,
- ResourceRequestAction action) {
- switch (action) {
- case BLOCK:
- rdh->BlockRequestsForRoute(process_id, render_view_host_id);
- break;
- case RESUME:
- rdh->ResumeBlockedRequestsForRoute(process_id, render_view_host_id);
- break;
- case CANCEL:
- rdh->CancelBlockedRequestsForRoute(process_id, render_view_host_id);
- break;
- default:
- NOTREACHED();
- }
-}
-
-} // namespace
class InterstitialPageImpl::InterstitialPageRVHDelegateView
: public RenderViewHostDelegateView {
@@ -181,15 +159,17 @@ InterstitialPageImpl::InterstitialPageImpl(
// TODO(creis): We will also need to pass delegates for the RVHM as we
// start to use it.
frame_tree_(new InterstitialPageNavigatorImpl(this, controller_),
- this, this, this,
+ this,
+ this,
+ this,
static_cast<WebContentsImpl*>(web_contents)),
original_child_id_(web_contents->GetRenderProcessHost()->GetID()),
original_rvh_id_(web_contents->GetRenderViewHost()->GetRoutingID()),
should_revert_web_contents_title_(false),
- web_contents_was_loading_(false),
resource_dispatcher_host_notified_(false),
rvh_delegate_view_(new InterstitialPageRVHDelegateView(this)),
create_view_(true),
+ pause_throbber_(false),
delegate_(delegate),
weak_ptr_factory_(this) {
InitInterstitialPageMap();
@@ -523,6 +503,9 @@ void InterstitialPageImpl::DidNavigate(
return;
}
+ // The interstitial is not loading anymore so stop the throbber.
+ pause_throbber_ = true;
+
// The RenderViewHost has loaded its contents, we can show it now.
if (!controller_->delegate()->IsHidden())
render_view_host_->GetWidget()->GetView()->Show();
@@ -540,14 +523,6 @@ void InterstitialPageImpl::DidNavigate(
// Hide the original RVH since we're showing the interstitial instead.
rwh_view->Hide();
}
-
- // Notify the tab we are not loading so the throbber is stopped. It also
- // causes a WebContentsObserver::DidStopLoading callback that the
- // AutomationProvider (used by the UI tests) expects to consider a navigation
- // as complete. Without this, navigating in a UI test to a URL that triggers
- // an interstitial would hang.
- web_contents_was_loading_ = controller_->delegate()->IsLoading();
- controller_->delegate()->SetIsLoading(false, true, NULL);
}
RendererPreferences InterstitialPageImpl::GetRendererPrefs(
@@ -577,17 +552,6 @@ void InterstitialPageImpl::HandleKeyboardEvent(
render_widget_host_delegate_->HandleKeyboardEvent(event);
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible
-InterstitialPageImpl::GetParentNativeViewAccessible() {
- if (web_contents_) {
- WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents_);
- return wci->GetParentNativeViewAccessible();
- }
- return NULL;
-}
-#endif
-
WebContents* InterstitialPageImpl::web_contents() const {
return web_contents_;
}
@@ -657,8 +621,8 @@ void InterstitialPageImpl::Proceed() {
action_taken_ = PROCEED_ACTION;
// Resumes the throbber, if applicable.
- if (web_contents_was_loading_)
- controller_->delegate()->SetIsLoading(true, true, NULL);
+ pause_throbber_ = false;
+ controller_->delegate()->DidProceedOnInterstitial();
// If this is a new navigation, the old page is going away, so we cancel any
// blocked requests for it. If it is not a new navigation, then it means the
@@ -855,22 +819,25 @@ void InterstitialPageImpl::TakeActionOnResourceDispatcher(
// The tab might not have a render_view_host if it was closed (in which case,
// we have taken care of the blocked requests when processing
// NOTIFY_RENDER_WIDGET_HOST_DESTROYED.
- // Also we need to test there is a ResourceDispatcherHostImpl, as when unit-
- // tests we don't have one.
RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(original_child_id_,
original_rvh_id_);
- if (!rvh || !ResourceDispatcherHostImpl::Get())
+ if (!rvh)
return;
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &ResourceRequestHelper,
- ResourceDispatcherHostImpl::Get(),
- original_child_id_,
- original_rvh_id_,
- action));
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
+ switch (action) {
+ case BLOCK:
+ ResourceDispatcherHost::BlockRequestsForFrameFromUI(rfh);
+ break;
+ case RESUME:
+ ResourceDispatcherHost::ResumeBlockedRequestsForFrameFromUI(rfh);
+ break;
+ default:
+ DCHECK_EQ(action, CANCEL);
+ ResourceDispatcherHostImpl::CancelBlockedRequestsForFrameFromUI(rfh);
+ break;
+ }
}
void InterstitialPageImpl::OnDomOperationResponse(
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.h b/chromium/content/browser/frame_host/interstitial_page_impl.h
index 32361e881e3..f619d050d24 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.h
@@ -88,6 +88,8 @@ class CONTENT_EXPORT InterstitialPageImpl
}
bool reload_on_dont_proceed() const { return reload_on_dont_proceed_; }
+ bool pause_throbber() const { return pause_throbber_; }
+
// TODO(nasko): This should move to InterstitialPageNavigatorImpl, but in
// the meantime make it public, so it can be called directly.
void DidNavigate(
@@ -154,9 +156,6 @@ class CONTENT_EXPORT InterstitialPageImpl
bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) override;
void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
-#if defined(OS_WIN)
- gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
-#endif
bool enabled() const { return enabled_; }
WebContents* web_contents() const;
@@ -271,10 +270,6 @@ class CONTENT_EXPORT InterstitialPageImpl
// revert it to its original value).
bool should_revert_web_contents_title_;
- // Whether or not the contents was loading resources when the interstitial was
- // shown. We restore this state if the user proceeds from the interstitial.
- bool web_contents_was_loading_;
-
// Whether the ResourceDispatcherHost has been notified to cancel/resume the
// resource requests blocked for the RenderViewHost.
bool resource_dispatcher_host_notified_;
@@ -283,7 +278,7 @@ class CONTENT_EXPORT InterstitialPageImpl
// interstitial is hidden.
base::string16 original_web_contents_title_;
- // Our RenderViewHostViewDelegate, necessary for accelerators to work.
+ // Our RenderViewHostDelegateView, necessary for accelerators to work.
scoped_ptr<InterstitialPageRVHDelegateView> rvh_delegate_view_;
// Settings passed to the renderer.
@@ -291,6 +286,11 @@ class CONTENT_EXPORT InterstitialPageImpl
bool create_view_;
+ // Whether the throbber should be paused. This is true from the moment the
+ // interstitial is shown until the moment the interstitial goes away or the
+ // user chooses to proceed.
+ bool pause_throbber_;
+
scoped_ptr<InterstitialPageDelegate> delegate_;
scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.cc b/chromium/content/browser/frame_host/navigation_controller_android.cc
index 81745177fb9..96aceacc070 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_android.cc
@@ -159,11 +159,11 @@ void NavigationControllerAndroid::ReloadToRefreshContent(
navigation_controller_->ReloadToRefreshContent(check_for_repost);
}
-void NavigationControllerAndroid::ReloadIgnoringCache(
+void NavigationControllerAndroid::ReloadBypassingCache(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean check_for_repost) {
- navigation_controller_->ReloadIgnoringCache(check_for_repost);
+ navigation_controller_->ReloadBypassingCache(check_for_repost);
}
void NavigationControllerAndroid::ReloadDisableLoFi(
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.h b/chromium/content/browser/frame_host/navigation_controller_android.h
index e22eb882a82..f2ec9058d95 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.h
+++ b/chromium/content/browser/frame_host/navigation_controller_android.h
@@ -57,9 +57,9 @@ class CONTENT_EXPORT NavigationControllerAndroid {
void ReloadToRefreshContent(JNIEnv* env,
jobject obj,
jboolean check_for_repost);
- void ReloadIgnoringCache(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jboolean check_for_repost);
+ void ReloadBypassingCache(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jboolean check_for_repost);
void ReloadDisableLoFi(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jboolean check_for_repost);
diff --git a/chromium/content/browser/frame_host/navigation_controller_delegate.h b/chromium/content/browser/frame_host/navigation_controller_delegate.h
index 9922ac59817..8a20e2bcd01 100644
--- a/chromium/content/browser/frame_host/navigation_controller_delegate.h
+++ b/chromium/content/browser/frame_host/navigation_controller_delegate.h
@@ -42,7 +42,6 @@ class NavigationControllerDelegate {
virtual void Stop() = 0;
virtual int32_t GetMaxPageID() = 0;
virtual int32_t GetMaxPageIDForSiteInstance(SiteInstance* site_instance) = 0;
- virtual bool IsLoading() const = 0;
virtual bool IsBeingDestroyed() const = 0;
virtual bool CanOverscrollContent() const = 0;
@@ -71,10 +70,8 @@ class NavigationControllerDelegate {
RenderFrameHost* render_frame_host) = 0;
virtual void AttachInterstitialPage(
InterstitialPageImpl* interstitial_page) = 0;
+ virtual void DidProceedOnInterstitial() = 0;
virtual void DetachInterstitialPage() = 0;
- virtual void SetIsLoading(bool is_loading,
- bool to_different_document,
- LoadNotificationDetails* details) = 0;
};
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.cc b/chromium/content/browser/frame_host/navigation_controller_impl.cc
index 071cec8e4bb..ac57709fb7e 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.cc
@@ -57,6 +57,7 @@
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
+#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/renderer_host/render_view_host_impl.h" // Temporary
#include "content/browser/site_instance_impl.h"
@@ -76,10 +77,9 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
-#include "content/public/common/content_switches.h"
+#include "content/public/common/content_features.h"
#include "media/base/mime_util.h"
#include "net/base/escape.h"
-#include "net/base/net_util.h"
#include "skia/ext/platform_canvas.h"
#include "url/url_constants.h"
@@ -148,13 +148,6 @@ bool ShouldKeepOverride(const NavigationEntry* last_entry) {
return last_entry && last_entry->GetIsOverridingUserAgent();
}
-// Helper method for FrameTree::ForEach to set the nav_entry_id on each current
-// RenderFrameHost in the tree.
-bool SetFrameNavEntryID(int nav_entry_id, FrameTreeNode* node) {
- node->current_frame_host()->set_nav_entry_id(nav_entry_id);
- return true;
-}
-
} // namespace
// NavigationControllerImpl ----------------------------------------------------
@@ -235,7 +228,6 @@ NavigationControllerImpl::NavigationControllerImpl(
: browser_context_(browser_context),
pending_entry_(NULL),
failed_pending_entry_id_(0),
- failed_pending_entry_should_replace_(false),
last_committed_entry_index_(-1),
pending_entry_index_(-1),
transient_entry_index_(-1),
@@ -295,15 +287,30 @@ void NavigationControllerImpl::Reload(bool check_for_repost) {
ReloadInternal(check_for_repost, RELOAD);
}
void NavigationControllerImpl::ReloadToRefreshContent(bool check_for_repost) {
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableNonValidatingReloadOnRefreshContent)) {
- ReloadInternal(check_for_repost, NO_RELOAD);
- } else {
- ReloadInternal(check_for_repost, RELOAD);
+ if (base::FeatureList::IsEnabled(
+ features::kNonValidatingReloadOnRefreshContent)) {
+ // Cause this reload to behave like NAVIGATION_TYPE_SAME_PAGE (e.g., enter
+ // in the omnibox), so that the main resource is cache-validated but all
+ // other resources use the cache as much as possible. This requires
+ // navigating to the current URL in a new pending entry.
+ // TODO(toyoshim): Introduce a new ReloadType for this behavior if it
+ // becomes the default.
+ NavigationEntryImpl* last_committed = GetLastCommittedEntry();
+
+ // If the last committed entry does not exist, or a repost check dialog is
+ // really needed, use a standard reload instead.
+ if (last_committed &&
+ !(check_for_repost && last_committed->GetHasPostData())) {
+ LoadURL(last_committed->GetURL(), last_committed->GetReferrer(),
+ last_committed->GetTransitionType(),
+ last_committed->extra_headers());
+ return;
+ }
}
+ ReloadInternal(check_for_repost, RELOAD);
}
-void NavigationControllerImpl::ReloadIgnoringCache(bool check_for_repost) {
- ReloadInternal(check_for_repost, RELOAD_IGNORING_CACHE);
+void NavigationControllerImpl::ReloadBypassingCache(bool check_for_repost) {
+ ReloadInternal(check_for_repost, RELOAD_BYPASSING_CACHE);
}
void NavigationControllerImpl::ReloadOriginalRequestURL(bool check_for_repost) {
ReloadInternal(check_for_repost, RELOAD_ORIGINAL_REQUEST_URL);
@@ -581,48 +588,13 @@ bool NavigationControllerImpl::CanGoToOffset(int offset) const {
}
void NavigationControllerImpl::GoBack() {
- if (!CanGoBack()) {
- NOTREACHED();
- return;
- }
-
- // Base the navigation on where we are now...
- int current_index = GetCurrentEntryIndex();
-
- DiscardNonCommittedEntries();
-
- pending_entry_index_ = current_index - 1;
- entries_[pending_entry_index_]->SetTransitionType(
- ui::PageTransitionFromInt(
- entries_[pending_entry_index_]->GetTransitionType() |
- ui::PAGE_TRANSITION_FORWARD_BACK));
- NavigateToPendingEntry(NO_RELOAD);
+ // Call GoToIndex rather than GoToOffset to get the NOTREACHED() check.
+ GoToIndex(GetIndexForOffset(-1));
}
void NavigationControllerImpl::GoForward() {
- if (!CanGoForward()) {
- NOTREACHED();
- return;
- }
-
- bool transient = (transient_entry_index_ != -1);
-
- // Base the navigation on where we are now...
- int current_index = GetCurrentEntryIndex();
-
- DiscardNonCommittedEntries();
-
- pending_entry_index_ = current_index;
- // If there was a transient entry, we removed it making the current index
- // the next page.
- if (!transient)
- pending_entry_index_++;
-
- entries_[pending_entry_index_]->SetTransitionType(
- ui::PageTransitionFromInt(
- entries_[pending_entry_index_]->GetTransitionType() |
- ui::PAGE_TRANSITION_FORWARD_BACK));
- NavigateToPendingEntry(NO_RELOAD);
+ // Call GoToIndex rather than GoToOffset to get the NOTREACHED() check.
+ GoToIndex(GetIndexForOffset(1));
}
void NavigationControllerImpl::GoToIndex(int index) {
@@ -653,6 +625,7 @@ void NavigationControllerImpl::GoToIndex(int index) {
}
void NavigationControllerImpl::GoToOffset(int offset) {
+ // Note: This is actually reached in unit tests.
if (!CanGoToOffset(offset))
return;
@@ -822,6 +795,12 @@ void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
LoadEntry(std::move(entry));
}
+bool NavigationControllerImpl::PendingEntryMatchesHandle(
+ NavigationHandleImpl* handle) const {
+ return pending_entry_ &&
+ pending_entry_->GetUniqueID() == handle->pending_nav_entry_id();
+}
+
bool NavigationControllerImpl::RendererDidNavigate(
RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
@@ -846,20 +825,8 @@ bool NavigationControllerImpl::RendererDidNavigate(
pending_entry_->restore_type() != NavigationEntryImpl::RESTORE_NONE)
pending_entry_->set_restore_type(NavigationEntryImpl::RESTORE_NONE);
- // If we are doing a cross-site reload, we need to replace the existing
- // navigation entry, not add another entry to the history. This has the side
- // effect of removing forward browsing history, if such existed. Or if we are
- // doing a cross-site redirect navigation, we will do a similar thing.
- //
- // If this is an error load, we may have already removed the pending entry
- // when we got the notice of the load failure. If so, look at the copy of the
- // pending parameters that were saved.
- if (params.url_is_unreachable && failed_pending_entry_id_ != 0) {
- details->did_replace_entry = failed_pending_entry_should_replace_;
- } else {
- details->did_replace_entry = pending_entry_ &&
- pending_entry_->should_replace_entry();
- }
+ // The renderer tells us whether the navigation replaces the current entry.
+ details->did_replace_entry = params.should_replace_current_entry;
// Do navigation-type specific actions. These will make and commit an entry.
details->type = ClassifyNavigation(rfh, params);
@@ -880,7 +847,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
RendererDidNavigateToSamePage(rfh, params);
break;
case NAVIGATION_TYPE_NEW_SUBFRAME:
- RendererDidNavigateNewSubframe(rfh, params);
+ RendererDidNavigateNewSubframe(rfh, params, details->did_replace_entry);
break;
case NAVIGATION_TYPE_AUTO_SUBFRAME:
if (!RendererDidNavigateAutoSubframe(rfh, params))
@@ -976,8 +943,9 @@ bool NavigationControllerImpl::RendererDidNavigate(
// committed anything in this navigation or not). This allows things like
// state and title updates from RenderFrames to apply to the latest relevant
// NavigationEntry.
- delegate_->GetFrameTree()->ForEach(
- base::Bind(&SetFrameNavEntryID, active_entry->GetUniqueID()));
+ int nav_entry_id = active_entry->GetUniqueID();
+ for (FrameTreeNode* node : delegate_->GetFrameTree()->Nodes())
+ node->current_frame_host()->set_nav_entry_id(nav_entry_id);
return true;
}
@@ -1003,6 +971,18 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
return NAVIGATION_TYPE_NEW_SUBFRAME;
}
+ // Cross-process location.replace navigations should be classified as New with
+ // replacement rather than ExistingPage, since it is not safe to reuse the
+ // NavigationEntry.
+ // TODO(creis): Have the renderer classify location.replace as
+ // did_create_new_entry for all cases and eliminate this special case. This
+ // requires updating several test expectations. See https://crbug.com/317872.
+ if (!rfh->GetParent() && GetLastCommittedEntry() &&
+ GetLastCommittedEntry()->site_instance() != rfh->GetSiteInstance() &&
+ params.should_replace_current_entry) {
+ return NAVIGATION_TYPE_NEW_PAGE;
+ }
+
// We only clear the session history when navigating to a new page.
DCHECK(!params.history_list_was_cleared);
@@ -1090,12 +1070,18 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
scoped_ptr<NavigationEntryImpl> new_entry;
bool update_virtual_url;
// Only make a copy of the pending entry if it is appropriate for the new page
- // that was just loaded. We verify this at a coarse grain by checking that
- // the SiteInstance hasn't been assigned to something else, and by making sure
- // that the pending entry was intended as a new entry (rather than being a
- // history navigation that was interrupted by an unrelated, renderer-initiated
- // navigation).
- if (pending_entry_ && pending_entry_index_ == -1 &&
+ // that was just loaded. Verify this by checking if the entry corresponds
+ // to the current navigation handle. Note that in some tests the render frame
+ // host does not have a valid handle. Additionally, coarsely check that:
+ // 1. The SiteInstance hasn't been assigned to something else.
+ // 2. The pending entry was intended as a new entry, rather than being a
+ // history navigation that was interrupted by an unrelated,
+ // renderer-initiated navigation.
+ // TODO(csharrison): Investigate whether we can remove some of the coarser
+ // checks.
+ NavigationHandleImpl* handle = rfh->navigation_handle();
+ DCHECK(handle);
+ if (PendingEntryMatchesHandle(handle) && pending_entry_index_ == -1 &&
(!pending_entry_->site_instance() ||
pending_entry_->site_instance() == rfh->GetSiteInstance())) {
new_entry = pending_entry_->Clone();
@@ -1262,7 +1248,8 @@ void NavigationControllerImpl::RendererDidNavigateToSamePage(
void NavigationControllerImpl::RendererDidNavigateNewSubframe(
RenderFrameHostImpl* rfh,
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
+ bool replace_entry) {
DCHECK(ui::PageTransitionCoreTypeIs(params.transition,
ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1292,7 +1279,7 @@ void NavigationControllerImpl::RendererDidNavigateNewSubframe(
}
new_entry->SetPageID(params.page_id);
- InsertOrReplaceEntry(std::move(new_entry), false);
+ InsertOrReplaceEntry(std::move(new_entry), replace_entry);
}
bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
@@ -1592,21 +1579,25 @@ NavigationControllerImpl::GetSessionStorageNamespace(SiteInstance* instance) {
browser_context_, instance->GetSiteURL());
}
+ // TODO(ajwong): Should this use the |partition_id| directly rather than
+ // re-lookup via |instance|? http://crbug.com/142685
+ StoragePartition* partition =
+ BrowserContext::GetStoragePartition(browser_context_, instance);
+ DOMStorageContextWrapper* context_wrapper =
+ static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
+
SessionStorageNamespaceMap::const_iterator it =
session_storage_namespace_map_.find(partition_id);
- if (it != session_storage_namespace_map_.end())
+ if (it != session_storage_namespace_map_.end()) {
+ // Ensure that this namespace actually belongs to this partition.
+ DCHECK(static_cast<SessionStorageNamespaceImpl*>(it->second.get())->
+ IsFromContext(context_wrapper));
return it->second.get();
+ }
// Create one if no one has accessed session storage for this partition yet.
- //
- // TODO(ajwong): Should this use the |partition_id| directly rather than
- // re-lookup via |instance|? http://crbug.com/142685
- StoragePartition* partition =
- BrowserContext::GetStoragePartition(browser_context_, instance);
SessionStorageNamespaceImpl* session_storage_namespace =
- new SessionStorageNamespaceImpl(
- static_cast<DOMStorageContextWrapper*>(
- partition->GetDOMStorageContext()));
+ new SessionStorageNamespaceImpl(context_wrapper);
session_storage_namespace_map_[partition_id] = session_storage_namespace;
return session_storage_namespace;
@@ -1875,8 +1866,10 @@ void NavigationControllerImpl::FindFramesToNavigate(
same_document_loads->push_back(std::make_pair(frame, new_item));
} else {
different_document_loads->push_back(std::make_pair(frame, new_item));
+ // For a different document, the subframes will be destroyed, so there's
+ // no need to consider them.
+ return;
}
- return;
}
for (size_t i = 0; i < frame->child_count(); i++) {
@@ -1973,8 +1966,6 @@ void NavigationControllerImpl::DiscardPendingEntry(bool was_failure) {
if (was_failure && pending_entry_) {
failed_pending_entry_id_ = pending_entry_->GetUniqueID();
- failed_pending_entry_should_replace_ =
- pending_entry_->should_replace_entry();
} else {
failed_pending_entry_id_ = 0;
}
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.h b/chromium/content/browser/frame_host/navigation_controller_impl.h
index 72b76d7464a..a0067f49051 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.h
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.h
@@ -87,7 +87,7 @@ class CONTENT_EXPORT NavigationControllerImpl
bool IsInitialBlankNavigation() const override;
void Reload(bool check_for_repost) override;
void ReloadToRefreshContent(bool check_for_repost) override;
- void ReloadIgnoringCache(bool check_for_repost) override;
+ void ReloadBypassingCache(bool check_for_repost) override;
void ReloadOriginalRequestURL(bool check_for_repost) override;
void ReloadDisableLoFi(bool check_for_repost) override;
void NotifyEntryChanged(const NavigationEntry* entry) override;
@@ -258,6 +258,10 @@ class CONTENT_EXPORT NavigationControllerImpl
FrameLoadVector* sameDocumentLoads,
FrameLoadVector* differentDocumentLoads);
+ // Returns whether there is a pending NavigationEntry whose unique ID matches
+ // the given NavigationHandle's pending_nav_entry_id.
+ bool PendingEntryMatchesHandle(NavigationHandleImpl* handle) const;
+
// Classifies the given renderer navigation (see the NavigationType enum).
NavigationType ClassifyNavigation(
RenderFrameHostImpl* rfh,
@@ -272,9 +276,11 @@ class CONTENT_EXPORT NavigationControllerImpl
// anything if some random subframe is loaded. It will return true if anything
// changed, or false if not.
//
- // The functions taking |did_replace_entry| will fill into the given variable
- // whether the last entry has been replaced or not.
- // See LoadCommittedDetails.did_replace_entry.
+ // The NewPage and NewSubframe functions take in |replace_entry| to pass to
+ // InsertOrReplaceEntry, in case the newly created NavigationEntry is meant to
+ // replace the current one (e.g., for location.replace or successful loads
+ // after net errors), in contrast to updating a NavigationEntry in place
+ // (e.g., for history.replaceState).
void RendererDidNavigateToNewPage(
RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
@@ -287,12 +293,14 @@ class CONTENT_EXPORT NavigationControllerImpl
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
void RendererDidNavigateNewSubframe(
RenderFrameHostImpl* rfh,
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
+ bool replace_entry);
bool RendererDidNavigateAutoSubframe(
RenderFrameHostImpl* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
- // Helper function for code shared between Reload() and ReloadIgnoringCache().
+ // Helper function for code shared between Reload() and
+ // ReloadBypassingCache().
void ReloadInternal(bool check_for_repost, ReloadType reload_type);
// Actually issues the navigation held in pending_entry.
@@ -369,8 +377,7 @@ class CONTENT_EXPORT NavigationControllerImpl
NavigationEntryImpl* pending_entry_;
// If a new entry fails loading, details about it are temporarily held here
- // until the error page is shown. These variables are only valid if
- // |failed_pending_entry_id_| is not 0.
+ // until the error page is shown (or 0 otherwise).
//
// TODO(avi): We need a better way to handle the connection between failed
// loads and the subsequent load of the error page. This current approach has
@@ -378,7 +385,6 @@ class CONTENT_EXPORT NavigationControllerImpl
// error page loaded, and 2. This doesn't work very well for frames.
// http://crbug.com/474261
int failed_pending_entry_id_;
- bool failed_pending_entry_should_replace_;
// The index of the currently visible entry.
int last_committed_entry_index_;
@@ -428,7 +434,7 @@ class CONTENT_EXPORT NavigationControllerImpl
// The maximum number of entries that a navigation controller can store.
static size_t max_entry_count_for_testing_;
- // If a repost is pending, its type (RELOAD or RELOAD_IGNORING_CACHE),
+ // If a repost is pending, its type (RELOAD or RELOAD_BYPASSING_CACHE),
// NO_RELOAD otherwise.
ReloadType pending_reload_;
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 5ead3764296..561f84ccc0f 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -15,8 +15,11 @@
#include "content/browser/frame_host/frame_navigation_entry.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/page_state_serialization.h"
#include "content/common/site_isolation_policy.h"
+#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host.h"
@@ -25,6 +28,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/bindings_policy.h"
+#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
@@ -34,6 +38,7 @@
#include "content/shell/browser/shell.h"
#include "content/shell/common/shell_switches.h"
#include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/test_frame_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/url_request/url_request_failed_job.h"
@@ -631,7 +636,7 @@ class LoadCommittedCapturer : public WebContentsObserver {
// Don't pay attention to swapped out RenderFrameHosts in the main frame.
// TODO(nasko): Remove once swappedout:// is gone.
// See https://crbug.com/357747.
- if (!RenderFrameHostImpl::IsRFHStateActive(rfh->rfh_state())) {
+ if (!rfh->is_active()) {
DLOG(INFO) << "Skipping swapped out RFH: "
<< rfh->GetSiteInstance()->GetSiteURL();
return;
@@ -721,15 +726,15 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
EXPECT_EQ(3, controller.GetEntryCount());
- // ... and replace it with a failed load. (Note that when you set the
- // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
- // because that is a classification of the renderer's behavior, and the flag
- // is a browser-side flag.)
+ // ... and replace it with a failed load.
+ // TODO(creis): Make this be NEW_PAGE along with the other location.replace
+ // cases. There isn't much impact to having this be EXISTING_PAGE for now.
+ // See https://crbug.com/317872.
{
FrameNavigateParamsCapturer capturer(root);
NavigateToURLAndReplace(shell(), error_url);
capturer.Wait();
- EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(3, controller.GetEntryCount());
@@ -829,6 +834,20 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
EXPECT_TRUE(capturer.details().is_in_page);
}
+
+ if (AreAllSitesIsolatedForTesting()) {
+ // Cross-process location.replace().
+ FrameNavigateParamsCapturer capturer(root);
+ GURL frame_url(embedded_test_server()->GetURL(
+ "foo.com", "/navigation_controller/simple_page_1.html"));
+ std::string script = "location.replace('" + frame_url.spec() + "')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
+ capturer.params().transition);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ EXPECT_FALSE(capturer.details().is_in_page);
+ }
}
// Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
@@ -952,6 +971,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// location.replace().
+ // TODO(creis): Change this to be NEW_PAGE with replacement in
+ // https://crbug.com/317872.
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
@@ -2673,8 +2694,18 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"bar.com", "/navigation_controller/simple_page_1.html"));
NavigateFrameToURL(foo_subframe, bar_url);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
- EXPECT_NE(main_site_instance,
- foo_subframe->current_frame_host()->GetSiteInstance());
+
+ // When run just with subframe navigation entries enabled and not in
+ // site-per-process-mode the subframe should be in the same SiteInstance as
+ // its parent.
+ if (!AreAllSitesIsolatedForTesting()) {
+ EXPECT_EQ(main_site_instance,
+ foo_subframe->current_frame_host()->GetSiteInstance());
+ } else {
+ EXPECT_NE(main_site_instance,
+ foo_subframe->current_frame_host()->GetSiteInstance());
+ }
+
foo_subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(foo_subframe);
EXPECT_EQ(named_subframe_name, foo_subframe_entry->frame_unique_name());
@@ -2940,6 +2971,63 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
DoReplaceStateWhilePending(shell(), url, url, "simple_page_1.html");
}
+// Ensure that a pending NavigationEntry for a different navigation doesn't
+// cause a commit to be incorrectly treated as a replacement.
+// See https://crbug.com/593153.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ OtherCommitDuringPendingEntryWithReplacement) {
+ NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+ shell()->web_contents()->GetController());
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Load an initial page.
+ GURL start_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+ int entry_count = controller.GetEntryCount();
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(start_url, controller.GetLastCommittedEntry()->GetURL());
+
+ // Start a cross-process navigation with replacement, which never completes.
+ GURL foo_url(embedded_test_server()->GetURL(
+ "foo.com", "/navigation_controller/page_with_links.html"));
+ NavigationStallDelegate stall_delegate(foo_url);
+ ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
+ NavigationController::LoadURLParams params(foo_url);
+ params.should_replace_current_entry = true;
+ controller.LoadURLWithParams(params);
+
+ // That should be the pending entry.
+ NavigationEntryImpl* entry = controller.GetPendingEntry();
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(foo_url, entry->GetURL());
+ EXPECT_EQ(entry_count, controller.GetEntryCount());
+
+ {
+ // Now the existing page uses history.pushState() while the pending entry
+ // for the other navigation still exists.
+ FrameNavigateParamsCapturer capturer(root);
+ capturer.set_wait_for_load(false);
+ std::string script = "history.pushState({}, '', 'pushed')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ capturer.Wait();
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+ EXPECT_TRUE(capturer.details().is_in_page);
+ }
+
+ // The in-page navigation should not have replaced the previous entry.
+ GURL push_state_url(
+ embedded_test_server()->GetURL("/navigation_controller/pushed"));
+ EXPECT_EQ(entry_count + 1, controller.GetEntryCount());
+ EXPECT_EQ(push_state_url, controller.GetLastCommittedEntry()->GetURL());
+ EXPECT_EQ(start_url, controller.GetEntryAtIndex(0)->GetURL());
+
+ ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+}
+
// Ensure the renderer process does not get confused about the current entry
// due to subframes and replaced entries. See https://crbug.com/480201.
// TODO(creis): Re-enable for Site Isolation FYI bots: https://crbug.com/502317.
@@ -3136,6 +3224,15 @@ class FailureWatcher : public WebContentsObserver {
message_loop_runner_->Quit();
}
+ void DidFinishNavigation(NavigationHandle* handle) override {
+ if (handle->GetFrameTreeNodeId() != frame_tree_node_id_)
+ return;
+ if (handle->HasCommitted())
+ return;
+
+ message_loop_runner_->Quit();
+ }
+
// The id of the FrameTreeNode whose navigations to observe.
int frame_tree_node_id_;
@@ -3146,7 +3243,7 @@ class FailureWatcher : public WebContentsObserver {
} // namespace
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
- StopCausesFailureDespiteJavaScriptURL) {
+ DISABLED_StopCausesFailureDespiteJavaScriptURL) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
@@ -3160,7 +3257,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
- // Have the user decide to go to a different page which is very slow.
+ // Have the user decide to go to a different page which will not commit.
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
NavigationStallDelegate stall_delegate(url2);
@@ -3180,8 +3277,10 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// This LoadURL ends up purging the pending entry, which is why this is
// tricky.
EXPECT_EQ(nullptr, controller.GetPendingEntry());
+ EXPECT_TRUE(shell()->web_contents()->IsLoading());
shell()->web_contents()->Stop();
watcher.Wait();
+ EXPECT_FALSE(shell()->web_contents()->IsLoading());
}
ResourceDispatcherHost::Get()->SetDelegate(nullptr);
@@ -3262,4 +3361,309 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
ExecuteScript(shell()->web_contents(), "console.log('Success');"));
}
+// This tests that 1) the initial "about:blank" URL is elided from the
+// navigation history of a subframe when it is loaded, and 2) that that initial
+// "about:blank" returns if it is navigated to as part of a history navigation.
+// See http://crbug.com/542299 and https://github.com/whatwg/html/issues/546 .
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ BackToAboutBlankIframe) {
+ GURL original_url(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ NavigateToURL(shell(), original_url);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ NavigationController& controller = shell()->web_contents()->GetController();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+
+ // Add an iframe with no 'src'.
+
+ std::string script =
+ "var iframe = document.createElement('iframe');"
+ "iframe.id = 'frame';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* frame = root->child_at(0);
+ ASSERT_NE(nullptr, frame);
+
+ EXPECT_EQ(GURL(url::kAboutBlankURL), frame->current_url());
+
+ // Now create a new navigation entry. Note that the old navigation entry has
+ // "about:blank" as the URL in the iframe.
+
+ script = "history.pushState({}, '', 'notarealurl.html')";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+ // Load the iframe; the initial "about:blank" URL should be elided and thus we
+ // shouldn't get a new navigation entry.
+
+ GURL frame_url = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html");
+ NavigateFrameToURL(frame, frame_url);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(frame_url, frame->current_url());
+
+ // Go back. Because the old state had an empty frame, that should be restored
+ // even though it was replaced in the second navigation entry.
+
+ TestFrameNavigationObserver observer(frame);
+ ASSERT_TRUE(controller.CanGoBack());
+ controller.GoBack();
+ observer.Wait();
+
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(GURL(url::kAboutBlankURL), frame->current_url());
+}
+
+// This test is similar to "BackToAboutBlankIframe" above, except that a
+// fragment navigation is used rather than pushState (both create an in-page
+// navigation, so we need to test both), and an initial 'src' is given to the
+// iframe to test proper restoration in that case.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ BackToIframeWithContent) {
+ GURL links_url(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_links.html"));
+ NavigateToURL(shell(), links_url);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ NavigationController& controller = shell()->web_contents()->GetController();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+
+ // Add an iframe with a 'src'.
+
+ GURL frame_url_1 = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html");
+ std::string script =
+ "var iframe = document.createElement('iframe');"
+ "iframe.src = '" + frame_url_1.spec() + "';"
+ "iframe.id = 'frame';"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(1, controller.GetEntryCount());
+ EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* frame = root->child_at(0);
+ ASSERT_NE(nullptr, frame);
+
+ EXPECT_EQ(frame_url_1, frame->current_url());
+
+ // Do a fragment navigation, creating a new navigation entry. Note that the
+ // old navigation entry has frame_url_1 as the URL in the iframe.
+
+ script = "document.getElementById('fraglink').click()";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(frame_url_1, frame->current_url());
+
+ // Navigate the iframe; unlike the test "BackToAboutBlankIframe" above, this
+ // _will_ create a new navigation entry.
+
+ GURL frame_url_2 = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html");
+ NavigateFrameToURL(frame, frame_url_2);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(3, controller.GetEntryCount());
+ EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(frame_url_2, frame->current_url());
+
+ // Go back two entries. The original frame URL should be back.
+
+ TestFrameNavigationObserver observer(frame);
+ ASSERT_TRUE(controller.CanGoToOffset(-2));
+ controller.GoToOffset(-2);
+ observer.Wait();
+
+ EXPECT_EQ(3, controller.GetEntryCount());
+ EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(frame_url_1, frame->current_url());
+}
+
+// Ensure that we do not corrupt a NavigationEntry's PageState if a subframe
+// forward navigation commits after we've already started another forward
+// navigation in the main frame. See https://crbug.com/597322.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ ForwardInSubframeWithPendingForward) {
+ // Navigate to a page with an iframe.
+ GURL url_a(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_data_iframe.html"));
+ GURL frame_url_a1("data:text/html,Subframe");
+ EXPECT_TRUE(NavigateToURL(shell(), url_a));
+
+ NavigationController& controller = shell()->web_contents()->GetController();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ EXPECT_EQ(url_a, root->current_url());
+ FrameTreeNode* frame = root->child_at(0);
+ EXPECT_EQ(frame_url_a1, frame->current_url());
+
+ // Navigate the iframe to a second page.
+ GURL frame_url_a2 = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html");
+ NavigateFrameToURL(frame, frame_url_a2);
+
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+ EXPECT_EQ(url_a, root->current_url());
+ EXPECT_EQ(frame_url_a2, frame->current_url());
+
+ // Navigate the top-level frame to another page with an iframe.
+ GURL url_b(embedded_test_server()->GetURL(
+ "/navigation_controller/page_with_iframe.html"));
+ GURL frame_url_b1(url::kAboutBlankURL);
+ EXPECT_TRUE(NavigateToURL(shell(), url_b));
+ EXPECT_EQ(3, controller.GetEntryCount());
+ EXPECT_EQ(url_b, root->current_url());
+ EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url());
+
+ // Go back two entries. The original frame URL should be back.
+ ASSERT_TRUE(controller.CanGoToOffset(-2));
+ controller.GoToOffset(-2);
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+ EXPECT_EQ(url_a, root->current_url());
+ EXPECT_EQ(frame_url_a1, root->child_at(0)->current_url());
+
+ // Go forward two times in a row, being careful that the subframe commits
+ // after the second forward navigation begins but before the main frame
+ // commits.
+ TestNavigationManager subframe_delayer(shell()->web_contents(), frame_url_a2);
+ TestNavigationManager mainframe_delayer(shell()->web_contents(), url_b);
+ controller.GoForward();
+ subframe_delayer.WaitForWillStartRequest();
+ controller.GoForward();
+ mainframe_delayer.WaitForWillStartRequest();
+ EXPECT_EQ(2, controller.GetPendingEntryIndex());
+
+ // Let the subframe commit.
+ subframe_delayer.ResumeNavigation();
+ subframe_delayer.WaitForNavigationFinished();
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+ EXPECT_EQ(url_a, root->current_url());
+ EXPECT_EQ(frame_url_a2, root->child_at(0)->current_url());
+
+ // Let the main frame commit.
+ mainframe_delayer.ResumeNavigation();
+ mainframe_delayer.WaitForNavigationFinished();
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+ EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+ EXPECT_EQ(url_b, root->current_url());
+ EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url());
+
+ // Check the PageState of the previous entry to ensure it isn't corrupted.
+ NavigationEntry* entry = controller.GetEntryAtIndex(1);
+ EXPECT_EQ(url_a, entry->GetURL());
+ ExplodedPageState exploded_state;
+ EXPECT_TRUE(
+ DecodePageState(entry->GetPageState().ToEncodedData(), &exploded_state));
+ EXPECT_EQ(url_a, GURL(exploded_state.top.url_string.string()));
+ EXPECT_EQ(frame_url_a2,
+ GURL(exploded_state.top.children.at(0).url_string.string()));
+}
+
+// Ensure that forward navigations in cloned tabs can commit if they redirect to
+// a different site than before. This causes the navigation's item sequence
+// number to change, meaning that we can't use it for determining whether the
+// commit matches the history item. See https://crbug.com/600238.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ ForwardRedirectWithNoCommittedEntry) {
+ NavigationController& controller = shell()->web_contents()->GetController();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Put 2 pages in history.
+ GURL url_1(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url_1));
+
+ GURL url_2(embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_2.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url_2));
+
+ EXPECT_EQ(url_2, root->current_url());
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+ // Do a replaceState to a URL that will redirect when we come back to it via
+ // session history.
+ GURL url_3(embedded_test_server()->GetURL(
+ "foo.com", "/navigation_controller/page_with_links.html"));
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ std::string script =
+ "history.replaceState({}, '', '/server-redirect?" + url_3.spec() + "')";
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+ observer.Wait();
+ }
+
+ // Go back.
+ controller.GoBack();
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+ EXPECT_EQ(url_1, root->current_url());
+
+ // Clone the tab without navigating it.
+ std::unique_ptr<WebContentsImpl> new_tab(
+ static_cast<WebContentsImpl*>(shell()->web_contents()->Clone()));
+ NavigationController& new_controller = new_tab->GetController();
+ FrameTreeNode* new_root = new_tab->GetFrameTree()->root();
+ EXPECT_TRUE(new_controller.IsInitialNavigation());
+ EXPECT_TRUE(new_controller.NeedsReload());
+
+ // Go forward in the new tab.
+ {
+ TestNavigationObserver observer(new_tab.get());
+ new_controller.GoForward();
+ observer.Wait();
+ }
+ EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_EQ(url_3, new_root->current_url());
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 775feb3debf..e86f1fdba6f 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -46,7 +46,6 @@
#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
-#include "net/base/net_util.h"
#include "skia/ext/platform_canvas.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
@@ -296,6 +295,25 @@ class TestWebContentsDelegate : public WebContentsDelegate {
int repost_form_warning_count_;
};
+// Observer that records the LoadCommittedDetails from the most recent commit.
+class LoadCommittedDetailsObserver : public WebContentsObserver {
+ public:
+ // Observes navigation for the specified |web_contents|.
+ explicit LoadCommittedDetailsObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+ const LoadCommittedDetails& details() { return details_; }
+
+ private:
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override {
+ details_ = details;
+ }
+
+ LoadCommittedDetails details_;
+};
+
// -----------------------------------------------------------------------------
TEST_F(NavigationControllerTest, Defaults) {
@@ -384,6 +402,50 @@ TEST_F(NavigationControllerTest, GoToOffset) {
}
}
+// This test case was added to reproduce crbug.com/513742. The repro steps are
+// as follows:
+// 1. Pending entry for A is created.
+// 2. DidStartProvisionalLoad message for A arrives.
+// 3. Pending entry for B is created.
+// 4. DidFailProvisionalLoad message for A arrives. The logic here discards.
+// 5. DidStartProvisionalLoad message for B arrives.
+//
+// At step (4), the pending entry for B is discarded, when A is the one that
+// is being aborted. This caused the last committed entry to be displayed in
+// the omnibox, which is the entry before A was created.
+TEST_F(NavigationControllerTest, DontDiscardWrongPendingEntry) {
+ NavigationControllerImpl& controller = controller_impl();
+ GURL initial_url("http://www.google.com");
+ GURL url_1("http://foo.com");
+ GURL url_2("http://foo2.com");
+
+ // Navigate inititally. This is the url that could erroneously be the visible
+ // entry when url_1 fails.
+ NavigateAndCommit(initial_url);
+
+ // Set the pending entry as url_1 and receive the DidStartProvisionalLoad
+ // message, creating the NavigationHandle.
+ controller.LoadURL(url_1, Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
+ EXPECT_EQ(url_1, controller.GetVisibleEntry()->GetURL());
+ main_test_rfh()->SimulateNavigationStart(url_1);
+ EXPECT_EQ(url_1, controller.GetVisibleEntry()->GetURL());
+
+ // Navigate to url_2, aborting url_1 before the DidStartProvisionalLoad
+ // message is received for url_2. Do not discard the pending entry for url_2
+ // here.
+ controller.LoadURL(url_2, Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
+ EXPECT_EQ(url_2, controller.GetVisibleEntry()->GetURL());
+ main_test_rfh()->SimulateNavigationError(url_1, net::ERR_ABORTED);
+ EXPECT_EQ(url_2, controller.GetVisibleEntry()->GetURL());
+
+ // Get the DidStartProvisionalLoad message for url_2.
+ main_test_rfh()->SimulateNavigationStart(url_2);
+
+ EXPECT_EQ(url_2, controller.GetVisibleEntry()->GetURL());
+}
+
TEST_F(NavigationControllerTest, LoadURL) {
NavigationControllerImpl& controller = controller_impl();
TestNotificationTracker notifications;
@@ -1048,10 +1110,7 @@ TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_FALSE(controller.GetPendingEntry());
EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
- if (IsBrowserSideNavigationEnabled())
- EXPECT_EQ(4, delegate->navigation_state_change_count());
- else
- EXPECT_EQ(2, delegate->navigation_state_change_count());
+ EXPECT_EQ(2, delegate->navigation_state_change_count());
contents()->SetDelegate(NULL);
}
@@ -1469,7 +1528,7 @@ TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
// Fake a commit response.
main_test_rfh()->PrepareForCommit();
- main_test_rfh()->SendNavigate(1, entry_id, true, url1);
+ main_test_rfh()->SendNavigateWithReplacement(1, entry_id, true, url1);
// Certain values that are only used for pending entries get reset after
// commit.
@@ -1824,10 +1883,8 @@ TEST_F(NavigationControllerTest, Redirect) {
params.is_post = false;
params.page_state = PageState::CreateFromURL(url2);
- LoadCommittedDetails details;
-
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1844,12 +1901,13 @@ TEST_F(NavigationControllerTest, Redirect) {
params.did_create_new_entry = false;
EXPECT_EQ(0U, notifications.size());
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
+ EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, observer.details().type);
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -1893,10 +1951,8 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
params.is_post = true;
params.page_state = PageState::CreateFromURL(url2);
- LoadCommittedDetails details;
-
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1914,12 +1970,13 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
params.is_post = false;
EXPECT_EQ(0U, notifications.size());
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
+ EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, observer.details().type);
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -1963,15 +2020,15 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
params.is_post = false;
params.page_state = PageState::CreateFromURL(url2);
- LoadCommittedDetails details;
+ LoadCommittedDetailsObserver observer(contents());
EXPECT_EQ(0U, notifications.size());
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, observer.details().type);
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -2028,12 +2085,11 @@ TEST_F(NavigationControllerTest,
params.transition = ui::PAGE_TRANSITION_TYPED;
params.page_state = PageState::CreateFromURL(url1);
- LoadCommittedDetails details;
+ LoadCommittedDetailsObserver observer(contents());
main_test_rfh()->PrepareForCommit();
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
- EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details.type);
+ main_test_rfh()->SendNavigateWithParams(&params);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, observer.details().type);
}
// Tests navigation via link click within a subframe. A new navigation entry
@@ -2051,10 +2107,10 @@ TEST_F(NavigationControllerTest, NewSubframe) {
// Prereq: add a subframe with an initial auto-subframe navigation.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe =
- contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
const GURL subframe_url("http://foo1/subframe");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -2069,8 +2125,9 @@ TEST_F(NavigationControllerTest, NewSubframe) {
params.page_state = PageState::CreateFromURL(subframe_url);
// Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(subframe_url, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(0U, notifications.size());
}
@@ -2087,18 +2144,20 @@ TEST_F(NavigationControllerTest, NewSubframe) {
params.is_post = false;
params.page_state = PageState::CreateFromURL(url2);
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
+ LoadCommittedDetailsObserver observer(contents());
+ subframe->SendRendererInitiatedNavigationRequest(url2, true);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_EQ(url1, details.previous_url);
- EXPECT_FALSE(details.is_in_page);
- EXPECT_FALSE(details.is_main_frame);
+ EXPECT_EQ(url1, observer.details().previous_url);
+ EXPECT_FALSE(observer.details().is_in_page);
+ EXPECT_FALSE(observer.details().is_main_frame);
// The new entry should be appended.
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(entry, details.entry);
+ EXPECT_EQ(entry, observer.details().entry);
// New entry should refer to the new page, but the old URL (entries only
// reflect the toplevel URL).
@@ -2132,10 +2191,10 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
// Add a subframe and navigate it.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe =
- contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
const GURL url2("http://foo/2");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -2150,8 +2209,9 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
params.page_state = PageState::CreateFromURL(url2);
// Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(url2, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(0U, notifications.size());
}
@@ -2178,10 +2238,10 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
// Add a second subframe and navigate.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName1", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe2 =
- contents()->GetFrameTree()->root()->child_at(1)->current_frame_host();
+ TestRenderFrameHost* subframe2 = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(1)->current_frame_host());
const GURL url3("http://foo/3");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -2196,8 +2256,9 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
params.page_state = PageState::CreateFromURL(url3);
// Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe2, params, &details));
+ subframe2->SendRendererInitiatedNavigationRequest(url3, false);
+ subframe2->PrepareForCommit();
+ subframe2->SendNavigateWithParams(&params);
EXPECT_EQ(0U, notifications.size());
}
@@ -2224,14 +2285,15 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
// Add a nested subframe and navigate.
subframe->OnCreateChildFrame(process()->GetNextRoutingID(),
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName2", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe3 = contents()
- ->GetFrameTree()
- ->root()
- ->child_at(0)
- ->child_at(0)
- ->current_frame_host();
+ TestRenderFrameHost* subframe3 =
+ static_cast<TestRenderFrameHost*>(contents()
+ ->GetFrameTree()
+ ->root()
+ ->child_at(0)
+ ->child_at(0)
+ ->current_frame_host());
const GURL url4("http://foo/4");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -2246,8 +2308,9 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
params.page_state = PageState::CreateFromURL(url4);
// Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe3, params, &details));
+ subframe3->SendRendererInitiatedNavigationRequest(url4, false);
+ subframe3->PrepareForCommit();
+ subframe3->SendNavigateWithParams(&params);
EXPECT_EQ(0U, notifications.size());
}
@@ -2289,10 +2352,10 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// Prereq: add a subframe with an initial auto-subframe navigation.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe =
- contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
const GURL subframe_url("http://foo1/subframe");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -2307,8 +2370,9 @@ TEST_F(NavigationControllerTest, BackSubframe) {
params.page_state = PageState::CreateFromURL(subframe_url);
// Navigating should do nothing.
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(subframe_url, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(0U, notifications.size());
}
@@ -2326,8 +2390,9 @@ TEST_F(NavigationControllerTest, BackSubframe) {
params.page_state = PageState::CreateFromURL(url2);
// This should generate a new entry.
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(url2, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -2351,7 +2416,9 @@ TEST_F(NavigationControllerTest, BackSubframe) {
params.url = url3;
params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
params.page_state = PageState::CreateFromURL(url3);
- EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(url3, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
@@ -2376,7 +2443,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
params.url = url2;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.page_state = PageState::CreateFromURL(url2);
- EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
@@ -2393,7 +2461,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
params.url = subframe_url;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.page_state = PageState::CreateFromURL(subframe_url);
- EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
@@ -2454,14 +2523,15 @@ TEST_F(NavigationControllerTest, InPage) {
self_params.page_state = PageState::CreateFromURL(url1);
self_params.was_within_same_page = true;
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), self_params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url1, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&self_params);
NavigationEntry* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
- EXPECT_TRUE(details.did_replace_entry);
+ EXPECT_TRUE(observer.details().is_in_page);
+ EXPECT_TRUE(observer.details().did_replace_entry);
EXPECT_EQ(1, controller.GetEntryCount());
// Fragment navigation to a new page_id.
@@ -2479,13 +2549,14 @@ TEST_F(NavigationControllerTest, InPage) {
params.was_within_same_page = true;
// This should generate a new entry.
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
NavigationEntry* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
- EXPECT_FALSE(details.did_replace_entry);
+ EXPECT_TRUE(observer.details().is_in_page);
+ EXPECT_FALSE(observer.details().did_replace_entry);
EXPECT_EQ(2, controller.GetEntryCount());
// Go back one.
@@ -2495,11 +2566,11 @@ TEST_F(NavigationControllerTest, InPage) {
back_params.page_id = 0;
back_params.nav_entry_id = entry1->GetUniqueID();
back_params.did_create_new_entry = false;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&back_params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
+ EXPECT_TRUE(observer.details().is_in_page);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
@@ -2511,11 +2582,11 @@ TEST_F(NavigationControllerTest, InPage) {
forward_params.page_id = 1;
forward_params.nav_entry_id = entry2->GetUniqueID();
forward_params.did_create_new_entry = false;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&forward_params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
+ EXPECT_TRUE(observer.details().is_in_page);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(forward_params.url,
@@ -2526,11 +2597,11 @@ TEST_F(NavigationControllerTest, InPage) {
// one identified by an existing page ID. This would result in the second URL
// losing the reference fragment when you navigate away from it and then back.
controller.GoBack();
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&back_params);
controller.GoForward();
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
- &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&forward_params);
EXPECT_EQ(forward_params.url,
controller.GetVisibleEntry()->GetURL());
@@ -2541,11 +2612,12 @@ TEST_F(NavigationControllerTest, InPage) {
params.did_create_new_entry = true;
params.url = url3;
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url3, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_FALSE(details.is_in_page);
+ EXPECT_FALSE(observer.details().is_in_page);
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
}
@@ -2576,13 +2648,14 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
params.was_within_same_page = true;
// This should NOT generate a new entry, nor prune the list.
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
- EXPECT_TRUE(details.did_replace_entry);
+ EXPECT_TRUE(observer.details().is_in_page);
+ EXPECT_TRUE(observer.details().did_replace_entry);
EXPECT_EQ(1, controller.GetEntryCount());
}
@@ -2630,13 +2703,14 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
params.was_within_same_page = true;
// This should NOT generate a new entry, nor prune the list.
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_TRUE(details.is_in_page);
- EXPECT_TRUE(details.did_replace_entry);
+ EXPECT_TRUE(observer.details().is_in_page);
+ EXPECT_TRUE(observer.details().did_replace_entry);
EXPECT_EQ(2, controller.GetEntryCount());
}
@@ -2657,12 +2731,13 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
params.page_state = PageState::CreateFromURL(url);
// This SHOULD generate a new entry.
- LoadCommittedDetails details;
- EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
- &details));
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- EXPECT_FALSE(details.is_in_page);
+ EXPECT_FALSE(observer.details().is_in_page);
EXPECT_EQ(3, controller.GetEntryCount());
}
@@ -2841,9 +2916,10 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
params.gesture = NavigationGestureUser;
params.is_post = false;
params.page_state = PageState::CreateFromURL(url);
- LoadCommittedDetails details;
- our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
- &details);
+ TestRenderFrameHost* main_rfh =
+ static_cast<TestRenderFrameHost*>(our_contents->GetMainFrame());
+ main_rfh->PrepareForCommit();
+ main_rfh->SendNavigateWithParams(&params);
// There should be no longer any pending entry and one committed one. This
// means that we were able to locate the entry, assign its site instance, and
@@ -2923,9 +2999,10 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
params.gesture = NavigationGestureUser;
params.is_post = false;
params.page_state = PageState::CreateFromURL(url);
- LoadCommittedDetails details;
- our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
- &details);
+ TestRenderFrameHost* main_rfh =
+ static_cast<TestRenderFrameHost*>(our_contents->GetMainFrame());
+ main_rfh->PrepareForCommit();
+ main_rfh->SendNavigateWithParams(&params);
// There should be no pending entry and one committed one.
EXPECT_EQ(1, our_controller.GetEntryCount());
@@ -3357,7 +3434,7 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
navigator->DidStartProvisionalLoad(main_test_rfh(), url2,
base::TimeTicks::Now());
EXPECT_TRUE(controller.GetPendingEntry()->should_replace_entry());
- main_test_rfh()->SendNavigate(0, 0, false, url2);
+ main_test_rfh()->SendNavigateWithReplacement(0, 0, false, url2);
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
}
@@ -3470,14 +3547,19 @@ TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
// Suppose it aborts before committing, if it's a 204 or download or due to a
// stop or a new navigation from the user. The URL should remain visible.
- FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
- params.error_code = net::ERR_ABORTED;
- params.error_description = base::string16();
- params.url = url;
- params.showing_repost_interstitial = false;
- main_test_rfh()->OnMessageReceived(
- FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
- contents()->SetIsLoading(false, true, NULL);
+ if (IsBrowserSideNavigationEnabled()) {
+ static_cast<NavigatorImpl*>(main_test_rfh()->frame_tree_node()->navigator())
+ ->CancelNavigation(main_test_rfh()->frame_tree_node());
+ } else {
+ FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
+ params.error_code = net::ERR_ABORTED;
+ params.error_description = base::string16();
+ params.url = url;
+ params.showing_repost_interstitial = false;
+ main_test_rfh()->OnMessageReceived(
+ FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
+ main_test_rfh()->OnMessageReceived(FrameHostMsg_DidStopLoading(0));
+ }
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
// If something else later modifies the contents of the about:blank page, then
@@ -3723,10 +3805,10 @@ TEST_F(NavigationControllerTest, SameSubframe) {
// Add and navigate a subframe that would normally count as in-page.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe =
- contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
const GURL subframe_url("http://www.google.com/#");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
@@ -3738,8 +3820,9 @@ TEST_F(NavigationControllerTest, SameSubframe) {
params.gesture = NavigationGestureAuto;
params.is_post = false;
params.page_state = PageState::CreateFromURL(subframe_url);
- LoadCommittedDetails details;
- EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(subframe_url, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
// Nothing should have changed.
EXPECT_EQ(controller.GetEntryCount(), 1);
@@ -3890,10 +3973,10 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
// automatically loaded. Auto subframes don't increment the page ID.
main_test_rfh()->OnCreateChildFrame(
process()->GetNextRoutingID(), blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
- RenderFrameHostImpl* subframe =
- contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
const GURL url1_sub("http://foo/subframe");
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = controller.GetLastCommittedEntry()->GetPageID();
@@ -3905,10 +3988,11 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
params.gesture = NavigationGestureAuto;
params.is_post = false;
params.page_state = PageState::CreateFromURL(url1_sub);
- LoadCommittedDetails details;
// This should return false meaning that nothing was actually updated.
- EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
+ subframe->SendRendererInitiatedNavigationRequest(url1_sub, false);
+ subframe->PrepareForCommit();
+ subframe->SendNavigateWithParams(&params);
// The notification should have updated the last committed one, and not
// the pending load.
@@ -4863,7 +4947,7 @@ TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
// The title should immediately be visible on the new NavigationEntry.
base::string16 new_title =
- controller().GetLastCommittedEntry()->GetTitleForDisplay(std::string());
+ controller().GetLastCommittedEntry()->GetTitleForDisplay();
EXPECT_EQ(title, new_title);
FaviconStatus new_favicon =
controller().GetLastCommittedEntry()->GetFavicon();
@@ -4967,6 +5051,8 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
TEST_F(NavigationControllerTest, UnreachableURLGivesErrorPage) {
GURL url("http://foo");
+ controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.nav_entry_id = 0;
@@ -4982,21 +5068,25 @@ TEST_F(NavigationControllerTest, UnreachableURLGivesErrorPage) {
// Navigate to new page.
{
- LoadCommittedDetails details;
- controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(PAGE_TYPE_ERROR,
controller_impl().GetLastCommittedEntry()->GetPageType());
- EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, details.type);
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, observer.details().type);
}
// Navigate to existing page.
{
params.did_create_new_entry = false;
- LoadCommittedDetails details;
- controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(url, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(PAGE_TYPE_ERROR,
controller_impl().GetLastCommittedEntry()->GetPageType());
- EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details.type);
+ EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, observer.details().type);
}
// Navigate to same page.
@@ -5007,11 +5097,12 @@ TEST_F(NavigationControllerTest, UnreachableURLGivesErrorPage) {
params.nav_entry_id = controller_impl().GetPendingEntry()->GetUniqueID();
params.transition = ui::PAGE_TRANSITION_TYPED;
{
- LoadCommittedDetails details;
- controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(PAGE_TYPE_ERROR,
controller_impl().GetLastCommittedEntry()->GetPageType());
- EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, details.type);
+ EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, observer.details().type);
}
// Navigate in page.
@@ -5019,11 +5110,13 @@ TEST_F(NavigationControllerTest, UnreachableURLGivesErrorPage) {
params.transition = ui::PAGE_TRANSITION_LINK;
params.was_within_same_page = true;
{
- LoadCommittedDetails details;
- controller_impl().RendererDidNavigate(main_test_rfh(), params, &details);
+ LoadCommittedDetailsObserver observer(contents());
+ main_test_rfh()->SendRendererInitiatedNavigationRequest(params.url, false);
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
EXPECT_EQ(PAGE_TYPE_ERROR,
controller_impl().GetLastCommittedEntry()->GetPageType());
- EXPECT_TRUE(details.is_in_page);
+ EXPECT_TRUE(observer.details().is_in_page);
}
}
@@ -5094,6 +5187,8 @@ TEST_F(NavigationControllerTest, StaleNavigationsResurrected) {
// killed.
TEST_F(NavigationControllerTest, RendererNavigateBogusSecurityInfo) {
GURL url("http://foo.test");
+ controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.nav_entry_id = 0;
@@ -5107,22 +5202,26 @@ TEST_F(NavigationControllerTest, RendererNavigateBogusSecurityInfo) {
params.was_within_same_page = false;
params.security_info = "bogus security info!";
- LoadCommittedDetails details;
+ LoadCommittedDetailsObserver observer(contents());
EXPECT_EQ(0, main_test_rfh()->GetProcess()->bad_msg_count());
- EXPECT_TRUE(
- controller_impl().RendererDidNavigate(main_test_rfh(), params, &details));
+ main_test_rfh()->PrepareForCommit();
+ main_test_rfh()->SendNavigateWithParams(&params);
SSLStatus default_ssl_status;
EXPECT_EQ(default_ssl_status.security_style,
- details.ssl_status.security_style);
- EXPECT_EQ(default_ssl_status.cert_id, details.ssl_status.cert_id);
- EXPECT_EQ(default_ssl_status.cert_status, details.ssl_status.cert_status);
- EXPECT_EQ(default_ssl_status.security_bits, details.ssl_status.security_bits);
+ observer.details().ssl_status.security_style);
+ EXPECT_EQ(default_ssl_status.cert_id, observer.details().ssl_status.cert_id);
+ EXPECT_EQ(default_ssl_status.cert_status,
+ observer.details().ssl_status.cert_status);
+ EXPECT_EQ(default_ssl_status.security_bits,
+ observer.details().ssl_status.security_bits);
EXPECT_EQ(default_ssl_status.connection_status,
- details.ssl_status.connection_status);
+ observer.details().ssl_status.connection_status);
EXPECT_EQ(default_ssl_status.content_status,
- details.ssl_status.content_status);
- EXPECT_EQ(0u, details.ssl_status.signed_certificate_timestamp_ids.size());
+ observer.details().ssl_status.content_status);
+ EXPECT_EQ(
+ 0u,
+ observer.details().ssl_status.signed_certificate_timestamp_ids.size());
EXPECT_EQ(1, main_test_rfh()->GetProcess()->bad_msg_count());
}
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.cc b/chromium/content/browser/frame_host/navigation_entry_impl.cc
index 258429a90b1..ecf43c456e6 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <queue>
+#include <utility>
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
@@ -156,15 +157,21 @@ NavigationEntryImpl::NavigationEntryImpl()
ui::PAGE_TRANSITION_LINK, false) {
}
-NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
- int page_id,
- const GURL& url,
- const Referrer& referrer,
- const base::string16& title,
- ui::PageTransition transition_type,
- bool is_renderer_initiated)
- : frame_tree_(new TreeNode(
- new FrameNavigationEntry(-1, "", -1, -1, instance, url, referrer))),
+NavigationEntryImpl::NavigationEntryImpl(
+ scoped_refptr<SiteInstanceImpl> instance,
+ int page_id,
+ const GURL& url,
+ const Referrer& referrer,
+ const base::string16& title,
+ ui::PageTransition transition_type,
+ bool is_renderer_initiated)
+ : frame_tree_(new TreeNode(new FrameNavigationEntry(-1,
+ "",
+ -1,
+ -1,
+ std::move(instance),
+ url,
+ referrer))),
unique_id_(GetUniqueIDInConstructor()),
bindings_(kInvalidBindings),
page_type_(PAGE_TYPE_NORMAL),
@@ -264,9 +271,17 @@ void NavigationEntryImpl::SetPageState(const PageState& state) {
return;
}
- // This should only be called when restoring a NavigationEntry, so there
- // should be no subframe FrameNavigationEntries yet.
- DCHECK_EQ(0U, frame_tree_->children.size());
+ // SetPageState should only be called before the NavigationEntry has been
+ // loaded, such as for restore (when there are no subframe
+ // FrameNavigationEntries yet). However, some callers expect to call this
+ // after a Clone but before loading the page. Clone will copy over the
+ // subframe entries, and we should reset them before setting the state again.
+ //
+ // TODO(creis): It would be good to verify that this NavigationEntry hasn't
+ // been loaded yet in cases that SetPageState is called while subframe
+ // entries exist, but there's currently no way to check that.
+ if (!frame_tree_->children.empty())
+ frame_tree_->children.clear();
// If the PageState can't be parsed or has no children, just store it on the
// main frame's FrameNavigationEntry without recursively creating subframe
@@ -310,9 +325,10 @@ int32_t NavigationEntryImpl::GetPageID() const {
return page_id_;
}
-void NavigationEntryImpl::set_site_instance(SiteInstanceImpl* site_instance) {
+void NavigationEntryImpl::set_site_instance(
+ scoped_refptr<SiteInstanceImpl> site_instance) {
// TODO(creis): Update all callers and remove this method.
- frame_tree_->frame_entry->set_site_instance(site_instance);
+ frame_tree_->frame_entry->set_site_instance(std::move(site_instance));
}
void NavigationEntryImpl::set_source_site_instance(
@@ -327,8 +343,7 @@ void NavigationEntryImpl::SetBindings(int bindings) {
bindings_ = bindings;
}
-const base::string16& NavigationEntryImpl::GetTitleForDisplay(
- const std::string& languages) const {
+const base::string16& NavigationEntryImpl::GetTitleForDisplay() const {
// Most pages have real titles. Don't even bother caching anything if this is
// the case.
if (!title_.empty())
@@ -342,9 +357,9 @@ const base::string16& NavigationEntryImpl::GetTitleForDisplay(
// Use the virtual URL first if any, and fall back on using the real URL.
base::string16 title;
if (!virtual_url_.is_empty()) {
- title = url_formatter::FormatUrl(virtual_url_, languages);
+ title = url_formatter::FormatUrl(virtual_url_);
} else if (!GetURL().is_empty()) {
- title = url_formatter::FormatUrl(GetURL(), languages);
+ title = url_formatter::FormatUrl(GetURL());
}
// For file:// URLs use the filename as the title, not the full path.
@@ -576,7 +591,7 @@ CommonNavigationParams NavigationEntryImpl::ConstructCommonNavigationParams(
dest_url, dest_referrer, GetTransitionType(), navigation_type,
!IsViewSourceMode(), should_replace_entry(), ui_timestamp, report_type,
GetBaseURLForDataURL(), GetHistoryURLForDataURL(), lofi_state,
- navigation_start);
+ navigation_start, GetHasPostData() ? "POST" : "GET");
}
StartNavigationParams NavigationEntryImpl::ConstructStartNavigationParams()
@@ -589,8 +604,7 @@ StartNavigationParams NavigationEntryImpl::ConstructStartNavigationParams()
GetBrowserInitiatedPostData()->size());
}
- return StartNavigationParams(GetHasPostData(), extra_headers(),
- browser_initiated_post_data,
+ return StartNavigationParams(extra_headers(), browser_initiated_post_data,
#if defined(OS_ANDROID)
has_user_gesture(),
#endif
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.h b/chromium/content/browser/frame_host/navigation_entry_impl.h
index ac5a3f2f593..ff840331a1f 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.h
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.h
@@ -69,7 +69,7 @@ class CONTENT_EXPORT NavigationEntryImpl
static int kInvalidBindings;
NavigationEntryImpl();
- NavigationEntryImpl(SiteInstanceImpl* instance,
+ NavigationEntryImpl(scoped_refptr<SiteInstanceImpl> instance,
int page_id,
const GURL& url,
const Referrer& referrer,
@@ -101,8 +101,7 @@ class CONTENT_EXPORT NavigationEntryImpl
PageState GetPageState() const override;
void SetPageID(int page_id) override;
int32_t GetPageID() const override;
- const base::string16& GetTitleForDisplay(
- const std::string& languages) const override;
+ const base::string16& GetTitleForDisplay() const override;
bool IsViewSourceMode() const override;
void SetTransitionType(ui::PageTransition transition_type) override;
ui::PageTransition GetTransitionType() const override;
@@ -219,7 +218,7 @@ class CONTENT_EXPORT NavigationEntryImpl
// Note that the SiteInstance should usually not be changed after it is set,
// but this may happen if the NavigationEntry was cloned and needs to use a
// different SiteInstance.
- void set_site_instance(SiteInstanceImpl* site_instance);
+ void set_site_instance(scoped_refptr<SiteInstanceImpl> site_instance);
SiteInstanceImpl* site_instance() const {
return frame_tree_->frame_entry->site_instance();
}
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc b/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
index 7319b5347c6..ccea60b0158 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -24,9 +24,7 @@ class NavigationEntryTest : public testing::Test {
void SetUp() override {
entry1_.reset(new NavigationEntryImpl);
-#if !defined(OS_IOS)
- instance_ = static_cast<SiteInstanceImpl*>(SiteInstance::Create(NULL));
-#endif
+ instance_ = SiteInstanceImpl::Create(NULL);
entry2_.reset(new NavigationEntryImpl(
instance_, 3,
GURL("test:url"),
@@ -42,7 +40,7 @@ class NavigationEntryTest : public testing::Test {
scoped_ptr<NavigationEntryImpl> entry1_;
scoped_ptr<NavigationEntryImpl> entry2_;
// SiteInstances are deleted when their NavigationEntries are gone.
- SiteInstanceImpl* instance_;
+ scoped_refptr<SiteInstanceImpl> instance_;
};
// Test unique ID accessors
@@ -63,44 +61,42 @@ TEST_F(NavigationEntryTest, NavigationEntryURLs) {
EXPECT_EQ(GURL(), entry1_->GetURL());
EXPECT_EQ(GURL(), entry1_->GetVirtualURL());
- EXPECT_TRUE(entry1_->GetTitleForDisplay(std::string()).empty());
+ EXPECT_TRUE(entry1_->GetTitleForDisplay().empty());
// Setting URL affects virtual_url and GetTitleForDisplay
entry1_->SetURL(GURL("http://www.google.com"));
EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetURL());
EXPECT_EQ(GURL("http://www.google.com"), entry1_->GetVirtualURL());
EXPECT_EQ(ASCIIToUTF16("www.google.com"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
// file:/// URLs should only show the filename.
entry1_->SetURL(GURL("file:///foo/bar baz.txt"));
- EXPECT_EQ(ASCIIToUTF16("bar baz.txt"),
- entry1_->GetTitleForDisplay(std::string()));
+ EXPECT_EQ(ASCIIToUTF16("bar baz.txt"), entry1_->GetTitleForDisplay());
// For file:/// URLs, make sure that slashes after the filename are ignored.
// Regression test for https://crbug.com/503003.
entry1_->SetURL(GURL("file:///foo/bar baz.txt#foo/bar"));
- EXPECT_EQ(ASCIIToUTF16("bar baz.txt#foo/bar"),
- entry1_->GetTitleForDisplay(std::string()));
+ EXPECT_EQ(ASCIIToUTF16("bar baz.txt#foo/bar"), entry1_->GetTitleForDisplay());
entry1_->SetURL(GURL("file:///foo/bar baz.txt?x=foo/bar"));
EXPECT_EQ(ASCIIToUTF16("bar baz.txt?x=foo/bar"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
entry1_->SetURL(GURL("file:///foo/bar baz.txt#baz/boo?x=foo/bar"));
EXPECT_EQ(ASCIIToUTF16("bar baz.txt#baz/boo?x=foo/bar"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
entry1_->SetURL(GURL("file:///foo/bar baz.txt?x=foo/bar#baz/boo"));
EXPECT_EQ(ASCIIToUTF16("bar baz.txt?x=foo/bar#baz/boo"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
entry1_->SetURL(GURL("file:///foo/bar baz.txt#foo/bar#baz/boo"));
EXPECT_EQ(ASCIIToUTF16("bar baz.txt#foo/bar#baz/boo"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
entry1_->SetURL(GURL("file:///foo/bar baz.txt?x=foo/bar?y=baz/boo"));
EXPECT_EQ(ASCIIToUTF16("bar baz.txt?x=foo/bar?y=baz/boo"),
- entry1_->GetTitleForDisplay(std::string()));
+ entry1_->GetTitleForDisplay());
// Title affects GetTitleForDisplay
entry1_->SetTitle(ASCIIToUTF16("Google"));
- EXPECT_EQ(ASCIIToUTF16("Google"), entry1_->GetTitleForDisplay(std::string()));
+ EXPECT_EQ(ASCIIToUTF16("Google"), entry1_->GetTitleForDisplay());
// Setting virtual_url doesn't affect URL
entry2_->SetVirtualURL(GURL("display:url"));
@@ -109,7 +105,7 @@ TEST_F(NavigationEntryTest, NavigationEntryURLs) {
EXPECT_EQ(GURL("display:url"), entry2_->GetVirtualURL());
// Having a title set in constructor overrides virtual URL
- EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitleForDisplay(std::string()));
+ EXPECT_EQ(ASCIIToUTF16("title"), entry2_->GetTitleForDisplay());
// User typed URL is independent of the others
EXPECT_EQ(GURL(), entry1_->GetUserTypedURL());
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.cc b/chromium/content/browser/frame_host/navigation_handle_impl.cc
index a8d32e911e2..dde5fa77087 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_handle_impl.cc
@@ -11,6 +11,7 @@
#include "content/browser/frame_host/navigator_delegate.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_navigation_handle.h"
+#include "content/common/frame_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_client.h"
@@ -32,15 +33,22 @@ void UpdateThrottleCheckResult(
scoped_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
const GURL& url,
FrameTreeNode* frame_tree_node,
- const base::TimeTicks& navigation_start) {
+ bool is_synchronous,
+ bool is_srcdoc,
+ const base::TimeTicks& navigation_start,
+ int pending_nav_entry_id) {
return scoped_ptr<NavigationHandleImpl>(
- new NavigationHandleImpl(url, frame_tree_node, navigation_start));
+ new NavigationHandleImpl(url, frame_tree_node, is_synchronous, is_srcdoc,
+ navigation_start, pending_nav_entry_id));
}
NavigationHandleImpl::NavigationHandleImpl(
const GURL& url,
FrameTreeNode* frame_tree_node,
- const base::TimeTicks& navigation_start)
+ bool is_synchronous,
+ bool is_srcdoc,
+ const base::TimeTicks& navigation_start,
+ int pending_nav_entry_id)
: url_(url),
is_post_(false),
has_user_gesture_(false),
@@ -49,11 +57,15 @@ NavigationHandleImpl::NavigationHandleImpl(
net_error_code_(net::OK),
render_frame_host_(nullptr),
is_same_page_(false),
+ is_synchronous_(is_synchronous),
+ is_srcdoc_(is_srcdoc),
+ was_redirected_(false),
state_(INITIAL),
is_transferring_(false),
frame_tree_node_(frame_tree_node),
next_index_(0),
- navigation_start_(navigation_start) {
+ navigation_start_(navigation_start),
+ pending_nav_entry_id_(pending_nav_entry_id) {
DCHECK(!navigation_start.is_null());
GetDelegate()->DidStartNavigation(this);
}
@@ -79,6 +91,36 @@ bool NavigationHandleImpl::IsInMainFrame() {
return frame_tree_node_->IsMainFrame();
}
+bool NavigationHandleImpl::IsParentMainFrame() {
+ if (frame_tree_node_->parent())
+ return frame_tree_node_->parent()->IsMainFrame();
+
+ return false;
+}
+
+bool NavigationHandleImpl::IsSynchronousNavigation() {
+ return is_synchronous_;
+}
+
+bool NavigationHandleImpl::IsSrcdoc() {
+ return is_srcdoc_;
+}
+
+bool NavigationHandleImpl::WasServerRedirect() {
+ return was_redirected_;
+}
+
+int NavigationHandleImpl::GetFrameTreeNodeId() {
+ return frame_tree_node_->frame_tree_node_id();
+}
+
+int NavigationHandleImpl::GetParentFrameTreeNodeId() {
+ if (frame_tree_node_->IsMainFrame())
+ return FrameTreeNode::kFrameTreeNodeInvalidId;
+
+ return frame_tree_node_->parent()->frame_tree_node_id();
+}
+
const base::TimeTicks& NavigationHandleImpl::NavigationStart() {
return navigation_start_;
}
@@ -132,9 +174,6 @@ bool NavigationHandleImpl::IsSamePage() {
}
const net::HttpResponseHeaders* NavigationHandleImpl::GetResponseHeaders() {
- DCHECK(state_ >= WILL_REDIRECT_REQUEST)
- << "This accessor should only be called when the request encountered a "
- "redirect or received a response";
return response_headers_.get();
}
@@ -147,14 +186,23 @@ bool NavigationHandleImpl::IsErrorPage() {
}
void NavigationHandleImpl::Resume() {
- if (state_ != DEFERRING_START && state_ != DEFERRING_REDIRECT)
+ if (state_ != DEFERRING_START && state_ != DEFERRING_REDIRECT &&
+ state_ != DEFERRING_RESPONSE) {
return;
+ }
NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
if (state_ == DEFERRING_START) {
result = CheckWillStartRequest();
- } else {
+ } else if (state_ == DEFERRING_REDIRECT) {
result = CheckWillRedirectRequest();
+ } else {
+ result = CheckWillProcessResponse();
+
+ // If the navigation is about to proceed after processing the response, then
+ // it's ready to commit.
+ if (result == NavigationThrottle::PROCEED)
+ ReadyToCommitNavigation(render_frame_host_);
}
if (result != NavigationThrottle::DEFER)
@@ -267,6 +315,7 @@ void NavigationHandleImpl::WillRedirectRequest(
sanitized_referrer_ = Referrer::SanitizeForRequest(url_, sanitized_referrer_);
is_external_protocol_ = new_is_external_protocol;
response_headers_ = response_headers;
+ was_redirected_ = true;
state_ = WILL_REDIRECT_REQUEST;
complete_callback_ = callback;
@@ -279,17 +328,32 @@ void NavigationHandleImpl::WillRedirectRequest(
RunCompleteCallback(result);
}
-void NavigationHandleImpl::DidRedirectNavigation(const GURL& new_url) {
- url_ = new_url;
- GetDelegate()->DidRedirectNavigation(this);
+void NavigationHandleImpl::WillProcessResponse(
+ RenderFrameHostImpl* render_frame_host,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ const ThrottleChecksFinishedCallback& callback) {
+ DCHECK(!render_frame_host_ || render_frame_host_ == render_frame_host);
+ render_frame_host_ = render_frame_host;
+ response_headers_ = response_headers;
+ state_ = WILL_PROCESS_RESPONSE;
+ complete_callback_ = callback;
+
+ // Notify each throttle of the response.
+ NavigationThrottle::ThrottleCheckResult result = CheckWillProcessResponse();
+
+ // If the navigation is about to proceed, then it's ready to commit.
+ if (result == NavigationThrottle::PROCEED)
+ ReadyToCommitNavigation(render_frame_host);
+
+ // If the navigation is not deferred, run the callback.
+ if (result != NavigationThrottle::DEFER)
+ RunCompleteCallback(result);
}
void NavigationHandleImpl::ReadyToCommitNavigation(
- RenderFrameHostImpl* render_frame_host,
- scoped_refptr<net::HttpResponseHeaders> response_headers) {
+ RenderFrameHostImpl* render_frame_host) {
DCHECK(!render_frame_host_ || render_frame_host_ == render_frame_host);
render_frame_host_ = render_frame_host;
- response_headers_ = response_headers;
state_ = READY_TO_COMMIT;
// Only notify the WebContentsObservers when PlzNavigate is enabled, as
@@ -299,11 +363,19 @@ void NavigationHandleImpl::ReadyToCommitNavigation(
}
void NavigationHandleImpl::DidCommitNavigation(
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool same_page,
RenderFrameHostImpl* render_frame_host) {
DCHECK(!render_frame_host_ || render_frame_host_ == render_frame_host);
- is_same_page_ = same_page;
+ DCHECK_EQ(frame_tree_node_, render_frame_host->frame_tree_node());
+ CHECK_EQ(url_, params.url);
+
+ is_post_ = params.is_post;
+ has_user_gesture_ = (params.gesture == NavigationGestureUser);
+ transition_ = params.transition;
render_frame_host_ = render_frame_host;
+ is_same_page_ = same_page;
+
state_ = net_error_code_ == net::OK ? DID_COMMIT : DID_COMMIT_ERROR_PAGE;
}
@@ -366,16 +438,54 @@ NavigationHandleImpl::CheckWillRedirectRequest() {
}
next_index_ = 0;
state_ = WILL_REDIRECT_REQUEST;
+
+ // Notify the delegate that a redirect was encountered and will be followed.
+ if (GetDelegate())
+ GetDelegate()->DidRedirectNavigation(this);
+
+ return NavigationThrottle::PROCEED;
+}
+
+NavigationThrottle::ThrottleCheckResult
+NavigationHandleImpl::CheckWillProcessResponse() {
+ DCHECK(state_ == WILL_PROCESS_RESPONSE || state_ == DEFERRING_RESPONSE);
+ DCHECK(state_ != WILL_PROCESS_RESPONSE || next_index_ == 0);
+ DCHECK(state_ != DEFERRING_RESPONSE || next_index_ != 0);
+ for (size_t i = next_index_; i < throttles_.size(); ++i) {
+ NavigationThrottle::ThrottleCheckResult result =
+ throttles_[i]->WillProcessResponse();
+ switch (result) {
+ case NavigationThrottle::PROCEED:
+ continue;
+
+ case NavigationThrottle::CANCEL:
+ case NavigationThrottle::CANCEL_AND_IGNORE:
+ state_ = CANCELING;
+ return result;
+
+ case NavigationThrottle::DEFER:
+ state_ = DEFERRING_RESPONSE;
+ next_index_ = i + 1;
+ return result;
+ }
+ }
+ next_index_ = 0;
+ state_ = WILL_PROCESS_RESPONSE;
return NavigationThrottle::PROCEED;
}
void NavigationHandleImpl::RunCompleteCallback(
NavigationThrottle::ThrottleCheckResult result) {
DCHECK(result != NavigationThrottle::DEFER);
- if (!complete_callback_.is_null())
- complete_callback_.Run(result);
+ ThrottleChecksFinishedCallback callback = complete_callback_;
complete_callback_.Reset();
+
+ if (!callback.is_null())
+ callback.Run(result);
+
+ // No code after running the callback, as it might have resulted in our
+ // destruction.
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.h b/chromium/content/browser/frame_host/navigation_handle_impl.h
index 192cdab3348..252a2e03d39 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl.h
+++ b/chromium/content/browser/frame_host/navigation_handle_impl.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
@@ -19,6 +18,8 @@
#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"
+struct FrameHostMsg_DidCommitProvisionalLoad_Params;
+
namespace content {
class NavigatorDelegate;
@@ -68,12 +69,21 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
static scoped_ptr<NavigationHandleImpl> Create(
const GURL& url,
FrameTreeNode* frame_tree_node,
- const base::TimeTicks& navigation_start);
+ bool is_synchronous,
+ bool is_srcdoc,
+ const base::TimeTicks& navigation_start,
+ int pending_nav_entry_id);
~NavigationHandleImpl() override;
// NavigationHandle implementation:
const GURL& GetURL() override;
bool IsInMainFrame() override;
+ bool IsParentMainFrame() override;
+ bool IsSynchronousNavigation() override;
+ bool IsSrcdoc() override;
+ bool WasServerRedirect() override;
+ int GetFrameTreeNodeId() override;
+ int GetParentFrameTreeNodeId() override;
const base::TimeTicks& NavigationStart() override;
bool IsPost() override;
const Referrer& GetReferrer() override;
@@ -104,12 +114,25 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
NavigatorDelegate* GetDelegate() const;
- // Returns the response headers for the request. This can only be accessed
- // after a redirect was encountered or after the the navigation is ready to
- // commit. It should not be modified, as modifications will not be reflected
- // in the network stack.
+ // Returns the response headers for the request or nullptr if there are none.
+ // This should only be accessed after a redirect was encountered or after the
+ // navigation is ready to commit. The headers returned should not be modified,
+ // as modifications will not be reflected in the network stack.
const net::HttpResponseHeaders* GetResponseHeaders();
+ // Get the unique id from the NavigationEntry associated with this
+ // NavigationHandle. Note that a synchronous, renderer-initiated navigation
+ // will not have a NavigationEntry associated with it, and this will return 0.
+ int pending_nav_entry_id() const { return pending_nav_entry_id_; }
+
+ // Changes the pending NavigationEntry ID for this handle. This is currently
+ // required during transfer navigations.
+ // TODO(creis): Remove this when transfer navigations do not require pending
+ // entries. See https://crbug.com/495161.
+ void update_entry_id_for_transfer(int nav_entry_id) {
+ pending_nav_entry_id_ = nav_entry_id;
+ }
+
void set_net_error_code(net::Error net_error_code) {
net_error_code_ = net_error_code;
}
@@ -152,6 +175,7 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// Called when the URLRequest will be redirected in the network stack.
// |callback| will be called when all throttles check have completed. This
// will allow the caller to cancel the navigation or let it proceed.
+ // This will also inform the delegate that the request was redirected.
void WillRedirectRequest(
const GURL& new_url,
bool new_method_is_post,
@@ -160,24 +184,32 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
scoped_refptr<net::HttpResponseHeaders> response_headers,
const ThrottleChecksFinishedCallback& callback);
+ // Called when the URLRequest has delivered response headers and metadata.
+ // |callback| will be called when all throttle checks have completed,
+ // allowing the caller to cancel the navigation or let it proceed.
+ // NavigationHandle will not call |callback| with a result of DEFER.
+ // If the result is PROCEED, then 'ReadyToCommitNavigation' will be called
+ // with |render_frame_host| and |response_headers| just before calling
+ // |callback|.
+ void WillProcessResponse(
+ RenderFrameHostImpl* render_frame_host,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ const ThrottleChecksFinishedCallback& callback);
+
// Returns the FrameTreeNode this navigation is happening in.
FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
- // Called when the navigation was redirected. This will update the |url_| and
- // inform the delegate.
- void DidRedirectNavigation(const GURL& new_url);
-
// Called when the navigation is ready to be committed in
// |render_frame_host|. This will update the |state_| and inform the
// delegate.
- void ReadyToCommitNavigation(
- RenderFrameHostImpl* render_frame_host,
- scoped_refptr<net::HttpResponseHeaders> response_headers);
+ void ReadyToCommitNavigation(RenderFrameHostImpl* render_frame_host);
// Called when the navigation was committed in |render_frame_host|. This will
// update the |state_|.
- void DidCommitNavigation(bool same_page,
- RenderFrameHostImpl* render_frame_host);
+ void DidCommitNavigation(
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
+ bool same_page,
+ RenderFrameHostImpl* render_frame_host);
private:
friend class NavigationHandleImplTest;
@@ -190,6 +222,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
WILL_REDIRECT_REQUEST,
DEFERRING_REDIRECT,
CANCELING,
+ WILL_PROCESS_RESPONSE,
+ DEFERRING_RESPONSE,
READY_TO_COMMIT,
DID_COMMIT,
DID_COMMIT_ERROR_PAGE,
@@ -197,10 +231,14 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
NavigationHandleImpl(const GURL& url,
FrameTreeNode* frame_tree_node,
- const base::TimeTicks& navigation_start);
+ bool is_synchronous,
+ bool is_srcdoc,
+ const base::TimeTicks& navigation_start,
+ int pending_nav_entry_id);
NavigationThrottle::ThrottleCheckResult CheckWillStartRequest();
NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
+ NavigationThrottle::ThrottleCheckResult CheckWillProcessResponse();
// Helper function to run and reset the |complete_callback_|. This marks the
// end of a round of NavigationThrottleChecks.
@@ -219,6 +257,9 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
net::Error net_error_code_;
RenderFrameHostImpl* render_frame_host_;
bool is_same_page_;
+ const bool is_synchronous_;
+ const bool is_srcdoc_;
+ bool was_redirected_;
scoped_refptr<net::HttpResponseHeaders> response_headers_;
// The state the navigation is in.
@@ -240,6 +281,9 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// The time this navigation started.
const base::TimeTicks navigation_start_;
+ // The unique id of the corresponding NavigationEntry.
+ int pending_nav_entry_id_;
+
// This callback will be run when all throttle checks have been performed.
ThrottleChecksFinishedCallback complete_callback_;
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc
new file mode 100644
index 00000000000..7630a743531
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc
@@ -0,0 +1,560 @@
+// 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 "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.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 "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/dns/mock_host_resolver.h"
+#include "ui/base/page_transition_types.h"
+#include "url/url_constants.h"
+
+namespace content {
+
+namespace {
+
+class NavigationHandleObserver : public WebContentsObserver {
+ public:
+ NavigationHandleObserver(WebContents* web_contents, const GURL& expected_url)
+ : WebContentsObserver(web_contents),
+ handle_(nullptr),
+ has_committed_(false),
+ is_error_(false),
+ is_main_frame_(false),
+ is_parent_main_frame_(false),
+ is_synchronous_(false),
+ is_srcdoc_(false),
+ was_redirected_(false),
+ frame_tree_node_id_(-1),
+ page_transition_(ui::PAGE_TRANSITION_LINK),
+ expected_url_(expected_url) {}
+
+ void DidStartNavigation(NavigationHandle* navigation_handle) override {
+ if (handle_ || navigation_handle->GetURL() != expected_url_)
+ return;
+
+ handle_ = navigation_handle;
+ has_committed_ = false;
+ is_error_ = false;
+ page_transition_ = ui::PAGE_TRANSITION_LINK;
+ last_committed_url_ = GURL();
+
+ is_main_frame_ = navigation_handle->IsInMainFrame();
+ is_parent_main_frame_ = navigation_handle->IsParentMainFrame();
+ is_synchronous_ = navigation_handle->IsSynchronousNavigation();
+ is_srcdoc_ = navigation_handle->IsSrcdoc();
+ was_redirected_ = navigation_handle->WasServerRedirect();
+ frame_tree_node_id_ = navigation_handle->GetFrameTreeNodeId();
+ }
+
+ void DidFinishNavigation(NavigationHandle* navigation_handle) override {
+ if (navigation_handle != handle_)
+ return;
+
+ DCHECK_EQ(is_main_frame_, navigation_handle->IsInMainFrame());
+ DCHECK_EQ(is_parent_main_frame_, navigation_handle->IsParentMainFrame());
+ DCHECK_EQ(is_synchronous_, navigation_handle->IsSynchronousNavigation());
+ DCHECK_EQ(is_srcdoc_, navigation_handle->IsSrcdoc());
+ DCHECK_EQ(frame_tree_node_id_, navigation_handle->GetFrameTreeNodeId());
+
+ was_redirected_ = navigation_handle->WasServerRedirect();
+
+ if (navigation_handle->HasCommitted()) {
+ has_committed_ = true;
+ if (!navigation_handle->IsErrorPage()) {
+ page_transition_ = navigation_handle->GetPageTransition();
+ last_committed_url_ = navigation_handle->GetURL();
+ } else {
+ is_error_ = true;
+ }
+ } else {
+ has_committed_ = false;
+ is_error_ = true;
+ }
+
+ handle_ = nullptr;
+ }
+
+ bool has_committed() { return has_committed_; }
+ bool is_error() { return is_error_; }
+ bool is_main_frame() { return is_main_frame_; }
+ bool is_parent_main_frame() { return is_parent_main_frame_; }
+ bool is_synchronous() { return is_synchronous_; }
+ bool is_srcdoc() { return is_srcdoc_; }
+ bool was_redirected() { return was_redirected_; }
+ int frame_tree_node_id() { return frame_tree_node_id_; }
+
+ const GURL& last_committed_url() { return last_committed_url_; }
+
+ ui::PageTransition page_transition() { return page_transition_; }
+
+ private:
+ // A reference to the NavigationHandle so this class will track only
+ // one navigation at a time. It is set at DidStartNavigation and cleared
+ // at DidFinishNavigation before the NavigationHandle is destroyed.
+ NavigationHandle* handle_;
+ bool has_committed_;
+ bool is_error_;
+ bool is_main_frame_;
+ bool is_parent_main_frame_;
+ bool is_synchronous_;
+ bool is_srcdoc_;
+ bool was_redirected_;
+ int frame_tree_node_id_;
+ ui::PageTransition page_transition_;
+ GURL expected_url_;
+ GURL last_committed_url_;
+};
+
+// A test NavigationThrottle that will return pre-determined checks and run
+// callbacks when the various NavigationThrottle methods are called.
+class TestNavigationThrottle : public NavigationThrottle {
+ public:
+ TestNavigationThrottle(
+ NavigationHandle* handle,
+ NavigationThrottle::ThrottleCheckResult will_start_result,
+ NavigationThrottle::ThrottleCheckResult will_redirect_result,
+ NavigationThrottle::ThrottleCheckResult will_process_result,
+ base::Closure did_call_will_start,
+ base::Closure did_call_will_redirect,
+ base::Closure did_call_will_process)
+ : NavigationThrottle(handle),
+ will_start_result_(will_start_result),
+ will_redirect_result_(will_redirect_result),
+ will_process_result_(will_process_result),
+ did_call_will_start_(did_call_will_start),
+ did_call_will_redirect_(did_call_will_redirect),
+ did_call_will_process_(did_call_will_process) {}
+ ~TestNavigationThrottle() override {}
+
+ void Resume() { navigation_handle()->Resume(); }
+
+ private:
+ // NavigationThrottle implementation.
+ NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, did_call_will_start_);
+ return will_start_result_;
+ }
+
+ NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ did_call_will_redirect_);
+ return will_redirect_result_;
+ }
+
+ NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ did_call_will_process_);
+ return will_process_result_;
+ }
+
+ NavigationThrottle::ThrottleCheckResult will_start_result_;
+ NavigationThrottle::ThrottleCheckResult will_redirect_result_;
+ NavigationThrottle::ThrottleCheckResult will_process_result_;
+ base::Closure did_call_will_start_;
+ base::Closure did_call_will_redirect_;
+ base::Closure did_call_will_process_;
+};
+
+// Install a TestNavigationThrottle on all requests and allows waiting for
+// various NavigationThrottle related events.
+class TestNavigationThrottleInstaller : public WebContentsObserver {
+ public:
+ TestNavigationThrottleInstaller(
+ WebContents* web_contents,
+ NavigationThrottle::ThrottleCheckResult will_start_result,
+ NavigationThrottle::ThrottleCheckResult will_redirect_result,
+ NavigationThrottle::ThrottleCheckResult will_process_result)
+ : WebContentsObserver(web_contents),
+ will_start_result_(will_start_result),
+ will_redirect_result_(will_redirect_result),
+ will_process_result_(will_process_result),
+ will_start_called_(0),
+ will_redirect_called_(0),
+ will_process_called_(0),
+ navigation_throttle_(nullptr) {}
+ ~TestNavigationThrottleInstaller() override{};
+
+ TestNavigationThrottle* navigation_throttle() { return navigation_throttle_; }
+
+ void WaitForThrottleWillStart() {
+ if (will_start_called_)
+ return;
+ will_start_loop_runner_ = new MessageLoopRunner();
+ will_start_loop_runner_->Run();
+ will_start_loop_runner_ = nullptr;
+ }
+
+ void WaitForThrottleWillRedirect() {
+ if (will_redirect_called_)
+ return;
+ will_redirect_loop_runner_ = new MessageLoopRunner();
+ will_redirect_loop_runner_->Run();
+ will_redirect_loop_runner_ = nullptr;
+ }
+
+ void WaitForThrottleWillProcess() {
+ if (will_process_called_)
+ return;
+ will_process_loop_runner_ = new MessageLoopRunner();
+ will_process_loop_runner_->Run();
+ will_process_loop_runner_ = nullptr;
+ }
+
+ int will_start_called() { return will_start_called_; }
+ int will_redirect_called() { return will_redirect_called_; }
+ int will_process_called() { return will_process_called_; }
+
+ private:
+ void DidStartNavigation(NavigationHandle* handle) override {
+ scoped_ptr<NavigationThrottle> throttle(new TestNavigationThrottle(
+ handle, will_start_result_, will_redirect_result_, will_process_result_,
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillStartRequest,
+ base::Unretained(this)),
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillRedirectRequest,
+ base::Unretained(this)),
+ base::Bind(&TestNavigationThrottleInstaller::DidCallWillProcessResponse,
+ base::Unretained(this))));
+ navigation_throttle_ = static_cast<TestNavigationThrottle*>(throttle.get());
+ handle->RegisterThrottleForTesting(std::move(throttle));
+ }
+
+ void DidFinishNavigation(NavigationHandle* handle) override {
+ if (!navigation_throttle_)
+ return;
+
+ if (handle == navigation_throttle_->navigation_handle())
+ navigation_throttle_ = nullptr;
+ }
+
+ void DidCallWillStartRequest() {
+ will_start_called_++;
+ if (will_start_loop_runner_)
+ will_start_loop_runner_->Quit();
+ }
+
+ void DidCallWillRedirectRequest() {
+ will_redirect_called_++;
+ if (will_redirect_loop_runner_)
+ will_redirect_loop_runner_->Quit();
+ }
+
+ void DidCallWillProcessResponse() {
+ will_process_called_++;
+ if (will_process_loop_runner_)
+ will_process_loop_runner_->Quit();
+ }
+
+ NavigationThrottle::ThrottleCheckResult will_start_result_;
+ NavigationThrottle::ThrottleCheckResult will_redirect_result_;
+ NavigationThrottle::ThrottleCheckResult will_process_result_;
+ int will_start_called_;
+ int will_redirect_called_;
+ int will_process_called_;
+ TestNavigationThrottle* navigation_throttle_;
+ scoped_refptr<MessageLoopRunner> will_start_loop_runner_;
+ scoped_refptr<MessageLoopRunner> will_redirect_loop_runner_;
+ scoped_refptr<MessageLoopRunner> will_process_loop_runner_;
+};
+
+} // namespace
+
+class NavigationHandleImplBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ SetupCrossSiteRedirector(embedded_test_server());
+ }
+};
+
+// Ensure that PageTransition is properly set on the NavigationHandle.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifyPageTransition) {
+ {
+ // Test browser initiated navigation, which should have a PageTransition as
+ // if it came from the omnibox.
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), url);
+ ui::PageTransition expected_transition = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_EQ(url, observer.last_committed_url());
+ EXPECT_EQ(expected_transition, observer.page_transition());
+ }
+
+ {
+ // Test navigating to a page with subframe. The subframe will have
+ // PageTransition of type AUTO_SUBFRAME.
+ GURL url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
+ NavigationHandleObserver observer(
+ shell()->web_contents(),
+ embedded_test_server()->GetURL("/cross-site/baz.com/title1.html"));
+ ui::PageTransition expected_transition =
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
+ observer.last_committed_url());
+ EXPECT_EQ(expected_transition, observer.page_transition());
+ EXPECT_FALSE(observer.is_main_frame());
+ }
+}
+
+// Ensure that the following methods on NavigationHandle behave correctly:
+// * IsInMainFrame
+// * IsParentMainFrame
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifyFrameTree) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
+ GURL b_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(c())"));
+ GURL c_url(embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c()"));
+
+ NavigationHandleObserver main_observer(shell()->web_contents(), main_url);
+ NavigationHandleObserver b_observer(shell()->web_contents(), b_url);
+ NavigationHandleObserver c_observer(shell()->web_contents(), c_url);
+
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Verify the main frame.
+ EXPECT_TRUE(main_observer.has_committed());
+ EXPECT_FALSE(main_observer.is_error());
+ EXPECT_EQ(main_url, main_observer.last_committed_url());
+ EXPECT_TRUE(main_observer.is_main_frame());
+ EXPECT_EQ(root->frame_tree_node_id(), main_observer.frame_tree_node_id());
+
+ // Verify the b.com frame.
+ EXPECT_TRUE(b_observer.has_committed());
+ EXPECT_FALSE(b_observer.is_error());
+ EXPECT_EQ(b_url, b_observer.last_committed_url());
+ EXPECT_FALSE(b_observer.is_main_frame());
+ EXPECT_TRUE(b_observer.is_parent_main_frame());
+ EXPECT_EQ(root->child_at(0)->frame_tree_node_id(),
+ b_observer.frame_tree_node_id());
+
+ // Verify the c.com frame.
+ EXPECT_TRUE(c_observer.has_committed());
+ EXPECT_FALSE(c_observer.is_error());
+ EXPECT_EQ(c_url, c_observer.last_committed_url());
+ EXPECT_FALSE(c_observer.is_main_frame());
+ EXPECT_FALSE(c_observer.is_parent_main_frame());
+ EXPECT_EQ(root->child_at(0)->child_at(0)->frame_tree_node_id(),
+ c_observer.frame_tree_node_id());
+}
+
+// Ensure that the WasRedirected() method on NavigationHandle behaves correctly.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifyRedirect) {
+ {
+ GURL url(embedded_test_server()->GetURL("/title1.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), url);
+
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_FALSE(observer.was_redirected());
+ }
+
+ {
+ GURL url(embedded_test_server()->GetURL("/cross-site/baz.com/title1.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), url);
+
+ NavigateToURL(shell(), url);
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_TRUE(observer.was_redirected());
+ }
+}
+
+// Ensure that the IsSrcdoc() method on NavigationHandle behaves correctly.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifySrcdoc) {
+ GURL url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_srcdoc_frame.html"));
+ NavigationHandleObserver observer(shell()->web_contents(),
+ GURL(url::kAboutBlankURL));
+
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_TRUE(observer.is_srcdoc());
+}
+
+// Ensure that the IsSynchronousNavigation() method on NavigationHandle behaves
+// correctly.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, VerifySynchronous) {
+ GURL url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a())"));
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ NavigationHandleObserver observer(
+ shell()->web_contents(), embedded_test_server()->GetURL("a.com", "/bar"));
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+ "window.history.pushState({}, '', 'bar');"));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_TRUE(observer.is_synchronous());
+}
+
+// Ensure that a NavigationThrottle can cancel the navigation at navigation
+// start.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, ThrottleCancelStart) {
+ GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+ GURL redirect_url(
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url);
+ TestNavigationThrottleInstaller installer(
+ shell()->web_contents(), NavigationThrottle::CANCEL,
+ NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
+
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
+
+ EXPECT_FALSE(observer.has_committed());
+ EXPECT_TRUE(observer.is_error());
+
+ // The navigation should have been canceled before being redirected.
+ EXPECT_FALSE(observer.was_redirected());
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url);
+}
+
+// Ensure that a NavigationThrottle can cancel the navigation when a navigation
+// is redirected.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest,
+ ThrottleCancelRedirect) {
+ GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+ // A navigation with a redirect should be canceled.
+ {
+ GURL redirect_url(
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url);
+ TestNavigationThrottleInstaller installer(
+ shell()->web_contents(), NavigationThrottle::PROCEED,
+ NavigationThrottle::CANCEL, NavigationThrottle::PROCEED);
+
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
+
+ EXPECT_FALSE(observer.has_committed());
+ EXPECT_TRUE(observer.is_error());
+ EXPECT_TRUE(observer.was_redirected());
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url);
+ }
+
+ // A navigation without redirects should be successful.
+ {
+ GURL no_redirect_url(embedded_test_server()->GetURL("/title2.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), no_redirect_url);
+ TestNavigationThrottleInstaller installer(
+ shell()->web_contents(), NavigationThrottle::PROCEED,
+ NavigationThrottle::CANCEL, NavigationThrottle::PROCEED);
+
+ EXPECT_TRUE(NavigateToURL(shell(), no_redirect_url));
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_FALSE(observer.was_redirected());
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), no_redirect_url);
+ }
+}
+
+// Ensure that a NavigationThrottle can cancel the navigation when the response
+// is received.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest,
+ ThrottleCancelResponse) {
+ GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+ GURL redirect_url(
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html"));
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url);
+ TestNavigationThrottleInstaller installer(
+ shell()->web_contents(), NavigationThrottle::PROCEED,
+ NavigationThrottle::PROCEED, NavigationThrottle::CANCEL);
+
+ EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
+
+ EXPECT_FALSE(observer.has_committed());
+ EXPECT_TRUE(observer.is_error());
+ // The navigation should have been redirected first, and then canceled when
+ // the response arrived.
+ EXPECT_TRUE(observer.was_redirected());
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url);
+}
+
+// Ensure that a NavigationThrottle can defer and resume the navigation at
+// navigation start, navigation redirect and response received.
+IN_PROC_BROWSER_TEST_F(NavigationHandleImplBrowserTest, ThrottleDefer) {
+ GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+ GURL redirect_url(
+ embedded_test_server()->GetURL("/cross-site/bar.com/title2.html"));
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ NavigationHandleObserver observer(shell()->web_contents(), redirect_url);
+ TestNavigationThrottleInstaller installer(
+ shell()->web_contents(), NavigationThrottle::DEFER,
+ NavigationThrottle::DEFER, NavigationThrottle::DEFER);
+
+ shell()->LoadURL(redirect_url);
+
+ // Wait for WillStartRequest.
+ installer.WaitForThrottleWillStart();
+ EXPECT_EQ(1, installer.will_start_called());
+ EXPECT_EQ(0, installer.will_redirect_called());
+ EXPECT_EQ(0, installer.will_process_called());
+ installer.navigation_throttle()->Resume();
+
+ // Wait for WillRedirectRequest.
+ installer.WaitForThrottleWillRedirect();
+ EXPECT_EQ(1, installer.will_start_called());
+ EXPECT_EQ(1, installer.will_redirect_called());
+ EXPECT_EQ(0, installer.will_process_called());
+ installer.navigation_throttle()->Resume();
+
+ // Wait for WillProcessResponse.
+ installer.WaitForThrottleWillProcess();
+ EXPECT_EQ(1, installer.will_start_called());
+ EXPECT_EQ(1, installer.will_redirect_called());
+ EXPECT_EQ(1, installer.will_process_called());
+ installer.navigation_throttle()->Resume();
+
+ // Wait for the end of the navigation.
+ navigation_observer.Wait();
+
+ EXPECT_TRUE(observer.has_committed());
+ EXPECT_TRUE(observer.was_redirected());
+ EXPECT_FALSE(observer.is_error());
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(),
+ GURL(embedded_test_server()->GetURL("bar.com", "/title2.html")));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl_unittest.cc b/chromium/content/browser/frame_host/navigation_handle_impl_unittest.cc
index ee999cb31b0..65adc6b494e 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_handle_impl_unittest.cc
@@ -9,9 +9,10 @@
namespace content {
-// Test version of a NavigationThrottle. It will always return the same
+// Test version of a NavigationThrottle. It will always return the current
// NavigationThrottle::ThrottleCheckResult |result_|, It also monitors the
-// number of times WillStartRequest and WillRedirectRequest were called.
+// number of times WillStartRequest, WillRedirectRequest, and
+// WillProcessResponse were called.
class TestNavigationThrottle : public NavigationThrottle {
public:
TestNavigationThrottle(NavigationHandle* handle,
@@ -19,7 +20,8 @@ class TestNavigationThrottle : public NavigationThrottle {
: NavigationThrottle(handle),
result_(result),
will_start_calls_(0),
- will_redirect_calls_(0) {}
+ will_redirect_calls_(0),
+ will_process_response_calls_(0) {}
~TestNavigationThrottle() override {}
@@ -33,16 +35,25 @@ class TestNavigationThrottle : public NavigationThrottle {
return result_;
}
+ NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
+ ++will_process_response_calls_;
+ return result_;
+ }
+
int will_start_calls() const { return will_start_calls_; }
int will_redirect_calls() const { return will_redirect_calls_; }
+ int will_process_response_calls() const {
+ return will_process_response_calls_;
+ }
private:
// The result returned by the TestNavigationThrottle.
NavigationThrottle::ThrottleCheckResult result_;
- // The number of times WillStartRequest and WillRedirectRequest were called.
+ // The number of times each handler was called.
int will_start_calls_;
int will_redirect_calls_;
+ int will_process_response_calls_;
};
class NavigationHandleImplTest : public RenderViewHostImplTestHarness {
@@ -53,8 +64,9 @@ class NavigationHandleImplTest : public RenderViewHostImplTestHarness {
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
- test_handle_ = NavigationHandleImpl::Create(
- GURL(), main_test_rfh()->frame_tree_node(), base::TimeTicks::Now());
+ test_handle_ =
+ NavigationHandleImpl::Create(GURL(), main_test_rfh()->frame_tree_node(),
+ false, false, base::TimeTicks::Now(), 0);
}
void TearDown() override {
@@ -72,6 +84,10 @@ class NavigationHandleImplTest : public RenderViewHostImplTestHarness {
return test_handle_->state() == NavigationHandleImpl::DEFERRING_REDIRECT;
}
+ bool IsDeferringResponse() {
+ return test_handle_->state() == NavigationHandleImpl::DEFERRING_RESPONSE;
+ }
+
bool IsCanceling() {
return test_handle_->state() == NavigationHandleImpl::CANCELING;
}
@@ -108,6 +124,24 @@ class NavigationHandleImplTest : public RenderViewHostImplTestHarness {
base::Unretained(this)));
}
+ // Helper function to call WillProcessResponse on |handle|. If this function
+ // returns DEFER, |callback_result_| will be set to the actual result of the
+ // throttle checks when they are finished.
+ // TODO(clamy): this should also simulate that WillStartRequest was called if
+ // it has not been called before.
+ void SimulateWillProcessResponse() {
+ was_callback_called_ = false;
+ callback_result_ = NavigationThrottle::DEFER;
+
+ // It's safe to use base::Unretained since the NavigationHandle is owned by
+ // the NavigationHandleImplTest.
+ test_handle_->WillProcessResponse(
+ main_test_rfh(),
+ scoped_refptr<net::HttpResponseHeaders>(),
+ base::Bind(&NavigationHandleImplTest::UpdateThrottleCheckResult,
+ base::Unretained(this)));
+ }
+
// Returns the handle used in tests.
NavigationHandleImpl* test_handle() const { return test_handle_.get(); }
@@ -150,46 +184,80 @@ TEST_F(NavigationHandleImplTest, ResumeDeferred) {
CreateTestNavigationThrottle(NavigationThrottle::DEFER);
EXPECT_FALSE(IsDeferringStart());
EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Simulate WillStartRequest. The request should be deferred. The callback
// should not have been called.
SimulateWillStartRequest();
EXPECT_TRUE(IsDeferringStart());
EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Resume the request. It should no longer be deferred and the callback
// should have been called.
test_handle()->Resume();
EXPECT_FALSE(IsDeferringStart());
EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
EXPECT_TRUE(was_callback_called());
EXPECT_EQ(NavigationThrottle::PROCEED, callback_result());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Simulate WillRedirectRequest. The request should be deferred. The callback
// should not have been called.
SimulateWillRedirectRequest();
EXPECT_FALSE(IsDeferringStart());
EXPECT_TRUE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Resume the request. It should no longer be deferred and the callback
// should have been called.
test_handle()->Resume();
EXPECT_FALSE(IsDeferringStart());
EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
EXPECT_TRUE(was_callback_called());
EXPECT_EQ(NavigationThrottle::PROCEED, callback_result());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
+
+ // Simulate WillProcessResponse. It will be deferred. The callback should not
+ // have been called.
+ SimulateWillProcessResponse();
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_TRUE(IsDeferringResponse());
+ EXPECT_FALSE(was_callback_called());
+ EXPECT_EQ(1, test_throttle->will_start_calls());
+ EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(1, test_throttle->will_process_response_calls());
+
+ // Resume the request. It should no longer be deferred and the callback should
+ // have been called.
+ test_handle()->Resume();
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_FALSE(IsDeferringResponse());
+ EXPECT_TRUE(was_callback_called());
+ EXPECT_EQ(NavigationThrottle::PROCEED, callback_result());
+ EXPECT_EQ(1, test_throttle->will_start_calls());
+ EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(1, test_throttle->will_process_response_calls());
+ EXPECT_TRUE(test_handle()->GetRenderFrameHost());
}
// Checks that a navigation deferred during WillStartRequest can be properly
@@ -201,6 +269,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillStart) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Simulate WillStartRequest. The request should be deferred. The callback
// should not have been called.
@@ -210,6 +279,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillStart) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Cancel the request. The callback should have been called.
test_handle()->CancelDeferredNavigation(
@@ -221,6 +291,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillStart) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
}
// Checks that a navigation deferred during WillRedirectRequest can be properly
@@ -232,6 +303,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillRedirect) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Simulate WillRedirectRequest. The request should be deferred. The callback
// should not have been called.
@@ -241,6 +313,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillRedirect) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Cancel the request. The callback should have been called.
test_handle()->CancelDeferredNavigation(
@@ -252,6 +325,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredWillRedirect) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(1, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
}
// Checks that a navigation deferred can be canceled and not ignored.
@@ -262,6 +336,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredNoIgnore) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Simulate WillRedirectRequest. The request should be deferred. The callback
// should not have been called.
@@ -271,6 +346,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredNoIgnore) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
// Cancel the request. The callback should have been called with CANCEL, and
// not CANCEL_AND_IGNORE.
@@ -282,6 +358,7 @@ TEST_F(NavigationHandleImplTest, CancelDeferredNoIgnore) {
EXPECT_EQ(NavigationThrottle::CANCEL, callback_result());
EXPECT_EQ(1, test_throttle->will_start_calls());
EXPECT_EQ(0, test_throttle->will_redirect_calls());
+ EXPECT_EQ(0, test_throttle->will_process_response_calls());
}
// Checks that a NavigationThrottle asking to defer followed by a
@@ -295,8 +372,10 @@ TEST_F(NavigationHandleImplTest, DeferThenProceed) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+ EXPECT_EQ(0, proceed_throttle->will_process_response_calls());
// Simulate WillStartRequest. The request should be deferred. The callback
// should not have been called. The second throttle should not have been
@@ -307,6 +386,7 @@ TEST_F(NavigationHandleImplTest, DeferThenProceed) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
@@ -319,6 +399,7 @@ TEST_F(NavigationHandleImplTest, DeferThenProceed) {
EXPECT_EQ(NavigationThrottle::PROCEED, callback_result());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(1, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
@@ -331,6 +412,7 @@ TEST_F(NavigationHandleImplTest, DeferThenProceed) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(1, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(1, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
@@ -343,6 +425,7 @@ TEST_F(NavigationHandleImplTest, DeferThenProceed) {
EXPECT_EQ(NavigationThrottle::PROCEED, callback_result());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(1, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(1, proceed_throttle->will_start_calls());
EXPECT_EQ(1, proceed_throttle->will_redirect_calls());
}
@@ -358,6 +441,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillStartRequest) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
@@ -370,6 +454,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillStartRequest) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
@@ -383,6 +468,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillStartRequest) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(1, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(1, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
}
@@ -398,6 +484,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillRedirectRequest) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, defer_throttle->will_start_calls());
EXPECT_EQ(0, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
@@ -410,6 +497,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillRedirectRequest) {
EXPECT_FALSE(was_callback_called());
EXPECT_EQ(0, defer_throttle->will_start_calls());
EXPECT_EQ(1, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
@@ -423,6 +511,7 @@ TEST_F(NavigationHandleImplTest, DeferThenCancelWillRedirectRequest) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(0, defer_throttle->will_start_calls());
EXPECT_EQ(1, defer_throttle->will_redirect_calls());
+ EXPECT_EQ(0, defer_throttle->will_process_response_calls());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(1, cancel_throttle->will_redirect_calls());
}
@@ -440,6 +529,7 @@ TEST_F(NavigationHandleImplTest, CancelThenProceedWillStartRequest) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
@@ -453,6 +543,7 @@ TEST_F(NavigationHandleImplTest, CancelThenProceedWillStartRequest) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(1, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
}
@@ -470,6 +561,7 @@ TEST_F(NavigationHandleImplTest, CancelThenProceedWillRedirectRequest) {
EXPECT_FALSE(IsDeferringRedirect());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
@@ -483,8 +575,74 @@ TEST_F(NavigationHandleImplTest, CancelThenProceedWillRedirectRequest) {
EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
EXPECT_EQ(0, cancel_throttle->will_start_calls());
EXPECT_EQ(1, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
+ EXPECT_EQ(0, proceed_throttle->will_start_calls());
+ EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+}
+
+// Checks that a NavigationThrottle asking to proceed followed by a
+// NavigationThrottle asking to cancel behave correctly in WillProcessResponse.
+// Both throttles will be called, and the request will be cancelled.
+TEST_F(NavigationHandleImplTest, ProceedThenCancelWillProcessResponse) {
+ TestNavigationThrottle* proceed_throttle =
+ CreateTestNavigationThrottle(NavigationThrottle::PROCEED);
+ TestNavigationThrottle* cancel_throttle =
+ CreateTestNavigationThrottle(NavigationThrottle::CANCEL_AND_IGNORE);
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_EQ(0, cancel_throttle->will_start_calls());
+ EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
+ EXPECT_EQ(0, proceed_throttle->will_start_calls());
+ EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+ EXPECT_EQ(0, proceed_throttle->will_process_response_calls());
+
+ // Simulate WillRedirectRequest. The request should not be deferred. The
+ // callback should have been called.
+ SimulateWillProcessResponse();
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_TRUE(was_callback_called());
+ EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
+ EXPECT_EQ(0, cancel_throttle->will_start_calls());
+ EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(1, cancel_throttle->will_process_response_calls());
+ EXPECT_EQ(0, proceed_throttle->will_start_calls());
+ EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+ EXPECT_EQ(1, proceed_throttle->will_process_response_calls());
+}
+
+// Checks that a NavigationThrottle asking to cancel followed by a
+// NavigationThrottle asking to proceed behave correctly in WillProcessResponse.
+// The navigation will be canceled directly, and the second throttle will not
+// be called.
+TEST_F(NavigationHandleImplTest, CancelThenProceedWillProcessResponse) {
+ TestNavigationThrottle* cancel_throttle =
+ CreateTestNavigationThrottle(NavigationThrottle::CANCEL_AND_IGNORE);
+ TestNavigationThrottle* proceed_throttle =
+ CreateTestNavigationThrottle(NavigationThrottle::PROCEED);
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_EQ(0, cancel_throttle->will_start_calls());
+ EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(0, cancel_throttle->will_process_response_calls());
+ EXPECT_EQ(0, proceed_throttle->will_start_calls());
+ EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+
+ // Simulate WillRedirectRequest. The request should not be deferred. The
+ // callback should have been called. The second throttle should not have
+ // been notified.
+ SimulateWillProcessResponse();
+ EXPECT_FALSE(IsDeferringStart());
+ EXPECT_FALSE(IsDeferringRedirect());
+ EXPECT_TRUE(was_callback_called());
+ EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
+ EXPECT_EQ(0, cancel_throttle->will_start_calls());
+ EXPECT_EQ(0, cancel_throttle->will_redirect_calls());
+ EXPECT_EQ(1, cancel_throttle->will_process_response_calls());
EXPECT_EQ(0, proceed_throttle->will_start_calls());
EXPECT_EQ(0, proceed_throttle->will_redirect_calls());
+ EXPECT_EQ(0, proceed_throttle->will_process_response_calls());
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc
index 582a6803dfb..617fc26dc41 100644
--- a/chromium/content/browser/frame_host/navigation_request.cc
+++ b/chromium/content/browser/frame_host/navigation_request.cc
@@ -6,12 +6,14 @@
#include <utility>
+#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/navigation_request_info.h"
#include "content/browser/frame_host/navigator.h"
+#include "content/browser/frame_host/navigator_impl.h"
#include "content/browser/loader/navigation_url_loader.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_navigation_handle.h"
@@ -41,7 +43,7 @@ int LoadFlagFromNavigationType(FrameMsg_Navigate_Type::Value navigation_type) {
case FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL:
load_flags |= net::LOAD_VALIDATE_CACHE;
break;
- case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE:
+ case FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE:
load_flags |= net::LOAD_BYPASS_CACHE;
break;
case FrameMsg_Navigate_Type::RESTORE:
@@ -67,19 +69,16 @@ scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
const FrameNavigationEntry& frame_entry,
const NavigationEntryImpl& entry,
FrameMsg_Navigate_Type::Value navigation_type,
+ LoFiState lofi_state,
bool is_same_document_history_load,
const base::TimeTicks& navigation_start,
NavigationControllerImpl* controller) {
- std::string method = entry.GetHasPostData() ? "POST" : "GET";
-
// Copy existing headers and add necessary headers that may not be present
// in the RequestNavigationParams.
net::HttpRequestHeaders headers;
headers.AddHeadersFromString(entry.extra_headers());
headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
GetContentClient()->GetUserAgent());
- // TODO(clamy): match what blink is doing with accept headers.
- headers.SetHeaderIfMissing("Accept", "*/*");
// Fill POST data from the browser in the request body.
scoped_refptr<ResourceRequestBody> request_body;
@@ -93,9 +92,9 @@ scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
scoped_ptr<NavigationRequest> navigation_request(new NavigationRequest(
frame_tree_node, entry.ConstructCommonNavigationParams(
- dest_url, dest_referrer, navigation_type,
- LOFI_UNSPECIFIED, navigation_start),
- BeginNavigationParams(method, headers.ToString(),
+ dest_url, dest_referrer, navigation_type, lofi_state,
+ navigation_start),
+ BeginNavigationParams(headers.ToString(),
LoadFlagFromNavigationType(navigation_type),
false, // has_user_gestures
false, // skip_service_worker
@@ -125,7 +124,6 @@ scoped_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
// TODO(clamy): See if the navigation start time should be measured in the
// renderer and sent to the browser instead of being measured here.
// TODO(clamy): The pending history list offset should be properly set.
- // TODO(clamy): Set has_committed_real_load.
RequestNavigationParams request_params(
false, // is_overriding_user_agent
std::vector<GURL>(), // redirects
@@ -135,7 +133,7 @@ scoped_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
-1, // page_id
0, // nav_entry_id
false, // is_same_document_history_load
- false, // has_committed_real_load
+ frame_tree_node->has_committed_real_load(),
false, // intended_as_new_entry
-1, // pending_history_list_offset
current_history_list_offset, current_history_list_length,
@@ -164,7 +162,8 @@ NavigationRequest::NavigationRequest(
state_(NOT_STARTED),
restore_type_(NavigationEntryImpl::RESTORE_NONE),
is_view_source_(false),
- bindings_(NavigationEntryImpl::kInvalidBindings) {
+ bindings_(NavigationEntryImpl::kInvalidBindings),
+ associated_site_instance_type_(AssociatedSiteInstanceType::NONE) {
DCHECK(!browser_initiated || (entry != nullptr && frame_entry != nullptr));
if (browser_initiated) {
// TODO(clamy): use the FrameNavigationEntry for the source SiteInstance
@@ -193,7 +192,7 @@ NavigationRequest::NavigationRequest(
false : frame_tree_node->parent()->IsMainFrame();
info_.reset(new NavigationRequestInfo(
common_params, begin_params, first_party_for_cookies,
- frame_tree_node->frame_origin(), frame_tree_node->IsMainFrame(),
+ frame_tree_node->current_origin(), frame_tree_node->IsMainFrame(),
parent_is_main_frame, frame_tree_node->frame_tree_node_id(), body));
}
@@ -204,13 +203,16 @@ void NavigationRequest::BeginNavigation() {
DCHECK(!loader_);
DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
state_ = STARTED;
+ RenderFrameDevToolsAgentHost::OnBeforeNavigation(navigation_handle_.get());
if (ShouldMakeNetworkRequestForURL(common_params_.url)) {
// It's safe to use base::Unretained because this NavigationRequest owns
// the NavigationHandle where the callback will be stored.
// TODO(clamy): pass the real value for |is_external_protocol| if needed.
+ // TODO(clamy): pass the method to the NavigationHandle instead of a
+ // boolean.
navigation_handle_->WillStartRequest(
- begin_params_.method == "POST",
+ common_params_.method == "POST",
Referrer::SanitizeForRequest(common_params_.url,
common_params_.referrer),
begin_params_.has_user_gesture, common_params_.transition, false,
@@ -222,13 +224,27 @@ void NavigationRequest::BeginNavigation() {
// There is no need to make a network request for this navigation, so commit
// it immediately.
state_ = RESPONSE_STARTED;
- frame_tree_node_->navigator()->CommitNavigation(
- frame_tree_node_, nullptr, scoped_ptr<StreamHandle>());
+
+ // Select an appropriate RenderFrameHost.
+ RenderFrameHostImpl* render_frame_host =
+ frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this);
+ NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host,
+ common_params_.url);
+
+ // Inform the NavigationHandle that the navigation will commit.
+ navigation_handle_->ReadyToCommitNavigation(render_frame_host);
+
+ CommitNavigation();
}
-void NavigationRequest::CreateNavigationHandle() {
+void NavigationRequest::CreateNavigationHandle(int pending_nav_entry_id) {
+ // TODO(nasko): Update the NavigationHandle creation to ensure that the
+ // proper values are specified for is_synchronous and is_srcdoc.
navigation_handle_ = NavigationHandleImpl::Create(
- common_params_.url, frame_tree_node_, common_params_.navigation_start);
+ common_params_.url, frame_tree_node_,
+ false, // is_synchronous
+ false, // is_srcdoc
+ common_params_.navigation_start, pending_nav_entry_id);
}
void NavigationRequest::TransferNavigationHandleOwnership(
@@ -240,7 +256,7 @@ void NavigationRequest::OnRequestRedirected(
const net::RedirectInfo& redirect_info,
const scoped_refptr<ResourceResponse>& response) {
common_params_.url = redirect_info.new_url;
- begin_params_.method = redirect_info.new_method;
+ common_params_.method = redirect_info.new_method;
common_params_.referrer.url = GURL(redirect_info.new_referrer);
// TODO(clamy): Have CSP + security upgrade checks here.
@@ -250,7 +266,7 @@ void NavigationRequest::OnRequestRedirected(
// NavigationHandle where the callback will be stored.
// TODO(clamy): pass the real value for |is_external_protocol| if needed.
navigation_handle_->WillRedirectRequest(
- common_params_.url, begin_params_.method == "POST",
+ common_params_.url, common_params_.method == "POST",
common_params_.referrer.url, false, response->head.headers,
base::Bind(&NavigationRequest::OnRedirectChecksComplete,
base::Unretained(this)));
@@ -262,9 +278,19 @@ void NavigationRequest::OnResponseStarted(
DCHECK(state_ == STARTED);
state_ = RESPONSE_STARTED;
+ // HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not
+ // commit; they leave the frame showing the previous page.
+ DCHECK(response);
+ if (response->head.headers.get() &&
+ (response->head.headers->response_code() == 204 ||
+ response->head.headers->response_code() == 205)) {
+ frame_tree_node_->ResetNavigationRequest(false);
+ return;
+ }
+
// Update the service worker params of the request params.
request_params_.should_create_service_worker =
- (frame_tree_node_->current_replication_state().sandbox_flags &
+ (frame_tree_node_->pending_sandbox_flags() &
blink::WebSandboxFlags::Origin) != blink::WebSandboxFlags::Origin;
if (navigation_handle_->service_worker_handle()) {
request_params_.service_worker_provider_id =
@@ -272,8 +298,38 @@ void NavigationRequest::OnResponseStarted(
->service_worker_provider_host_id();
}
- frame_tree_node_->navigator()->CommitNavigation(
- frame_tree_node_, response.get(), std::move(body));
+ // Update the lofi state of the request.
+ if (response->head.is_using_lofi)
+ common_params_.lofi_state = LOFI_ON;
+ else
+ common_params_.lofi_state = LOFI_OFF;
+
+ // Select an appropriate renderer to commit the navigation.
+ RenderFrameHostImpl* render_frame_host =
+ frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this);
+ NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host,
+ common_params_.url);
+
+ // For renderer-initiated navigations that are set to commit in a different
+ // renderer, allow the embedder to cancel the transfer.
+ if (!browser_initiated_ &&
+ render_frame_host != frame_tree_node_->current_frame_host() &&
+ !frame_tree_node_->navigator()
+ ->GetDelegate()
+ ->ShouldTransferNavigation()) {
+ frame_tree_node_->ResetNavigationRequest(false);
+ return;
+ }
+
+ // Store the response and the StreamHandle until checks have been processed.
+ response_ = response;
+ body_ = std::move(body);
+
+ // Check if the navigation should be allowed to proceed.
+ navigation_handle_->WillProcessResponse(
+ render_frame_host, response->head.headers.get(),
+ base::Bind(&NavigationRequest::OnWillProcessResponseChecksComplete,
+ base::Unretained(this)));
}
void NavigationRequest::OnRequestFailed(bool has_stale_copy_in_cache,
@@ -327,14 +383,57 @@ void NavigationRequest::OnRedirectChecksComplete(
}
loader_->FollowRedirect();
- navigation_handle_->DidRedirectNavigation(common_params_.url);
+}
+
+void NavigationRequest::OnWillProcessResponseChecksComplete(
+ NavigationThrottle::ThrottleCheckResult result) {
+ CHECK(result != NavigationThrottle::DEFER);
+
+ // Abort the request if needed. This will destroy the NavigationRequest.
+ if (result == NavigationThrottle::CANCEL_AND_IGNORE ||
+ result == NavigationThrottle::CANCEL) {
+ // TODO(clamy): distinguish between CANCEL and CANCEL_AND_IGNORE.
+ frame_tree_node_->ResetNavigationRequest(false);
+ return;
+ }
+
+ // Have the processing of the response resume in the network stack.
+ loader_->ProceedWithResponse();
+
+ CommitNavigation();
+
+ // DO NOT ADD CODE after this. The previous call to CommitNavigation caused
+ // the destruction of the NavigationRequest.
+}
+
+void NavigationRequest::CommitNavigation() {
+ DCHECK(response_ || !ShouldMakeNetworkRequestForURL(common_params_.url));
+
+ // Retrieve the RenderFrameHost that needs to commit the navigation.
+ RenderFrameHostImpl* render_frame_host =
+ navigation_handle_->GetRenderFrameHost();
+ DCHECK(render_frame_host ==
+ frame_tree_node_->render_manager()->current_frame_host() ||
+ render_frame_host ==
+ frame_tree_node_->render_manager()->speculative_frame_host());
+
+ TransferNavigationHandleOwnership(render_frame_host);
+ render_frame_host->CommitNavigation(response_.get(), std::move(body_),
+ common_params_, request_params_,
+ is_view_source_);
+
+ // When navigating to a Javascript url, the NavigationRequest is not stored
+ // in the FrameTreeNode. Therefore do not reset it, as this could cancel an
+ // existing pending navigation.
+ if (!common_params_.url.SchemeIs(url::kJavaScriptScheme))
+ frame_tree_node_->ResetNavigationRequest(true);
}
void NavigationRequest::InitializeServiceWorkerHandleIfNeeded() {
// Only initialize the ServiceWorkerNavigationHandle if it can be created for
// this frame.
bool can_create_service_worker =
- (frame_tree_node_->current_replication_state().sandbox_flags &
+ (frame_tree_node_->pending_sandbox_flags() &
blink::WebSandboxFlags::Origin) != blink::WebSandboxFlags::Origin;
if (!can_create_service_worker)
return;
diff --git a/chromium/content/browser/frame_host/navigation_request.h b/chromium/content/browser/frame_host/navigation_request.h
index fb418c54d11..da8f9d7b81e 100644
--- a/chromium/content/browser/frame_host/navigation_request.h
+++ b/chromium/content/browser/frame_host/navigation_request.h
@@ -57,6 +57,16 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
FAILED,
};
+ // The SiteInstance currently associated with the navigation. Note that the
+ // final value will only be known when the response is received, or the
+ // navigation fails, as server redirects can modify the SiteInstance to use
+ // for the navigation.
+ enum class AssociatedSiteInstanceType {
+ NONE = 0,
+ CURRENT,
+ SPECULATIVE,
+ };
+
// Creates a request for a browser-intiated navigation.
static scoped_ptr<NavigationRequest> CreateBrowserInitiated(
FrameTreeNode* frame_tree_node,
@@ -65,6 +75,7 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
const FrameNavigationEntry& frame_entry,
const NavigationEntryImpl& entry,
FrameMsg_Navigate_Type::Value navigation_type,
+ LoFiState lofi_state,
bool is_same_document_history_load,
const base::TimeTicks& navigation_start,
NavigationControllerImpl* controller);
@@ -99,6 +110,8 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
NavigationState state() const { return state_; }
+ FrameTreeNode* frame_tree_node() const { return frame_tree_node_; }
+
SiteInstanceImpl* source_site_instance() const {
return source_site_instance_.get();
}
@@ -122,13 +135,20 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
state_ = WAITING_FOR_RENDERER_RESPONSE;
}
+ AssociatedSiteInstanceType associated_site_instance_type() const {
+ return associated_site_instance_type_;
+ }
+ void set_associated_site_instance_type(AssociatedSiteInstanceType type) {
+ associated_site_instance_type_ = type;
+ }
+
NavigationHandleImpl* navigation_handle() const {
return navigation_handle_.get();
}
// Creates a NavigationHandle. This should be called after any previous
// NavigationRequest for the FrameTreeNode has been destroyed.
- void CreateNavigationHandle();
+ void CreateNavigationHandle(int pending_nav_entry_id);
// Transfers the ownership of the NavigationHandle to |render_frame_host|.
// This should be called when the navigation is ready to commit, because the
@@ -161,6 +181,12 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
// NavigationHandle.
void OnStartChecksComplete(NavigationThrottle::ThrottleCheckResult result);
void OnRedirectChecksComplete(NavigationThrottle::ThrottleCheckResult result);
+ void OnWillProcessResponseChecksComplete(
+ NavigationThrottle::ThrottleCheckResult result);
+
+ // Have a RenderFrameHost commit the navigation. The NavigationRequest will
+ // be destroyed after this call.
+ void CommitNavigation();
// Called when the navigation is about to be sent to the IO thread.
void InitializeServiceWorkerHandleIfNeeded();
@@ -199,8 +225,16 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
bool is_view_source_;
int bindings_;
+ // The type of SiteInstance associated with this navigation.
+ AssociatedSiteInstanceType associated_site_instance_type_;
+
scoped_ptr<NavigationHandleImpl> navigation_handle_;
+ // Holds the ResourceResponse and the StreamHandle for the navigation while
+ // the WillProcessResponse checks are performed by the NavigationHandle.
+ scoped_refptr<ResourceResponse> response_;
+ scoped_ptr<StreamHandle> body_;
+
DISALLOW_COPY_AND_ASSIGN(NavigationRequest);
};
diff --git a/chromium/content/browser/frame_host/navigator.cc b/chromium/content/browser/frame_host/navigator.cc
index 333d1033374..ac6c248cae6 100644
--- a/chromium/content/browser/frame_host/navigator.cc
+++ b/chromium/content/browser/frame_host/navigator.cc
@@ -42,9 +42,4 @@ void Navigator::OnBeginNavigation(
scoped_refptr<ResourceRequestBody> body) {
}
-void Navigator::CommitNavigation(FrameTreeNode* frame_tree_node,
- ResourceResponse* response,
- scoped_ptr<StreamHandle> body) {
-}
-
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigator.h b/chromium/content/browser/frame_host/navigator.h
index b5e0e84a538..ce1c97dec99 100644
--- a/chromium/content/browser/frame_host/navigator.h
+++ b/chromium/content/browser/frame_host/navigator.h
@@ -124,6 +124,7 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
virtual void RequestTransferURL(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -148,13 +149,6 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
scoped_refptr<ResourceRequestBody> body);
// PlzNavigate
- // Signal |render_frame_host| that a navigation is ready to commit (the
- // response to the navigation request has been received).
- virtual void CommitNavigation(FrameTreeNode* frame_tree_node,
- ResourceResponse* response,
- scoped_ptr<StreamHandle> body);
-
- // PlzNavigate
// Called when a NavigationRequest for |frame_tree_node| failed. An
// appropriate RenderFrameHost should be selected and asked to show an error
// page. |has_stale_copy_in_cache| is true if there is a stale copy of the
diff --git a/chromium/content/browser/frame_host/navigator_impl.cc b/chromium/content/browser/frame_host/navigator_impl.cc
index 2acedd76a19..35ee34045fe 100644
--- a/chromium/content/browser/frame_host/navigator_impl.cc
+++ b/chromium/content/browser/frame_host/navigator_impl.cc
@@ -42,6 +42,7 @@
#include "content/public/common/resource_response.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_errors.h"
+#include "url/url_constants.h"
namespace content {
@@ -53,9 +54,9 @@ FrameMsg_Navigate_Type::Value GetNavigationType(
switch (reload_type) {
case NavigationControllerImpl::RELOAD:
return FrameMsg_Navigate_Type::RELOAD;
- case NavigationControllerImpl::RELOAD_IGNORING_CACHE:
+ case NavigationControllerImpl::RELOAD_BYPASSING_CACHE:
case NavigationControllerImpl::RELOAD_DISABLE_LOFI_MODE:
- return FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE;
+ return FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE;
case NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL:
return FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
case NavigationControllerImpl::NO_RELOAD:
@@ -103,6 +104,27 @@ NavigatorImpl::NavigatorImpl(
NavigatorImpl::~NavigatorImpl() {}
+// static
+void NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(
+ RenderFrameHostImpl* render_frame_host,
+ const GURL& url) {
+ int enabled_bindings =
+ render_frame_host->render_view_host()->GetEnabledBindings();
+ bool is_allowed_in_web_ui_renderer =
+ WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
+ render_frame_host->frame_tree_node()
+ ->navigator()
+ ->GetController()
+ ->GetBrowserContext(),
+ url);
+ if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) &&
+ !is_allowed_in_web_ui_renderer) {
+ // Log the URL to help us diagnose any future failures of this CHECK.
+ GetContentClient()->SetActiveURL(url);
+ CHECK(0);
+ }
+}
+
NavigatorDelegate* NavigatorImpl::GetDelegate() {
return delegate_;
}
@@ -124,7 +146,8 @@ void NavigatorImpl::DidStartProvisionalLoad(
if (is_main_frame && !is_error_page) {
DidStartMainFrameNavigation(validated_url,
- render_frame_host->GetSiteInstance());
+ render_frame_host->GetSiteInstance(),
+ render_frame_host->navigation_handle());
}
if (delegate_) {
@@ -151,8 +174,12 @@ void NavigatorImpl::DidStartProvisionalLoad(
render_frame_host->SetNavigationHandle(scoped_ptr<NavigationHandleImpl>());
}
+ NavigationEntry* pending_entry = controller_->GetPendingEntry();
render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create(
- validated_url, render_frame_host->frame_tree_node(), navigation_start));
+ validated_url, render_frame_host->frame_tree_node(),
+ false, // is_synchronous
+ is_iframe_srcdoc, // is_srcdoc
+ navigation_start, pending_entry ? pending_entry->GetUniqueID() : 0));
}
void NavigatorImpl::DidFailProvisionalLoadWithError(
@@ -192,37 +219,14 @@ void NavigatorImpl::DidFailProvisionalLoadWithError(
// We used to cancel the pending renderer here for cross-site downloads.
// However, it's not safe to do that because the download logic repeatedly
- // looks for this WebContents based on a render ID. Instead, we just
+ // looks for this WebContents based on a render ID. Instead, we just
// leave the pending renderer around until the next navigation event
// (Navigate, DidNavigate, etc), which will clean it up properly.
//
// TODO(creis): Find a way to cancel any pending RFH here.
}
- // We usually clear the pending entry when it fails, so that an arbitrary URL
- // isn't left visible above a committed page. This must be enforced when
- // the pending entry isn't visible (e.g., renderer-initiated navigations) to
- // prevent URL spoofs for in-page navigations that don't go through
- // DidStartProvisionalLoadForFrame.
- //
- // However, we do preserve the pending entry in some cases, such as on the
- // initial navigation of an unmodified blank tab. We also allow the delegate
- // to say when it's safe to leave aborted URLs in the omnibox, to let the user
- // edit the URL and try again. This may be useful in cases that the committed
- // page cannot be attacker-controlled. In these cases, we still allow the
- // view to clear the pending entry and typed URL if the user requests
- // (e.g., hitting Escape with focus in the address bar).
- //
- // Note: don't touch the transient entry, since an interstitial may exist.
- bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() ||
- delegate_->ShouldPreserveAbortedURLs();
- if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() ||
- !should_preserve_entry) {
- controller_->DiscardPendingEntry(true);
-
- // Also force the UI to refresh.
- controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
- }
+ DiscardPendingEntryOnFailureIfNeeded(render_frame_host->navigation_handle());
if (delegate_)
delegate_->DidFailProvisionalLoadWithError(render_frame_host, params);
@@ -272,8 +276,8 @@ bool NavigatorImpl::NavigateToEntry(
// The renderer will reject IPC messages with URLs longer than
// this limit, so don't attempt to navigate with a longer URL.
- if (dest_url.spec().size() > kMaxURLChars) {
- LOG(WARNING) << "Refusing to load URL as it exceeds " << kMaxURLChars
+ if (dest_url.spec().size() > url::kMaxURLChars) {
+ LOG(WARNING) << "Refusing to load URL as it exceeds " << url::kMaxURLChars
<< " characters.";
return false;
}
@@ -287,13 +291,27 @@ bool NavigatorImpl::NavigateToEntry(
"navigation", "NavigationTiming navigationStart",
TRACE_EVENT_SCOPE_GLOBAL, navigation_start.ToInternalValue());
+ // Determine if LoFi should be used for the navigation.
+ LoFiState lofi_state = LOFI_UNSPECIFIED;
+ if (!frame_tree_node->IsMainFrame()) {
+ // For subframes, use the state of the top-level frame.
+ lofi_state = frame_tree_node->frame_tree()
+ ->root()
+ ->current_frame_host()
+ ->last_navigation_lofi_state();
+ } else if (reload_type ==
+ NavigationController::ReloadType::RELOAD_DISABLE_LOFI_MODE) {
+ // Disable LoFi when asked for it explicitly.
+ lofi_state = LOFI_OFF;
+ }
+
// PlzNavigate: the RenderFrameHosts are no longer asked to navigate.
if (IsBrowserSideNavigationEnabled()) {
navigation_data_.reset(new NavigationMetricsData(navigation_start, dest_url,
entry.restore_type()));
RequestNavigation(frame_tree_node, dest_url, dest_referrer, frame_entry,
- entry, reload_type, is_same_document_history_load,
- navigation_start);
+ entry, reload_type, lofi_state,
+ is_same_document_history_load, navigation_start);
if (frame_tree_node->IsMainFrame() &&
frame_tree_node->navigation_request()) {
// TODO(carlosk): extend these traces to support subframes and
@@ -315,61 +333,63 @@ bool NavigatorImpl::NavigateToEntry(
"FrameTreeNode id", frame_tree_node->frame_tree_node_id());
}
- // Notify observers about navigation if this is for the pending entry.
- if (delegate_ && is_pending_entry)
- delegate_->DidStartNavigationToPendingEntry(dest_url, reload_type);
-
- return true;
- }
-
- RenderFrameHostImpl* dest_render_frame_host =
- frame_tree_node->render_manager()->Navigate(dest_url, frame_entry, entry);
- if (!dest_render_frame_host)
- return false; // Unable to create the desired RenderFrameHost.
-
- // Make sure no code called via RFHM::Navigate clears the pending entry.
- if (is_pending_entry)
- CHECK_EQ(controller_->GetPendingEntry(), &entry);
-
- // For security, we should never send non-Web-UI URLs to a Web UI renderer.
- // Double check that here.
- CheckWebUIRendererDoesNotDisplayNormalURL(dest_render_frame_host, dest_url);
-
- // Navigate in the desired RenderFrameHost.
- // We can skip this step in the rare case that this is a transfer navigation
- // which began in the chosen RenderFrameHost, since the request has already
- // been issued. In that case, simply resume the response.
- bool is_transfer_to_same =
- entry.transferred_global_request_id().child_id != -1 &&
- entry.transferred_global_request_id().child_id ==
- dest_render_frame_host->GetProcess()->GetID();
- if (!is_transfer_to_same) {
- navigation_data_.reset(new NavigationMetricsData(navigation_start, dest_url,
- entry.restore_type()));
- // Create the navigation parameters.
- FrameMsg_Navigate_Type::Value navigation_type =
- GetNavigationType(controller_->GetBrowserContext(), entry, reload_type);
- LoFiState lofi_state =
- (reload_type ==
- NavigationController::ReloadType::RELOAD_DISABLE_LOFI_MODE
- ? LOFI_OFF
- : LOFI_UNSPECIFIED);
- dest_render_frame_host->Navigate(
- entry.ConstructCommonNavigationParams(dest_url, dest_referrer,
- navigation_type, lofi_state,
- navigation_start),
- entry.ConstructStartNavigationParams(),
- entry.ConstructRequestNavigationParams(
- frame_entry, is_same_document_history_load,
- frame_tree_node->has_committed_real_load(),
- controller_->GetPendingEntryIndex() == -1,
- controller_->GetIndexOfEntry(&entry),
- controller_->GetLastCommittedEntryIndex(),
- controller_->GetEntryCount()));
} else {
- // No need to navigate again. Just resume the deferred request.
- dest_render_frame_host->GetProcess()->ResumeDeferredNavigation(
- entry.transferred_global_request_id());
+ RenderFrameHostImpl* dest_render_frame_host =
+ frame_tree_node->render_manager()->Navigate(dest_url, frame_entry,
+ entry);
+ if (!dest_render_frame_host)
+ return false; // Unable to create the desired RenderFrameHost.
+
+ // Make sure no code called via RFHM::Navigate clears the pending entry.
+ if (is_pending_entry)
+ CHECK_EQ(controller_->GetPendingEntry(), &entry);
+
+ // For security, we should never send non-Web-UI URLs to a Web UI renderer.
+ // Double check that here.
+ CheckWebUIRendererDoesNotDisplayNormalURL(dest_render_frame_host, dest_url);
+
+ // In the case of a transfer navigation, set the destination
+ // RenderFrameHost as loading. This ensures that the RenderFrameHost gets
+ // in a loading state without emitting a spurious DidStartLoading
+ // notification at the FrameTreeNode level (since the FrameTreeNode was
+ // already loading). Note that this works both for a transfer to a
+ // different RenderFrameHost and in the rare case where the navigation is
+ // transferred back to the same RenderFrameHost.
+ bool is_transfer = entry.transferred_global_request_id().child_id != -1;
+ if (is_transfer)
+ dest_render_frame_host->set_is_loading(true);
+
+ // Navigate in the desired RenderFrameHost.
+ // We can skip this step in the rare case that this is a transfer navigation
+ // which began in the chosen RenderFrameHost, since the request has already
+ // been issued. In that case, simply resume the response.
+ bool is_transfer_to_same =
+ is_transfer &&
+ entry.transferred_global_request_id().child_id ==
+ dest_render_frame_host->GetProcess()->GetID();
+ if (!is_transfer_to_same) {
+ navigation_data_.reset(new NavigationMetricsData(
+ navigation_start, dest_url, entry.restore_type()));
+ // Create the navigation parameters.
+ FrameMsg_Navigate_Type::Value navigation_type = GetNavigationType(
+ controller_->GetBrowserContext(), entry, reload_type);
+ dest_render_frame_host->Navigate(
+ entry.ConstructCommonNavigationParams(dest_url, dest_referrer,
+ navigation_type, lofi_state,
+ navigation_start),
+ entry.ConstructStartNavigationParams(),
+ entry.ConstructRequestNavigationParams(
+ frame_entry, is_same_document_history_load,
+ frame_tree_node->has_committed_real_load(),
+ controller_->GetPendingEntryIndex() == -1,
+ controller_->GetIndexOfEntry(&entry),
+ controller_->GetLastCommittedEntryIndex(),
+ controller_->GetEntryCount()));
+ } else {
+ // No need to navigate again. Just resume the deferred request.
+ dest_render_frame_host->GetProcess()->ResumeDeferredNavigation(
+ entry.transferred_global_request_id());
+ }
}
// Make sure no code called via RFH::Navigate clears the pending entry.
@@ -436,6 +456,11 @@ void NavigatorImpl::DidNavigate(
FrameTree* frame_tree = render_frame_host->frame_tree_node()->frame_tree();
bool oopifs_possible = SiteIsolationPolicy::AreCrossProcessFramesPossible();
+ bool has_embedded_credentials =
+ params.url.has_username() || params.url.has_password();
+ UMA_HISTOGRAM_BOOLEAN("Navigation.FrameHasEmbeddedCredentials",
+ has_embedded_credentials);
+
bool is_navigation_within_page = controller_->IsURLInPageNavigation(
params.url, params.was_within_same_page, render_frame_host);
@@ -470,6 +495,9 @@ void NavigatorImpl::DidNavigate(
// Run tasks that must execute just before the commit.
delegate_->DidNavigateMainFramePreCommit(is_navigation_within_page);
+
+ UMA_HISTOGRAM_BOOLEAN("Navigation.MainFrameHasEmbeddedCredentials",
+ has_embedded_credentials);
}
if (!oopifs_possible)
@@ -483,7 +511,8 @@ void NavigatorImpl::DidNavigate(
// origin because it creates a RenderFrameProxy that needs this to initialize
// its security context. This origin will also be sent to RenderFrameProxies
// created via ViewMsg_New and FrameMsg_NewFrameProxy.
- render_frame_host->frame_tree_node()->SetCurrentOrigin(params.origin);
+ render_frame_host->frame_tree_node()->SetCurrentOrigin(
+ params.origin, params.has_potentially_trustworthy_unique_origin);
render_frame_host->frame_tree_node()->SetEnforceStrictMixedContentChecking(
params.should_enforce_strict_mixed_content_checking);
@@ -524,9 +553,21 @@ void NavigatorImpl::DidNavigate(
bool did_navigate = controller_->RendererDidNavigate(render_frame_host,
params, &details);
- // Keep track of each frame's URL in its FrameTreeNode.
+ // Keep track of each frame's URL in its FrameTreeNode, whether it's for a net
+ // error or not.
+ // TODO(creis): Move the last committed URL to RenderFrameHostImpl.
render_frame_host->frame_tree_node()->SetCurrentURL(params.url);
+ // Separately, update the frame's last successful URL except for net error
+ // pages, since those do not end up in the correct process after transfers
+ // (see https://crbug.com/560511). Instead, the next cross-process navigation
+ // or transfer should decide whether to swap as if the net error had not
+ // occurred.
+ // TODO(creis): Remove this block and always set the URL once transfers handle
+ // network errors or PlzNavigate is enabled. See https://crbug.com/588314.
+ if (!params.url_is_unreachable)
+ render_frame_host->set_last_successful_url(params.url);
+
if (did_navigate && render_frame_host->frame_tree_node()->IsMainFrame() &&
IsBrowserSideNavigationEnabled()) {
TRACE_EVENT_ASYNC_END0("navigation", "Navigation timeToCommit",
@@ -554,7 +595,7 @@ void NavigatorImpl::DidNavigate(
params.url,
transition_type);
render_frame_host->navigation_handle()->DidCommitNavigation(
- is_navigation_within_page, render_frame_host);
+ params, is_navigation_within_page, render_frame_host);
render_frame_host->SetNavigationHandle(nullptr);
}
@@ -604,17 +645,9 @@ void NavigatorImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
DCHECK(!render_frame_host->GetParent() ||
SiteIsolationPolicy::AreCrossProcessFramesPossible());
- // If this came from a swapped out RenderFrameHost, we only allow the request
- // if we are still in the same BrowsingInstance.
- // TODO(creis): Move this to RenderFrameProxyHost::OpenURL.
SiteInstance* current_site_instance = render_frame_host->frame_tree_node()
->current_frame_host()
->GetSiteInstance();
- if (render_frame_host->is_swapped_out() &&
- !render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
- current_site_instance)) {
- return;
- }
// TODO(creis): Pass the redirect_chain into this method to support client
// redirects. http://crbug.com/311721.
@@ -672,6 +705,7 @@ void NavigatorImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
void NavigatorImpl::RequestTransferURL(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -716,9 +750,8 @@ void NavigatorImpl::RequestTransferURL(
}
NavigationController::LoadURLParams load_url_params(dest_url);
- // The source_site_instance only matters for navigations via RenderFrameProxy,
- // which go through RequestOpenURL.
- load_url_params.source_site_instance = nullptr;
+ // The source_site_instance may matter for navigations via RenderFrameProxy.
+ load_url_params.source_site_instance = source_site_instance;
load_url_params.transition_type = page_transition;
load_url_params.frame_tree_node_id = node->frame_tree_node_id();
load_url_params.referrer = referrer_to_use;
@@ -775,6 +808,10 @@ void NavigatorImpl::OnBeginNavigation(
(ongoing_navigation_request->browser_initiated() ||
ongoing_navigation_request->begin_params().has_user_gesture) &&
!begin_params.has_user_gesture) {
+ RenderFrameHost* current_frame_host =
+ frame_tree_node->render_manager()->current_frame_host();
+ current_frame_host->Send(
+ new FrameMsg_Stop(current_frame_host->GetRoutingID()));
return;
}
@@ -786,8 +823,6 @@ void NavigatorImpl::OnBeginNavigation(
controller_->GetLastCommittedEntryIndex(),
controller_->GetEntryCount()));
NavigationRequest* navigation_request = frame_tree_node->navigation_request();
- navigation_request->CreateNavigationHandle();
-
if (frame_tree_node->IsMainFrame()) {
// Renderer-initiated main-frame navigations that need to swap processes
// will go to the browser via a OpenURL call, and then be handled by the
@@ -798,62 +833,20 @@ void NavigatorImpl::OnBeginNavigation(
// RenderFrameHost.
DidStartMainFrameNavigation(
common_params.url,
- frame_tree_node->current_frame_host()->GetSiteInstance());
+ frame_tree_node->current_frame_host()->GetSiteInstance(), nullptr);
navigation_data_.reset();
}
+ // For main frames, NavigationHandle will be created after the call to
+ // |DidStartMainFrameNavigation|, so it receives the most up to date pending
+ // entry from the NavigationController.
+ NavigationEntry* pending_entry = controller_->GetPendingEntry();
+ navigation_request->CreateNavigationHandle(
+ pending_entry ? pending_entry->GetUniqueID() : 0);
navigation_request->BeginNavigation();
}
// PlzNavigate
-void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node,
- ResourceResponse* response,
- scoped_ptr<StreamHandle> body) {
- CHECK(IsBrowserSideNavigationEnabled());
-
- NavigationRequest* navigation_request = frame_tree_node->navigation_request();
- DCHECK(navigation_request);
- DCHECK(response ||
- !ShouldMakeNetworkRequestForURL(
- navigation_request->common_params().url));
-
- // HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not
- // commit; they leave the frame showing the previous page.
- if (response && response->head.headers.get() &&
- (response->head.headers->response_code() == 204 ||
- response->head.headers->response_code() == 205)) {
- CancelNavigation(frame_tree_node);
- return;
- }
-
- // Select an appropriate renderer to commit the navigation.
- RenderFrameHostImpl* render_frame_host =
- frame_tree_node->render_manager()->GetFrameHostForNavigation(
- *navigation_request);
-
- // The renderer can exit view source mode when any error or cancellation
- // happen. When reusing the same renderer, overwrite to recover the mode.
- if (navigation_request->is_view_source() &&
- render_frame_host ==
- frame_tree_node->render_manager()->current_frame_host()) {
- DCHECK(!render_frame_host->GetParent());
- render_frame_host->render_view_host()->Send(
- new ViewMsg_EnableViewSourceMode(
- render_frame_host->render_view_host()->GetRoutingID()));
- }
-
- CheckWebUIRendererDoesNotDisplayNormalURL(
- render_frame_host, navigation_request->common_params().url);
-
- navigation_request->TransferNavigationHandleOwnership(render_frame_host);
- render_frame_host->navigation_handle()->ReadyToCommitNavigation(
- render_frame_host, response ? response->head.headers : nullptr);
- render_frame_host->CommitNavigation(response, std::move(body),
- navigation_request->common_params(),
- navigation_request->request_params());
-}
-
-// PlzNavigate
void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node,
bool has_stale_copy_in_cache,
int error_code) {
@@ -862,6 +855,8 @@ void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node,
NavigationRequest* navigation_request = frame_tree_node->navigation_request();
DCHECK(navigation_request);
+ DiscardPendingEntryOnFailureIfNeeded(navigation_request->navigation_handle());
+
// If the request was canceled by the user do not show an error page.
if (error_code == net::ERR_ABORTED) {
frame_tree_node->ResetNavigationRequest(false);
@@ -877,7 +872,7 @@ void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node,
navigation_request->TransferNavigationHandleOwnership(render_frame_host);
render_frame_host->navigation_handle()->ReadyToCommitNavigation(
- render_frame_host, scoped_refptr<net::HttpResponseHeaders>());
+ render_frame_host);
render_frame_host->FailedNavigation(navigation_request->common_params(),
navigation_request->request_params(),
has_stale_copy_in_cache, error_code);
@@ -913,22 +908,6 @@ void NavigatorImpl::LogBeforeUnloadTime(
}
}
-void NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(
- RenderFrameHostImpl* render_frame_host,
- const GURL& url) {
- int enabled_bindings =
- render_frame_host->render_view_host()->GetEnabledBindings();
- bool is_allowed_in_web_ui_renderer =
- WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
- controller_->GetBrowserContext(), url);
- if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) &&
- !is_allowed_in_web_ui_renderer) {
- // Log the URL to help us diagnose any future failures of this CHECK.
- GetContentClient()->SetActiveURL(url);
- CHECK(0);
- }
-}
-
// PlzNavigate
void NavigatorImpl::RequestNavigation(
FrameTreeNode* frame_tree_node,
@@ -937,6 +916,7 @@ void NavigatorImpl::RequestNavigation(
const FrameNavigationEntry& frame_entry,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type,
+ LoFiState lofi_state,
bool is_same_document_history_load,
base::TimeTicks navigation_start) {
CHECK(IsBrowserSideNavigationEnabled());
@@ -948,13 +928,21 @@ void NavigatorImpl::RequestNavigation(
frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload();
FrameMsg_Navigate_Type::Value navigation_type =
GetNavigationType(controller_->GetBrowserContext(), entry, reload_type);
- frame_tree_node->CreatedNavigationRequest(
+ scoped_ptr<NavigationRequest> scoped_request =
NavigationRequest::CreateBrowserInitiated(
frame_tree_node, dest_url, dest_referrer, frame_entry, entry,
- navigation_type, is_same_document_history_load, navigation_start,
- controller_));
- NavigationRequest* navigation_request = frame_tree_node->navigation_request();
- navigation_request->CreateNavigationHandle();
+ navigation_type, lofi_state, is_same_document_history_load,
+ navigation_start, controller_);
+ NavigationRequest* navigation_request = scoped_request.get();
+
+ // For Javascript navigations, do not assign the NavigationRequest to the
+ // FrameTreeNode, as navigating to a Javascript URL should not interrupt a
+ // previous navigation. BeginNavigation will have it commit, and the
+ // scoped_request will be destroyed at the end of this function.
+ if (!dest_url.SchemeIs(url::kJavaScriptScheme))
+ frame_tree_node->CreatedNavigationRequest(std::move(scoped_request));
+
+ navigation_request->CreateNavigationHandle(entry.GetUniqueID());
// Have the current renderer execute its beforeunload event if needed. If it
// is not needed (when beforeunload dispatch is not needed or this navigation
@@ -1026,7 +1014,8 @@ void NavigatorImpl::RecordNavigationMetrics(
void NavigatorImpl::DidStartMainFrameNavigation(
const GURL& url,
- SiteInstanceImpl* site_instance) {
+ SiteInstanceImpl* site_instance,
+ NavigationHandleImpl* navigation_handle) {
// If there is no browser-initiated pending entry for this navigation and it
// is not for the error URL, create a pending entry using the current
// SiteInstance, and ensure the address bar updates accordingly. We don't
@@ -1035,7 +1024,12 @@ void NavigatorImpl::DidStartMainFrameNavigation(
NavigationEntryImpl* pending_entry = controller_->GetPendingEntry();
bool has_browser_initiated_pending_entry =
pending_entry && !pending_entry->is_renderer_initiated();
- if (!has_browser_initiated_pending_entry) {
+
+ // If there is a transient entry, creating a new pending entry will result
+ // in deleting it, which leads to inconsistent state.
+ bool has_transient_entry = !!controller_->GetTransientEntry();
+
+ if (!has_browser_initiated_pending_entry && !has_transient_entry) {
scoped_ptr<NavigationEntryImpl> entry =
NavigationEntryImpl::FromNavigationEntry(
controller_->CreateNavigationEntry(
@@ -1045,16 +1039,65 @@ void NavigatorImpl::DidStartMainFrameNavigation(
entry->set_site_instance(site_instance);
// TODO(creis): If there's a pending entry already, find a safe way to
// update it instead of replacing it and copying over things like this.
+ // That will allow us to skip the NavigationHandle update below as well.
if (pending_entry) {
entry->set_transferred_global_request_id(
pending_entry->transferred_global_request_id());
entry->set_should_replace_entry(pending_entry->should_replace_entry());
entry->SetRedirectChain(pending_entry->GetRedirectChain());
}
+
+ // If there's a current NavigationHandle, update its pending NavEntry ID.
+ // This is necessary for transfer navigations. The handle may be null in
+ // PlzNavigate.
+ if (navigation_handle)
+ navigation_handle->update_entry_id_for_transfer(entry->GetUniqueID());
+
controller_->SetPendingEntry(std::move(entry));
if (delegate_)
delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
}
}
+void NavigatorImpl::DiscardPendingEntryOnFailureIfNeeded(
+ NavigationHandleImpl* handle) {
+ // Racy conditions can cause a fail message to arrive after its corresponding
+ // pending entry has been replaced by another navigation. If
+ // |DiscardPendingEntry| is called in this case, then the completely valid
+ // entry for the new navigation would be discarded. See crbug.com/513742. To
+ // catch this case, the current pending entry is compared against the current
+ // navigation handle's entry id, which should correspond to the failed load.
+ NavigationEntry* pending_entry = controller_->GetPendingEntry();
+ bool pending_matches_fail_msg =
+ handle && pending_entry &&
+ handle->pending_nav_entry_id() == pending_entry->GetUniqueID();
+ if (!pending_matches_fail_msg)
+ return;
+
+ // We usually clear the pending entry when it fails, so that an arbitrary URL
+ // isn't left visible above a committed page. This must be enforced when the
+ // pending entry isn't visible (e.g., renderer-initiated navigations) to
+ // prevent URL spoofs for in-page navigations that don't go through
+ // DidStartProvisionalLoadForFrame.
+ //
+ // However, we do preserve the pending entry in some cases, such as on the
+ // initial navigation of an unmodified blank tab. We also allow the delegate
+ // to say when it's safe to leave aborted URLs in the omnibox, to let the
+ // user edit the URL and try again. This may be useful in cases that the
+ // committed page cannot be attacker-controlled. In these cases, we still
+ // allow the view to clear the pending entry and typed URL if the user
+ // requests (e.g., hitting Escape with focus in the address bar).
+ //
+ // Note: don't touch the transient entry, since an interstitial may exist.
+ bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() ||
+ delegate_->ShouldPreserveAbortedURLs();
+ if (pending_entry != controller_->GetVisibleEntry() ||
+ !should_preserve_entry) {
+ controller_->DiscardPendingEntry(true);
+
+ // Also force the UI to refresh.
+ controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigator_impl.h b/chromium/content/browser/frame_host/navigator_impl.h
index a8907689a6c..da3762fd555 100644
--- a/chromium/content/browser/frame_host/navigator_impl.h
+++ b/chromium/content/browser/frame_host/navigator_impl.h
@@ -13,6 +13,7 @@
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/common/content_export.h"
+#include "content/common/navigation_params.h"
#include "url/gurl.h"
class GURL;
@@ -23,9 +24,6 @@ class NavigationControllerImpl;
class NavigatorDelegate;
class NavigatorTest;
struct LoadCommittedDetails;
-struct CommitNavigationParams;
-struct CommonNavigationParams;
-struct RequestNavigationParams;
// This class is an implementation of Navigator, responsible for managing
// navigations in regular browser tabs.
@@ -34,6 +32,10 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
NavigatorImpl(NavigationControllerImpl* navigation_controller,
NavigatorDelegate* delegate);
+ static void CheckWebUIRendererDoesNotDisplayNormalURL(
+ RenderFrameHostImpl* render_frame_host,
+ const GURL& url);
+
// Navigator implementation.
NavigatorDelegate* GetDelegate() override;
NavigationController* GetController() override;
@@ -68,6 +70,7 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
bool user_gesture) override;
void RequestTransferURL(RenderFrameHostImpl* render_frame_host,
const GURL& url,
+ SiteInstance* source_site_instance,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
ui::PageTransition page_transition,
@@ -78,9 +81,6 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
const CommonNavigationParams& common_params,
const BeginNavigationParams& begin_params,
scoped_refptr<ResourceRequestBody> body) override;
- void CommitNavigation(FrameTreeNode* frame_tree_node,
- ResourceResponse* response,
- scoped_ptr<StreamHandle> body) override;
void FailedNavigation(FrameTreeNode* frame_tree_node,
bool has_stale_copy_in_cache,
int error_code) override;
@@ -110,10 +110,6 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
bool ShouldAssignSiteForURL(const GURL& url);
- void CheckWebUIRendererDoesNotDisplayNormalURL(
- RenderFrameHostImpl* render_frame_host,
- const GURL& url);
-
// PlzNavigate: if needed, sends a BeforeUnload IPC to the renderer to ask it
// to execute the beforeUnload event. Otherwise, the navigation request will
// be started.
@@ -123,6 +119,7 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
const FrameNavigationEntry& frame_entry,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type,
+ LoFiState lofi_state,
bool is_same_document_history_load,
base::TimeTicks navigation_start);
@@ -135,7 +132,12 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
// NavigationEntry if the controller does not currently have a
// browser-initiated one.
void DidStartMainFrameNavigation(const GURL& url,
- SiteInstanceImpl* site_instance);
+ SiteInstanceImpl* site_instance,
+ NavigationHandleImpl* navigation_handle);
+
+ // Called when a navigation has failed to discard the pending entry in order
+ // to avoid url spoofs.
+ void DiscardPendingEntryOnFailureIfNeeded(NavigationHandleImpl* handle);
// The NavigationController that will keep track of session history for all
// RenderFrameHost objects using this NavigatorImpl.
diff --git a/chromium/content/browser/frame_host/navigator_impl_unittest.cc b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
index 28cce0799b7..a8ff15d9df5 100644
--- a/chromium/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
@@ -43,9 +43,8 @@ namespace content {
class NavigatorTestWithBrowserSideNavigation
: public RenderViewHostImplTestHarness {
public:
- // Re-defines the private RenderFrameHostManager::SiteInstanceDescriptor here
- // to allow access to it from tests.
- typedef RenderFrameHostManager::SiteInstanceDescriptor SiteInstanceDescriptor;
+ using SiteInstanceDescriptor = RenderFrameHostManager::SiteInstanceDescriptor;
+ using SiteInstanceRelation = RenderFrameHostManager::SiteInstanceRelation;
void SetUp() override {
#if !defined(OS_ANDROID)
@@ -110,9 +109,10 @@ class NavigatorTestWithBrowserSideNavigation
return message && rfh->GetRoutingID() == message->routing_id();
}
- SiteInstance* ConvertToSiteInstance(RenderFrameHostManager* rfhm,
- const SiteInstanceDescriptor& descriptor,
- SiteInstance* candidate_instance) {
+ scoped_refptr<SiteInstance> ConvertToSiteInstance(
+ RenderFrameHostManager* rfhm,
+ const SiteInstanceDescriptor& descriptor,
+ SiteInstance* candidate_instance) {
return rfhm->ConvertToSiteInstance(descriptor, candidate_instance);
}
};
@@ -151,7 +151,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Commit the navigation.
main_test_rfh()->SendNavigate(0, entry_id, true, kUrl);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_TRUE(main_test_rfh()->is_active());
EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
main_test_rfh()->GetSiteInstance()->GetSiteURL());
EXPECT_EQ(kUrl, contents()->GetLastCommittedURL());
@@ -204,7 +204,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Commit the navigation.
main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_TRUE(main_test_rfh()->is_active());
EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl2),
main_test_rfh()->GetSiteInstance()->GetSiteURL());
EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
@@ -237,19 +237,28 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_FALSE(request->begin_params().has_user_gesture);
EXPECT_EQ(kUrl2, request->common_params().url);
EXPECT_FALSE(request->browser_initiated());
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
// Have the current RenderFrameHost commit the navigation.
scoped_refptr<ResourceResponse> response(new ResourceResponse);
GetLoaderForNavigationRequest(request)
->CallOnResponseStarted(response, MakeEmptyStream());
- EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(
+ DidRenderFrameHostRequestCommit(GetSpeculativeRenderFrameHost(node)));
+ } else {
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ }
EXPECT_TRUE(main_test_rfh()->is_loading());
EXPECT_FALSE(node->navigation_request());
// Commit the navigation.
main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+ EXPECT_TRUE(main_test_rfh()->is_active());
EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
EXPECT_FALSE(node->render_manager()->pending_frame_host());
@@ -447,7 +456,6 @@ TEST_F(NavigatorTestWithBrowserSideNavigation, CrossSiteNavigation) {
// Receive the beforeUnload ACK.
main_test_rfh()->SendBeforeUnloadACK(true);
EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
- EXPECT_FALSE(contents()->CrossProcessNavigationPending());
scoped_refptr<ResourceResponse> response(new ResourceResponse);
GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
@@ -455,7 +463,6 @@ TEST_F(NavigatorTestWithBrowserSideNavigation, CrossSiteNavigation) {
EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh));
EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
- EXPECT_TRUE(contents()->CrossProcessNavigationPending());
speculative_rfh->SendNavigate(0, entry_id, true, kUrl2);
@@ -622,14 +629,24 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Confirm that the first loader got destroyed.
EXPECT_FALSE(loader1);
- // Confirm that the speculative RenderFrameHost was destroyed.
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ // Confirm that the speculative RenderFrameHost was destroyed in the non
+ // SitePerProcess case.
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
// Have the RenderFrameHost commit the navigation.
scoped_refptr<ResourceResponse> response(new ResourceResponse);
GetLoaderForNavigationRequest(request2)
->CallOnResponseStarted(response, MakeEmptyStream());
- EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(
+ DidRenderFrameHostRequestCommit(GetSpeculativeRenderFrameHost(node)));
+ } else {
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ }
// Commit the navigation.
main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
@@ -660,7 +677,11 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_EQ(kUrl1, request1->common_params().url);
EXPECT_FALSE(request1->browser_initiated());
EXPECT_TRUE(request1->begin_params().has_user_gesture);
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
// Now receive a renderer-initiated non-user-initiated request. Nothing should
// change.
@@ -671,13 +692,22 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_EQ(kUrl1, request2->common_params().url);
EXPECT_FALSE(request2->browser_initiated());
EXPECT_TRUE(request2->begin_params().has_user_gesture);
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
// Have the RenderFrameHost commit the navigation.
scoped_refptr<ResourceResponse> response(new ResourceResponse);
GetLoaderForNavigationRequest(request2)
->CallOnResponseStarted(response, MakeEmptyStream());
- EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(
+ DidRenderFrameHostRequestCommit(GetSpeculativeRenderFrameHost(node)));
+ } else {
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ }
// Commit the navigation.
main_test_rfh()->SendNavigate(1, 0, true, kUrl1);
@@ -753,7 +783,11 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_EQ(kUrl1, request1->common_params().url);
EXPECT_FALSE(request1->browser_initiated());
EXPECT_FALSE(request1->begin_params().has_user_gesture);
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
base::WeakPtr<TestNavigationURLLoader> loader1 =
GetLoaderForNavigationRequest(request1)->AsWeakPtr();
EXPECT_TRUE(loader1);
@@ -764,7 +798,11 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_EQ(kUrl2, request2->common_params().url);
EXPECT_FALSE(request2->browser_initiated());
EXPECT_FALSE(request2->begin_params().has_user_gesture);
- EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
+ } else {
+ EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
+ }
// Confirm that the first loader got destroyed.
EXPECT_FALSE(loader1);
@@ -773,7 +811,12 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
scoped_refptr<ResourceResponse> response(new ResourceResponse);
GetLoaderForNavigationRequest(request2)
->CallOnResponseStarted(response, MakeEmptyStream());
- EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ EXPECT_TRUE(
+ DidRenderFrameHostRequestCommit(GetSpeculativeRenderFrameHost(node)));
+ } else {
+ EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
+ }
// Commit the navigation.
main_test_rfh()->SendNavigate(1, 0, true, kUrl2);
@@ -805,11 +848,11 @@ TEST_F(NavigatorTestWithBrowserSideNavigation, Reload) {
EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
// Now do a shift+reload.
- controller().ReloadIgnoringCache(false);
+ controller().ReloadBypassingCache(false);
// A NavigationRequest should have been generated.
main_request = node->navigation_request();
ASSERT_TRUE(main_request != NULL);
- EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE,
+ EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE,
main_request->common_params().navigation_type);
main_test_rfh()->PrepareForCommit();
EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
@@ -930,62 +973,6 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
}
-// PlzNavigate: Verify that a previously swapped out RenderFrameHost is
-// correctly reused when spawning a speculative RenderFrameHost in a navigation
-// using the same SiteInstance.
-TEST_F(NavigatorTestWithBrowserSideNavigation,
- SpeculativeRendererReuseSwappedOutRFH) {
- // This test doesn't make sense in --site-per-process where swapped out
- // RenderFrameHost is no longer used.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden())
- return;
-
- // Navigate to an initial site.
- const GURL kUrl1("http://wikipedia.org/");
- contents()->NavigateAndCommit(kUrl1);
- TestRenderFrameHost* rfh1 = main_test_rfh();
- FrameTreeNode* node = rfh1->frame_tree_node();
- RenderFrameHostManager* rfhm = node->render_manager();
-
- // Increment active frame count to cause the RenderFrameHost to be swapped out
- // (instead of immediately destroyed).
- rfh1->GetSiteInstance()->IncrementActiveFrameCount();
-
- // Navigate to another site to swap out the initial RenderFrameHost.
- const GURL kUrl2("http://chromium.org/");
- contents()->NavigateAndCommit(kUrl2);
- ASSERT_NE(rfh1, main_test_rfh());
- EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
- EXPECT_TRUE(rfhm->IsOnSwappedOutList(rfh1));
-
- // Now go back to the initial site so that the swapped out RenderFrameHost
- // should be reused.
- process()->sink().ClearMessages();
- rfh1->GetProcess()->sink().ClearMessages();
- int entry_id = RequestNavigation(node, kUrl1);
- EXPECT_EQ(rfh1, GetSpeculativeRenderFrameHost(node));
-
- main_test_rfh()->SendBeforeUnloadACK(true);
- EXPECT_EQ(rfh1, GetSpeculativeRenderFrameHost(node));
- EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT,
- GetSpeculativeRenderFrameHost(node)->rfh_state());
-
- scoped_refptr<ResourceResponse> response(new ResourceResponse);
- GetLoaderForNavigationRequest(node->navigation_request())
- ->CallOnResponseStarted(response, MakeEmptyStream());
- EXPECT_EQ(rfh1, GetSpeculativeRenderFrameHost(node));
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT,
- GetSpeculativeRenderFrameHost(node)->rfh_state());
- EXPECT_TRUE(DidRenderFrameHostRequestCommit(rfh1));
- EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
-
- rfh1->SendNavigate(1, entry_id, true, kUrl1);
- EXPECT_EQ(rfh1, main_test_rfh());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
- EXPECT_FALSE(rfhm->IsOnSwappedOutList(rfh1));
-}
-
// PlzNavigate: Verify that data urls are properly handled.
TEST_F(NavigatorTestWithBrowserSideNavigation, DataUrls) {
const GURL kUrl1("http://wikipedia.org/");
@@ -1038,7 +1025,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
main_test_rfh()->frame_tree_node()->render_manager();
{
SiteInstanceDescriptor descriptor(current_instance);
- SiteInstance* converted_instance =
+ scoped_refptr<SiteInstance> converted_instance =
ConvertToSiteInstance(rfhm, descriptor, nullptr);
EXPECT_EQ(current_instance, converted_instance);
}
@@ -1052,7 +1039,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
current_instance->IsRelatedSiteInstance(unrelated_instance.get()));
{
SiteInstanceDescriptor descriptor(unrelated_instance.get());
- SiteInstance* converted_instance =
+ scoped_refptr<SiteInstance> converted_instance =
ConvertToSiteInstance(rfhm, descriptor, nullptr);
EXPECT_EQ(unrelated_instance.get(), converted_instance);
}
@@ -1061,8 +1048,9 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// current one.
GURL kUrlSameSiteAs1("http://www.a.com/foo");
{
- SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs1, true);
- SiteInstance* converted_instance =
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs1,
+ SiteInstanceRelation::RELATED);
+ scoped_refptr<SiteInstance> converted_instance =
ConvertToSiteInstance(rfhm, descriptor, nullptr);
EXPECT_EQ(current_instance, converted_instance);
}
@@ -1072,7 +1060,8 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
GURL kUrlSameSiteAs2("http://www.b.com/foo");
scoped_refptr<SiteInstance> related_instance;
{
- SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2, true);
+ SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2,
+ SiteInstanceRelation::RELATED);
related_instance = ConvertToSiteInstance(rfhm, descriptor, nullptr);
// Should return a new instance, related to the current, set to the new site
// URL.
@@ -1088,7 +1077,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// current one, several times, with and without candidate sites.
{
SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs1,
- false);
+ SiteInstanceRelation::UNRELATED);
scoped_refptr<SiteInstance> converted_instance_1 =
ConvertToSiteInstance(rfhm, descriptor, nullptr);
// Should return a new instance, unrelated to the current one, set to the
@@ -1115,7 +1104,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
converted_instance_2->GetSiteURL());
// Converts once more but with |converted_instance_1| as a candidate.
- SiteInstance* converted_instance_3 =
+ scoped_refptr<SiteInstance> converted_instance_3 =
ConvertToSiteInstance(rfhm, descriptor, converted_instance_1.get());
// Should return |converted_instance_1| because its site matches and it is
// unrelated to the current SiteInstance.
@@ -1126,7 +1115,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// related_instance and using it as a candidate.
{
SiteInstanceDescriptor descriptor(browser_context(), kUrlSameSiteAs2,
- false);
+ SiteInstanceRelation::UNRELATED);
scoped_refptr<SiteInstance> converted_instance_1 =
ConvertToSiteInstance(rfhm, descriptor, related_instance.get());
// Should return a new instance, unrelated to the current, set to the
@@ -1138,7 +1127,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2),
converted_instance_1->GetSiteURL());
- SiteInstance* converted_instance_2 =
+ scoped_refptr<SiteInstance> converted_instance_2 =
ConvertToSiteInstance(rfhm, descriptor, unrelated_instance.get());
// Should return |unrelated_instance| because its site matches and it is
// unrelated to the current SiteInstance.
@@ -1151,6 +1140,7 @@ void SetWithinPage(const GURL& url,
FrameHostMsg_DidCommitProvisionalLoad_Params* params) {
params->was_within_same_page = true;
params->url = url;
+ params->origin = url::Origin(url);
}
}
diff --git a/chromium/content/browser/frame_host/render_frame_host_delegate.cc b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
index 03d9729cac2..b9dca1db897 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
@@ -88,11 +88,4 @@ scoped_ptr<WebUIImpl> RenderFrameHostDelegate::CreateWebUIForRenderFrameHost(
return nullptr;
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible
- RenderFrameHostDelegate::GetParentNativeViewAccessible() {
- return NULL;
-}
-#endif // defined(OS_WIN)
-
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_delegate.h b/chromium/content/browser/frame_host/render_frame_host_delegate.h
index a2a4c599c3a..1cec9c701ab 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.h
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.h
@@ -81,7 +81,6 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
IPC::Message* reply_msg) {}
virtual void RunBeforeUnloadConfirm(RenderFrameHost* render_frame_host,
- const base::string16& message,
bool is_reload,
IPC::Message* reply_msg) {}
@@ -158,7 +157,10 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
virtual void EnterFullscreenMode(const GURL& origin) {}
// Notification that the frame wants to go out of fullscreen mode.
- virtual void ExitFullscreenMode() {}
+ // |will_cause_resize| indicates whether the fullscreen change causes a
+ // view resize. e.g. This will be false when going from tab fullscreen to
+ // browser fullscreen.
+ virtual void ExitFullscreenMode(bool will_cause_resize) {}
// Let the delegate decide whether postMessage should be delivered to
// |target_rfh| from a source frame in the given SiteInstance. This defaults
@@ -184,11 +186,6 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// applies, returns null.
virtual scoped_ptr<WebUIImpl> CreateWebUIForRenderFrameHost(const GURL& url);
-#if defined(OS_WIN)
- // Returns the frame's parent's NativeViewAccessible.
- virtual gfx::NativeViewAccessible GetParentNativeViewAccessible();
-#endif
-
protected:
virtual ~RenderFrameHostDelegate() {}
};
diff --git a/chromium/content/browser/frame_host/render_frame_host_factory.cc b/chromium/content/browser/frame_host/render_frame_host_factory.cc
index d91354bfe33..92a449fa787 100644
--- a/chromium/content/browser/frame_host/render_frame_host_factory.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_factory.cc
@@ -23,15 +23,15 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostFactory::Create(
FrameTreeNode* frame_tree_node,
int32_t routing_id,
int32_t widget_routing_id,
- int flags) {
+ bool hidden) {
if (factory_) {
return factory_->CreateRenderFrameHost(
site_instance, render_view_host, delegate, rwh_delegate, frame_tree,
- frame_tree_node, routing_id, widget_routing_id, flags);
+ frame_tree_node, routing_id, widget_routing_id, hidden);
}
return make_scoped_ptr(new RenderFrameHostImpl(
site_instance, render_view_host, delegate, rwh_delegate, frame_tree,
- frame_tree_node, routing_id, widget_routing_id, flags));
+ frame_tree_node, routing_id, widget_routing_id, hidden));
}
// static
diff --git a/chromium/content/browser/frame_host/render_frame_host_factory.h b/chromium/content/browser/frame_host/render_frame_host_factory.h
index 1b2fdc3aa4b..d6eb4908e16 100644
--- a/chromium/content/browser/frame_host/render_frame_host_factory.h
+++ b/chromium/content/browser/frame_host/render_frame_host_factory.h
@@ -37,7 +37,7 @@ class CONTENT_EXPORT RenderFrameHostFactory {
FrameTreeNode* frame_tree_node,
int32_t routing_id,
int32_t widget_routing_id,
- int flags);
+ bool hidden);
// Returns true if there is currently a globally-registered factory.
static bool has_factory() { return !!factory_; }
@@ -57,7 +57,7 @@ class CONTENT_EXPORT RenderFrameHostFactory {
FrameTreeNode* frame_tree_node,
int32_t routing_id,
int32_t widget_routing_id,
- int flags) = 0;
+ bool hidden) = 0;
// Registers a factory to be called when new RenderFrameHostImpls are created.
// We have only one global factory, so there must be no factory registered
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc
index f0de4ccf8e7..9eb6eaf828a 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/metrics/histogram.h"
@@ -17,6 +18,7 @@
#include "content/browser/accessibility/ax_tree_id_registry.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/bluetooth/web_bluetooth_service_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -34,10 +36,11 @@
#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/geolocation/geolocation_service_context.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/permissions/permission_service_context.h"
#include "content/browser/permissions/permission_service_impl.h"
#include "content/browser/presentation/presentation_service_impl.h"
-#include "content/browser/renderer_host/input/input_router.h"
+#include "content/browser/renderer_host/input/input_router_impl.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
@@ -70,11 +73,13 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_update.h"
+#include "ui/gfx/geometry/quad_f.h"
#include "url/gurl.h"
#if defined(OS_ANDROID)
@@ -131,11 +136,6 @@ base::i18n::TextDirection WebTextDirectionToChromeTextDirection(
} // namespace
// static
-bool RenderFrameHostImpl::IsRFHStateActive(RenderFrameHostImplState rfh_state) {
- return rfh_state == STATE_DEFAULT;
-}
-
-// static
RenderFrameHost* RenderFrameHost::FromID(int render_process_id,
int render_frame_id) {
return RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
@@ -181,7 +181,7 @@ RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
FrameTreeNode* frame_tree_node,
int32_t routing_id,
int32_t widget_routing_id,
- int flags)
+ bool hidden)
: render_view_host_(render_view_host),
delegate_(delegate),
site_instance_(static_cast<SiteInstanceImpl*>(site_instance)),
@@ -192,6 +192,7 @@ RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
frame_tree_node_(frame_tree_node),
render_widget_host_(nullptr),
routing_id_(routing_id),
+ is_waiting_for_swapout_ack_(false),
render_frame_created_(false),
navigations_suspended_(false),
is_waiting_for_beforeunload_ack_(false),
@@ -201,25 +202,20 @@ RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
nav_entry_id_(0),
accessibility_reset_token_(0),
accessibility_reset_count_(0),
+ browser_plugin_embedder_ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
no_create_browser_accessibility_manager_for_testing_(false),
web_ui_type_(WebUI::kNoWebUI),
pending_web_ui_type_(WebUI::kNoWebUI),
should_reuse_web_ui_(false),
+ last_navigation_lofi_state_(LOFI_UNSPECIFIED),
weak_ptr_factory_(this) {
- bool is_swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
- bool hidden = !!(flags & CREATE_RF_HIDDEN);
frame_tree_->AddRenderViewHostRef(render_view_host_);
GetProcess()->AddRoute(routing_id_, this);
g_routing_id_frame_map.Get().insert(std::make_pair(
RenderFrameHostID(GetProcess()->GetID(), routing_id_),
this));
-
- if (is_swapped_out) {
- rfh_state_ = STATE_SWAPPED_OUT;
- } else {
- rfh_state_ = STATE_DEFAULT;
- GetSiteInstance()->IncrementActiveFrameCount();
- }
+ site_instance_->AddObserver(this);
+ GetSiteInstance()->IncrementActiveFrameCount();
// New child frames should inherit the nav_entry_id of their parent.
if (frame_tree_node_->parent()) {
@@ -246,6 +242,9 @@ RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
} else {
DCHECK(!render_widget_host_->owned_by_render_frame_host());
}
+ InputRouterImpl* ir =
+ static_cast<InputRouterImpl*>(render_widget_host_->input_router());
+ ir->SetFrameTreeNodeId(frame_tree_node_->frame_tree_node_id());
}
}
@@ -258,21 +257,21 @@ RenderFrameHostImpl::~RenderFrameHostImpl() {
g_routing_id_frame_map.Get().erase(
RenderFrameHostID(GetProcess()->GetID(), routing_id_));
+ site_instance_->RemoveObserver(this);
+
if (delegate_ && render_frame_created_)
delegate_->RenderFrameDeleted(this);
- bool is_active = IsRFHStateActive(rfh_state_);
-
// If this RenderFrameHost is swapped out, it already decremented the active
// frame count of the SiteInstance it belongs to.
- if (is_active)
+ if (is_active())
GetSiteInstance()->DecrementActiveFrameCount();
// If this RenderFrameHost is swapping with a RenderFrameProxyHost, the
// RenderFrame will already be deleted in the renderer process. Main frame
// RenderFrames will be cleaned up as part of deleting its RenderView. In all
// other cases, the RenderFrame should be cleaned up (if it exists).
- if (is_active && !frame_tree_node_->IsMainFrame() && render_frame_created_)
+ if (is_active() && !frame_tree_node_->IsMainFrame() && render_frame_created_)
Send(new FrameMsg_Delete(routing_id_));
// NULL out the swapout timer; in crash dumps this member will be null only if
@@ -311,7 +310,7 @@ RenderProcessHost* RenderFrameHostImpl::GetProcess() {
return process_;
}
-RenderFrameHost* RenderFrameHostImpl::GetParent() {
+RenderFrameHostImpl* RenderFrameHostImpl::GetParent() {
FrameTreeNode* parent_node = frame_tree_node_->parent();
if (!parent_node)
return NULL;
@@ -334,8 +333,8 @@ bool RenderFrameHostImpl::IsCrossProcessSubframe() {
parent_node->current_frame_host()->GetSiteInstance();
}
-GURL RenderFrameHostImpl::GetLastCommittedURL() {
- return frame_tree_node_->current_url();
+const GURL& RenderFrameHostImpl::GetLastCommittedURL() {
+ return last_committed_url();
}
url::Origin RenderFrameHostImpl::GetLastCommittedOrigin() {
@@ -459,22 +458,9 @@ bool RenderFrameHostImpl::Send(IPC::Message* message) {
}
bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
- // Filter out most IPC messages if this frame is swapped out.
- // We still want to handle certain ACKs to keep our state consistent.
- if (is_swapped_out()) {
- if (!SwappedOutMessages::CanHandleWhileSwappedOut(msg)) {
- // If this is a synchronous message and we decided not to handle it,
- // we must send an error reply, or else the renderer will be stuck
- // and won't respond to future requests.
- if (msg.is_sync()) {
- IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
- reply->set_reply_error();
- Send(reply);
- }
- // Don't continue looking for someone to handle it.
- return true;
- }
- }
+ // Only process messages if the RenderFrame is alive.
+ if (!render_frame_created_)
+ return false;
// This message map is for handling internal IPC messages which should not
// be dispatched to other objects.
@@ -513,7 +499,6 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnDidFailLoadWithError)
IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad,
OnDidCommitProvisionalLoad(msg))
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidDropNavigation, OnDidDropNavigation)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateState, OnUpdateState)
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted,
@@ -535,6 +520,8 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeName, OnDidChangeName)
IPC_MESSAGE_HANDLER(FrameHostMsg_EnforceStrictMixedContentChecking,
OnEnforceStrictMixedContentChecking)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateToUniqueOrigin,
+ OnUpdateToUniqueOrigin)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidAssignPageId, OnDidAssignPageId)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeSandboxFlags,
OnDidChangeSandboxFlags)
@@ -552,6 +539,8 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnAccessibilityLocationChanges)
IPC_MESSAGE_HANDLER(AccessibilityHostMsg_FindInPageResult,
OnAccessibilityFindInPageResult)
+ IPC_MESSAGE_HANDLER(AccessibilityHostMsg_ChildFrameHitTestResult,
+ OnAccessibilityChildFrameHitTestResult)
IPC_MESSAGE_HANDLER(AccessibilityHostMsg_SnapshotResponse,
OnAccessibilitySnapshotResponse)
IPC_MESSAGE_HANDLER(FrameHostMsg_ToggleFullscreen, OnToggleFullscreen)
@@ -606,7 +595,7 @@ void RenderFrameHostImpl::AccessibilitySetSelection(int anchor_object_id,
int focus_object_id,
int focus_offset) {
Send(new AccessibilityMsg_SetSelection(routing_id_,
- focus_object_id,
+ anchor_object_id,
anchor_offset,
focus_object_id,
focus_offset));
@@ -640,6 +629,25 @@ gfx::Point RenderFrameHostImpl::AccessibilityOriginInScreen(
return gfx::Point();
}
+gfx::Rect RenderFrameHostImpl::AccessibilityTransformToRootCoordSpace(
+ const gfx::Rect& bounds) {
+ RenderWidgetHostViewBase* view =
+ static_cast<RenderWidgetHostViewBase*>(GetView());
+ gfx::Point p1 = view->TransformPointToRootCoordSpace(bounds.origin());
+ gfx::Point p2 = view->TransformPointToRootCoordSpace(bounds.top_right());
+ gfx::Point p3 = view->TransformPointToRootCoordSpace(bounds.bottom_right());
+ gfx::Point p4 = view->TransformPointToRootCoordSpace(bounds.bottom_left());
+ gfx::QuadF transformed_quad = gfx::QuadF(
+ gfx::PointF(p1), gfx::PointF(p2), gfx::PointF(p3), gfx::PointF(p4));
+ gfx::RectF new_bounds = transformed_quad.BoundingBox();
+ return gfx::Rect(new_bounds.x(), new_bounds.y(),
+ new_bounds.width(), new_bounds.height());
+}
+
+SiteInstance* RenderFrameHostImpl::AccessibilityGetSiteInstance() {
+ return GetSiteInstance();
+}
+
void RenderFrameHostImpl::AccessibilityHitTest(const gfx::Point& point) {
Send(new AccessibilityMsg_HitTest(routing_id_, point));
}
@@ -670,6 +678,14 @@ void RenderFrameHostImpl::AccessibilityFatalError() {
gfx::AcceleratedWidget
RenderFrameHostImpl::AccessibilityGetAcceleratedWidget() {
+ // Only the main frame's current frame host is connected to the native
+ // widget tree for accessibility, so return null if this is queried on
+ // any other frame.
+ if (frame_tree_node()->parent() ||
+ frame_tree_node()->current_frame_host() != this) {
+ return gfx::kNullAcceleratedWidget;
+ }
+
RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
render_view_host_->GetWidget()->GetView());
if (view)
@@ -686,6 +702,13 @@ gfx::NativeViewAccessible
return NULL;
}
+void RenderFrameHostImpl::RenderProcessGone(SiteInstanceImpl* site_instance) {
+ DCHECK_EQ(site_instance_.get(), site_instance);
+
+ // The renderer process is gone, so this frame can no longer be loading.
+ ResetLoadingState();
+}
+
bool RenderFrameHostImpl::CreateRenderFrame(int proxy_routing_id,
int opener_routing_id,
int parent_routing_id,
@@ -709,6 +732,16 @@ bool RenderFrameHostImpl::CreateRenderFrame(int proxy_routing_id,
params.parent_routing_id = parent_routing_id;
params.previous_sibling_routing_id = previous_sibling_routing_id;
params.replication_state = frame_tree_node()->current_replication_state();
+
+ // Normally, the replication state contains effective sandbox flags,
+ // excluding flags that were updated but have not taken effect. However, a
+ // new RenderFrame should use the pending sandbox flags, since it is being
+ // created as part of the navigation that will commit these flags. (I.e., the
+ // RenderFrame needs to know the flags to use when initializing the new
+ // document once it commits).
+ params.replication_state.sandbox_flags =
+ frame_tree_node()->pending_sandbox_flags();
+
params.frame_owner_properties = frame_tree_node()->frame_owner_properties();
if (render_widget_host_) {
@@ -769,9 +802,7 @@ void RenderFrameHostImpl::SetRenderFrameCreated(bool created) {
}
void RenderFrameHostImpl::Init() {
- // TODO(csharrison): Call GetProcess()->ResumeRequestsForFrame(routing_id_)
- // once ResourceDispatcherHostImpl is keyed on render frame routing ids
- // instead of render view routing ids.
+ ResourceDispatcherHost::ResumeBlockedRequestsForFrameFromUI(this);
}
void RenderFrameHostImpl::OnAddMessageToConsole(
@@ -804,18 +835,21 @@ void RenderFrameHostImpl::OnCreateChildFrame(
int new_routing_id,
blink::WebTreeScopeType scope,
const std::string& frame_name,
+ const std::string& frame_unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) {
+ // TODO(lukasza): Call ReceivedBadMessage when |frame_unique_name| is empty.
+ DCHECK(!frame_unique_name.empty());
+
// It is possible that while a new RenderFrameHost was committed, the
// RenderFrame corresponding to this host sent an IPC message to create a
// frame and it is delivered after this host is swapped out.
// Ignore such messages, as we know this RenderFrameHost is going away.
- if (rfh_state_ != RenderFrameHostImpl::STATE_DEFAULT ||
- frame_tree_node_->current_frame_host() != this)
+ if (!is_active() || frame_tree_node_->current_frame_host() != this)
return;
frame_tree_->AddFrame(frame_tree_node_, GetProcess()->GetID(), new_routing_id,
- scope, frame_name, sandbox_flags,
+ scope, frame_name, frame_unique_name, sandbox_flags,
frame_owner_properties);
}
@@ -963,6 +997,15 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// Kills the process.
bad_message::ReceivedBadMessage(process,
bad_message::RFH_CAN_COMMIT_URL_BLOCKED);
+ return;
+ }
+
+ // Verify that the origin passed from the renderer process is valid and can
+ // be allowed to commit in this RenderFrameHost.
+ if (!CanCommitOrigin(validated_params.origin, validated_params.url)) {
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RFH_INVALID_ORIGIN_ON_COMMIT);
+ return;
}
// Without this check, an evil renderer can trick the browser into creating
@@ -993,8 +1036,30 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// commit as a new navigation. This can happen if an ongoing slow
// same-process navigation is interrupted by a synchronous renderer-initiated
// navigation.
+ // TODO(csharrison): Data navigations loaded with LoadDataWithBaseURL get
+ // reset here, because the NavigationHandle tracks the URL but the
+ // validated_params.url tracks the data. The trick of saving the old entry ids
+ // for these navigations should go away when this is properly handled. See
+ // crbug.com/588317.
+ int entry_id_for_data_nav = 0;
if (navigation_handle_ &&
- navigation_handle_->GetURL() != validated_params.url) {
+ (navigation_handle_->GetURL() != validated_params.url)) {
+ // Make sure that the pending entry was really loaded via
+ // LoadDataWithBaseURL and that it matches this handle.
+ NavigationEntry* pending_entry =
+ frame_tree_node()->navigator()->GetController()->GetPendingEntry();
+ bool pending_entry_matches_handle =
+ pending_entry &&
+ pending_entry->GetUniqueID() ==
+ navigation_handle_->pending_nav_entry_id();
+ // TODO(csharrison): The pending entry's base url should equal
+ // |validated_params.base_url|. This is not the case for loads with invalid
+ // base urls.
+ if (navigation_handle_->GetURL() == validated_params.base_url &&
+ pending_entry_matches_handle &&
+ !pending_entry->GetBaseURLForDataURL().is_empty()) {
+ entry_id_for_data_nav = navigation_handle_->pending_nav_entry_id();
+ }
navigation_handle_.reset();
}
@@ -1002,8 +1067,25 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// DidCommitProvisionalLoad IPC without a prior DidStartProvisionalLoad
// message.
if (!navigation_handle_) {
+ // There is no pending NavigationEntry in these cases, so pass 0 as the
+ // nav_id. If the previous handle was a prematurely aborted navigation
+ // loaded via LoadDataWithBaseURL, propogate the entry id.
navigation_handle_ = NavigationHandleImpl::Create(
- validated_params.url, frame_tree_node_, base::TimeTicks::Now());
+ validated_params.url, frame_tree_node_,
+ true, // is_synchronous
+ validated_params.is_srcdoc, base::TimeTicks::Now(),
+ entry_id_for_data_nav);
+ // PlzNavigate
+ if (IsBrowserSideNavigationEnabled()) {
+ // PlzNavigate: synchronous loads happen in the renderer, and the browser
+ // has not been notified about the start of the load yet. Do it now.
+ if (!is_loading()) {
+ bool was_loading = frame_tree_node()->frame_tree()->IsLoading();
+ is_loading_ = true;
+ frame_tree_node()->DidStartLoading(true, was_loading);
+ }
+ pending_commit_ = false;
+ }
}
accessibility_reset_count_ = 0;
@@ -1021,19 +1103,6 @@ void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
RenderWidgetHostImpl::From(GetView()->GetRenderWidgetHost())
->StartNewContentRenderingTimeout();
}
-
- // PlzNavigate
- if (IsBrowserSideNavigationEnabled())
- pending_commit_ = false;
-}
-
-void RenderFrameHostImpl::OnDidDropNavigation() {
- // At the end of Navigate(), the FrameTreeNode's DidStartLoading is called to
- // force the spinner to start, even if the renderer didn't yet begin the load.
- // If it turns out that the renderer dropped the navigation, the spinner needs
- // to be turned off.
- frame_tree_node_->DidStopLoading();
- navigation_handle_.reset();
}
void RenderFrameHostImpl::OnUpdateState(const PageState& state) {
@@ -1067,6 +1136,10 @@ RenderWidgetHostView* RenderFrameHostImpl::GetView() {
return nullptr;
}
+GlobalFrameRoutingId RenderFrameHostImpl::GetGlobalFrameRoutingId() {
+ return GlobalFrameRoutingId(GetProcess()->GetID(), GetRoutingID());
+}
+
int RenderFrameHostImpl::GetEnabledBindings() {
return render_view_host_->GetEnabledBindings();
}
@@ -1107,9 +1180,9 @@ void RenderFrameHostImpl::SwapOut(
// to be fixed when RenderViewHostImpl::OnSwapOut moves to RenderFrameHost.
TRACE_EVENT_ASYNC_BEGIN0("navigation", "RenderFrameHostImpl::SwapOut", this);
- // If this RenderFrameHost is not in the default state, it must have already
+ // If this RenderFrameHost is already pending deletion, it must have already
// gone through this, therefore just return.
- if (rfh_state_ != RenderFrameHostImpl::STATE_DEFAULT) {
+ if (!is_active()) {
NOTREACHED() << "RFH should be in default state when calling SwapOut.";
return;
}
@@ -1131,9 +1204,16 @@ void RenderFrameHostImpl::SwapOut(
replication_state));
}
- // If this is the last active frame in the SiteInstance, the SetState call
- // below will trigger the deletion of the SiteInstance's proxies.
- SetState(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT);
+ // TODO(nasko): If the frame is not live, the RFH should just be deleted by
+ // simulating the receipt of swap out ack.
+ is_waiting_for_swapout_ack_ = true;
+ if (frame_tree_node_->IsMainFrame())
+ render_view_host_->set_is_active(false);
+
+ // If this is the last active frame in the SiteInstance, the
+ // DecrementActiveFrameCount call will trigger the deletion of the
+ // SiteInstance's proxies.
+ GetSiteInstance()->DecrementActiveFrameCount();
if (!GetParent())
delegate_->SwappedOut(this);
@@ -1233,7 +1313,7 @@ void RenderFrameHostImpl::OnBeforeUnloadACK(
bool RenderFrameHostImpl::IsWaitingForUnloadACK() const {
return render_view_host_->is_waiting_for_close_ack_ ||
- rfh_state_ == STATE_PENDING_SWAP_OUT;
+ is_waiting_for_swapout_ack_;
}
void RenderFrameHostImpl::OnSwapOutACK() {
@@ -1251,11 +1331,7 @@ void RenderFrameHostImpl::OnRenderProcessGone(int status, int exit_code) {
// Reset frame tree state associated with this process. This must happen
// before RenderViewTerminated because observers expect the subframes of any
// affected frames to be cleared first.
- // Note: When a RenderFrameHost is swapped out there is a different one
- // which is the current host. In this case, the FrameTreeNode state must
- // not be reset.
- if (!is_swapped_out())
- frame_tree_node_->ResetForNewProcess();
+ frame_tree_node_->ResetForNewProcess();
// Reset state for the current RenderFrameHost once the FrameTreeNode has been
// reset.
@@ -1268,6 +1344,12 @@ void RenderFrameHostImpl::OnRenderProcessGone(int status, int exit_code) {
iter.second.Run(ui::AXTreeUpdate());
ax_tree_snapshot_callbacks_.clear();
+ // If the process has died, we don't need to wait for the swap out ack from
+ // this RenderFrame if it is pending deletion. Complete the swap out to
+ // destroy it.
+ if (!is_active())
+ OnSwappedOut();
+
// Note: don't add any more code at this point in the function because
// |this| may be deleted. Any additional cleanup should happen before
// the last block of code here.
@@ -1275,7 +1357,7 @@ void RenderFrameHostImpl::OnRenderProcessGone(int status, int exit_code) {
void RenderFrameHostImpl::OnSwappedOut() {
// Ignore spurious swap out ack.
- if (rfh_state_ != STATE_PENDING_SWAP_OUT)
+ if (!is_waiting_for_swapout_ack_)
return;
TRACE_EVENT_ASYNC_END0("navigation", "RenderFrameHostImpl::SwapOut", this);
@@ -1284,21 +1366,19 @@ void RenderFrameHostImpl::OnSwappedOut() {
ClearAllWebUI();
// If this is a main frame RFH that's about to be deleted, update its RVH's
- // swapped-out state here, since SetState won't be called once this RFH is
- // deleted below. https://crbug.com/505887
- if (frame_tree_node_->IsMainFrame() &&
- frame_tree_node_->render_manager()->IsPendingDeletion(this)) {
+ // swapped-out state here. https://crbug.com/505887
+ if (frame_tree_node_->IsMainFrame()) {
render_view_host_->set_is_active(false);
render_view_host_->set_is_swapped_out(true);
}
- if (frame_tree_node_->render_manager()->DeleteFromPendingList(this)) {
- // We are now deleted.
- return;
- }
+ bool deleted =
+ frame_tree_node_->render_manager()->DeleteFromPendingList(this);
+ CHECK(deleted);
+}
- // If this RFH wasn't pending deletion, then it is now swapped out.
- SetState(RenderFrameHostImpl::STATE_SWAPPED_OUT);
+void RenderFrameHostImpl::ResetSwapOutTimerForTesting() {
+ swapout_event_monitor_timeout_->Stop();
}
void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) {
@@ -1317,9 +1397,9 @@ void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) {
// It is necessary to transform the coordinates to account for nested
// RenderWidgetHosts, such as with out-of-process iframes.
gfx::Point original_point(validated_params.x, validated_params.y);
- gfx::Point transformed_point = original_point;
- static_cast<RenderWidgetHostViewBase*>(GetView())
- ->TransformPointToRootCoordSpace(original_point, &transformed_point);
+ gfx::Point transformed_point =
+ static_cast<RenderWidgetHostViewBase*>(GetView())
+ ->TransformPointToRootCoordSpace(original_point);
validated_params.x = transformed_point.x();
validated_params.y = transformed_point.y();
@@ -1371,20 +1451,19 @@ void RenderFrameHostImpl::OnRunJavaScriptMessage(
void RenderFrameHostImpl::OnRunBeforeUnloadConfirm(
const GURL& frame_url,
- const base::string16& message,
bool is_reload,
IPC::Message* reply_msg) {
// While a JS beforeunload dialog is showing, tabs in the same process
// shouldn't process input events.
GetProcess()->SetIgnoreInputEvents(true);
render_view_host_->GetWidget()->StopHangMonitorTimeout();
- delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg);
+ delegate_->RunBeforeUnloadConfirm(this, is_reload, reply_msg);
}
void RenderFrameHostImpl::OnTextSurroundingSelectionResponse(
const base::string16& content,
- size_t start_offset,
- size_t end_offset) {
+ uint32_t start_offset,
+ uint32_t end_offset) {
render_view_host_->OnTextSurroundingSelectionResponse(
content, start_offset, end_offset);
}
@@ -1398,9 +1477,15 @@ void RenderFrameHostImpl::OnDidChangeOpener(int32_t opener_routing_id) {
GetSiteInstance());
}
-void RenderFrameHostImpl::OnDidChangeName(const std::string& name) {
+void RenderFrameHostImpl::OnDidChangeName(const std::string& name,
+ const std::string& unique_name) {
+ if (GetParent() != nullptr) {
+ // TODO(lukasza): Call ReceivedBadMessage when |unique_name| is empty.
+ DCHECK(!unique_name.empty());
+ }
+
std::string old_name = frame_tree_node()->frame_name();
- frame_tree_node()->SetFrameName(name);
+ frame_tree_node()->SetFrameName(name, unique_name);
if (old_name.empty() && !name.empty())
frame_tree_node_->render_manager()->CreateProxiesForNewNamedFrame();
delegate_->DidChangeName(this, name);
@@ -1410,6 +1495,14 @@ void RenderFrameHostImpl::OnEnforceStrictMixedContentChecking() {
frame_tree_node()->SetEnforceStrictMixedContentChecking(true);
}
+void RenderFrameHostImpl::OnUpdateToUniqueOrigin(
+ bool is_potentially_trustworthy_unique_origin) {
+ url::Origin origin;
+ DCHECK(origin.unique());
+ frame_tree_node()->SetCurrentOrigin(origin,
+ is_potentially_trustworthy_unique_origin);
+}
+
void RenderFrameHostImpl::OnDidAssignPageId(int32_t page_id) {
// Update the RVH's current page ID so that future IPCs from the renderer
// correspond to the new page.
@@ -1441,7 +1534,7 @@ void RenderFrameHostImpl::OnDidChangeSandboxFlags(
if (!child)
return;
- child->set_sandbox_flags(flags);
+ child->SetPendingSandboxFlags(flags);
// Notify the RenderFrame if it lives in a different process from its
// parent. The frame's proxies in other processes also need to learn about
@@ -1550,8 +1643,7 @@ void RenderFrameHostImpl::OnAccessibilityEvents(
RenderWidgetHostViewBase* view = GetViewForAccessibility();
AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
- if ((accessibility_mode != AccessibilityModeOff) && view &&
- RenderFrameHostImpl::IsRFHStateActive(rfh_state())) {
+ if ((accessibility_mode != AccessibilityModeOff) && view && is_active()) {
if (accessibility_mode & AccessibilityModeFlagPlatform)
GetOrCreateBrowserAccessibilityManager();
@@ -1565,8 +1657,8 @@ void RenderFrameHostImpl::OnAccessibilityEvents(
detail.ax_tree_id = GetAXTreeID();
if (param.update.has_tree_data) {
detail.update.has_tree_data = true;
- AXContentTreeDataToAXTreeData(param.update.tree_data,
- &detail.update.tree_data);
+ ax_content_tree_data_ = param.update.tree_data;
+ AXContentTreeDataToAXTreeData(&detail.update.tree_data);
}
detail.update.node_id_to_clear = param.update.node_id_to_clear;
detail.update.nodes.resize(param.update.nodes.size());
@@ -1605,7 +1697,7 @@ void RenderFrameHostImpl::OnAccessibilityEvents(
CHECK(ax_tree_for_testing_->Unserialize(detail.update))
<< ax_tree_for_testing_->error();
}
- accessibility_testing_callback_.Run(detail.event_type, detail.id);
+ accessibility_testing_callback_.Run(this, detail.event_type, detail.id);
}
}
}
@@ -1621,7 +1713,7 @@ void RenderFrameHostImpl::OnAccessibilityLocationChanges(
RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
render_view_host_->GetWidget()->GetView());
- if (view && RenderFrameHostImpl::IsRFHStateActive(rfh_state())) {
+ if (view && is_active()) {
AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
if (accessibility_mode & AccessibilityModeFlagPlatform) {
BrowserAccessibilityManager* manager =
@@ -1647,6 +1739,15 @@ void RenderFrameHostImpl::OnAccessibilityFindInPageResult(
}
}
+void RenderFrameHostImpl::OnAccessibilityChildFrameHitTestResult(
+ const gfx::Point& point,
+ int hit_obj_id) {
+ if (browser_accessibility_manager_) {
+ browser_accessibility_manager_->OnChildFrameHitTestResult(point,
+ hit_obj_id);
+ }
+}
+
void RenderFrameHostImpl::OnAccessibilitySnapshotResponse(
int callback_id,
const AXContentTreeUpdate& snapshot) {
@@ -1659,8 +1760,8 @@ void RenderFrameHostImpl::OnAccessibilitySnapshotResponse(
&dst_snapshot.nodes[i]);
}
if (snapshot.has_tree_data) {
- AXContentTreeDataToAXTreeData(snapshot.tree_data,
- &dst_snapshot.tree_data);
+ ax_content_tree_data_ = snapshot.tree_data;
+ AXContentTreeDataToAXTreeData(&dst_snapshot.tree_data);
dst_snapshot.has_tree_data = true;
}
it->second.Run(dst_snapshot);
@@ -1672,9 +1773,9 @@ void RenderFrameHostImpl::OnAccessibilitySnapshotResponse(
void RenderFrameHostImpl::OnToggleFullscreen(bool enter_fullscreen) {
if (enter_fullscreen)
- delegate_->EnterFullscreenMode(GetLastCommittedURL().GetOrigin());
+ delegate_->EnterFullscreenMode(last_committed_url().GetOrigin());
else
- delegate_->ExitFullscreenMode();
+ delegate_->ExitFullscreenMode(/* will_cause_resize */ true);
// The previous call might change the fullscreen state. We need to make sure
// the renderer is aware of that, which is done via the resize message.
@@ -1682,23 +1783,20 @@ void RenderFrameHostImpl::OnToggleFullscreen(bool enter_fullscreen) {
}
void RenderFrameHostImpl::OnDidStartLoading(bool to_different_document) {
- // Any main frame load to a new document should reset the load since it will
- // replace the current page and any frames.
- if (to_different_document && !GetParent())
- is_loading_ = false;
-
- // This method should never be called when the frame is loading.
- // Unfortunately, it can happen if a history navigation happens during a
- // BeforeUnload or Unload event.
- // TODO(fdegans): Change this to a DCHECK after LoadEventProgress has been
- // refactored in Blink. See crbug.com/466089
- if (is_loading_) {
- LOG(WARNING) << "OnDidStartLoading was called twice.";
+ if (IsBrowserSideNavigationEnabled() && to_different_document) {
+ bad_message::ReceivedBadMessage(GetProcess(),
+ bad_message::RFH_UNEXPECTED_LOAD_START);
return;
}
-
- frame_tree_node_->DidStartLoading(to_different_document);
+ bool was_previously_loading = frame_tree_node_->frame_tree()->IsLoading();
is_loading_ = true;
+
+ // Only inform the FrameTreeNode of a change in load state if the load state
+ // of this RenderFrameHost is being tracked.
+ if (is_active()) {
+ frame_tree_node_->DidStartLoading(to_different_document,
+ was_previously_loading);
+ }
}
void RenderFrameHostImpl::OnDidStopLoading() {
@@ -1713,8 +1811,12 @@ void RenderFrameHostImpl::OnDidStopLoading() {
}
is_loading_ = false;
- frame_tree_node_->DidStopLoading();
navigation_handle_.reset();
+
+ // Only inform the FrameTreeNode of a change in load state if the load state
+ // of this RenderFrameHost is being tracked.
+ if (is_active())
+ frame_tree_node_->DidStopLoading();
}
void RenderFrameHostImpl::OnDidChangeLoadProgress(double load_progress) {
@@ -1735,13 +1837,15 @@ void RenderFrameHostImpl::OnShowPopup(
RenderViewHostDelegateView* view =
render_view_host_->delegate_->GetDelegateView();
if (view) {
- view->ShowPopupMenu(this,
- params.bounds,
- params.item_height,
- params.item_font_size,
- params.selected_item,
- params.popup_items,
- params.right_aligned,
+ gfx::Point original_point(params.bounds.x(), params.bounds.y());
+ gfx::Point transformed_point =
+ static_cast<RenderWidgetHostViewBase*>(GetView())
+ ->TransformPointToRootCoordSpace(original_point);
+ gfx::Rect transformed_bounds(transformed_point.x(), transformed_point.y(),
+ params.bounds.width(), params.bounds.height());
+ view->ShowPopupMenu(this, transformed_bounds, params.item_height,
+ params.item_font_size, params.selected_item,
+ params.popup_items, params.right_aligned,
params.allow_multiple_selection);
}
}
@@ -1761,11 +1865,17 @@ void RenderFrameHostImpl::RegisterMojoServices() {
// TODO(creis): Bind process ID here so that GeolocationServiceImpl
// can perform permissions checks once site isolation is complete.
// crbug.com/426384
- GetServiceRegistry()->AddService<GeolocationService>(
+ // NOTE: At shutdown, there is no guaranteed ordering between destruction of
+ // this object and destruction of any GeolocationServicesImpls created via
+ // the below service registry, the reason being that the destruction of the
+ // latter is triggered by receiving a message that the pipe was closed from
+ // the renderer side. Hence, supply the reference to this object as a weak
+ // pointer.
+ GetServiceRegistry()->AddService(
base::Bind(&GeolocationServiceContext::CreateService,
base::Unretained(geolocation_service_context),
base::Bind(&RenderFrameHostImpl::DidUseGeolocationPermission,
- base::Unretained(this))));
+ weak_ptr_factory_.GetWeakPtr())));
}
WakeLockServiceContext* wake_lock_service_context =
@@ -1774,7 +1884,7 @@ void RenderFrameHostImpl::RegisterMojoServices() {
// WakeLockServiceContext is owned by WebContentsImpl so it will outlive
// this RenderFrameHostImpl, hence a raw pointer can be bound to service
// factory callback.
- GetServiceRegistry()->AddService<WakeLockService>(
+ GetServiceRegistry()->AddService<mojom::WakeLockService>(
base::Bind(&WakeLockServiceContext::CreateService,
base::Unretained(wake_lock_service_context),
GetProcess()->GetID(), GetRoutingID()));
@@ -1783,18 +1893,29 @@ void RenderFrameHostImpl::RegisterMojoServices() {
if (!permission_service_context_)
permission_service_context_.reset(new PermissionServiceContext(this));
- GetServiceRegistry()->AddService<PermissionService>(
+ GetServiceRegistry()->AddService(
base::Bind(&PermissionServiceContext::CreateService,
base::Unretained(permission_service_context_.get())));
- GetServiceRegistry()->AddService<presentation::PresentationService>(
- base::Bind(&PresentationServiceImpl::CreateMojoService,
- base::Unretained(this)));
+ GetServiceRegistry()->AddService(base::Bind(
+ &PresentationServiceImpl::CreateMojoService, base::Unretained(this)));
+
+ bool enable_web_bluetooth = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableWebBluetooth);
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+ enable_web_bluetooth = true;
+#endif
+
+ if (enable_web_bluetooth) {
+ GetServiceRegistry()->AddService(
+ base::Bind(&RenderFrameHostImpl::CreateWebBluetoothService,
+ base::Unretained(this)));
+ }
if (!frame_mojo_shell_)
frame_mojo_shell_.reset(new FrameMojoShell(this));
- GetServiceRegistry()->AddService<mojo::Shell>(base::Bind(
+ GetServiceRegistry()->AddService<mojo::shell::mojom::Connector>(base::Bind(
&FrameMojoShell::BindRequest, base::Unretained(frame_mojo_shell_.get())));
#if defined(ENABLE_WEBVR)
@@ -1802,8 +1923,7 @@ void RenderFrameHostImpl::RegisterMojoServices() {
*base::CommandLine::ForCurrentProcess();
if (browser_command_line.HasSwitch(switches::kEnableWebVR)) {
- GetServiceRegistry()->AddService<VRService>(
- base::Bind(&VRDeviceManager::BindRequest));
+ GetServiceRegistry()->AddService(base::Bind(&VRDeviceManager::BindRequest));
}
#endif
@@ -1811,43 +1931,26 @@ void RenderFrameHostImpl::RegisterMojoServices() {
GetServiceRegistry(), this);
}
-void RenderFrameHostImpl::SetState(RenderFrameHostImplState rfh_state) {
- // Only main frames should be swapped out and retained inside a proxy host.
- if (rfh_state == STATE_SWAPPED_OUT)
- CHECK(!GetParent());
+void RenderFrameHostImpl::ResetWaitingState() {
+ DCHECK(is_active());
- // We update the number of RenderFrameHosts in a SiteInstance when the swapped
- // out status of a RenderFrameHost gets flipped to/from active.
- if (!IsRFHStateActive(rfh_state_) && IsRFHStateActive(rfh_state))
- GetSiteInstance()->IncrementActiveFrameCount();
- else if (IsRFHStateActive(rfh_state_) && !IsRFHStateActive(rfh_state))
- GetSiteInstance()->DecrementActiveFrameCount();
-
- // The active and swapped out state of the RVH is determined by its main
- // frame, since subframes should have their own widgets.
+ // The active state of the RVH is determined by its main frame, since
+ // subframes should have their own widgets.
if (frame_tree_node_->IsMainFrame()) {
- render_view_host_->set_is_active(IsRFHStateActive(rfh_state));
- render_view_host_->set_is_swapped_out(rfh_state == STATE_SWAPPED_OUT);
- }
-
- // Whenever we change the RFH state to and from active or swapped out state,
- // we should not be waiting for beforeunload or close acks. We clear them
- // here to be safe, since they can cause navigations to be ignored in
- // OnDidCommitProvisionalLoad.
- // TODO(creis): Move is_waiting_for_beforeunload_ack_ into the state machine.
- if (rfh_state == STATE_DEFAULT ||
- rfh_state == STATE_SWAPPED_OUT ||
- rfh_state_ == STATE_DEFAULT ||
- rfh_state_ == STATE_SWAPPED_OUT) {
- if (is_waiting_for_beforeunload_ack_) {
- is_waiting_for_beforeunload_ack_ = false;
- render_view_host_->GetWidget()->decrement_in_flight_event_count();
- render_view_host_->GetWidget()->StopHangMonitorTimeout();
- }
- send_before_unload_start_time_ = base::TimeTicks();
- render_view_host_->is_waiting_for_close_ack_ = false;
+ render_view_host_->set_is_active(true);
+ render_view_host_->set_is_swapped_out(false);
}
- rfh_state_ = rfh_state;
+
+ // Whenever we reset the RFH state, we should not be waiting for beforeunload
+ // or close acks. We clear them here to be safe, since they can cause
+ // navigations to be ignored in OnDidCommitProvisionalLoad.
+ if (is_waiting_for_beforeunload_ack_) {
+ is_waiting_for_beforeunload_ack_ = false;
+ render_view_host_->GetWidget()->decrement_in_flight_event_count();
+ render_view_host_->GetWidget()->StopHangMonitorTimeout();
+ }
+ send_before_unload_start_time_ = base::TimeTicks();
+ render_view_host_->is_waiting_for_close_ack_ = false;
}
bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
@@ -1859,6 +1962,42 @@ bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
return GetContentClient()->browser()->CanCommitURL(GetProcess(), url);
}
+bool RenderFrameHostImpl::CanCommitOrigin(
+ const url::Origin& origin,
+ const GURL& url) {
+ // If the --disable-web-security flag is specified, all bets are off and the
+ // renderer process can send any origin it wishes.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWebSecurity)) {
+ return true;
+ }
+
+ // file: URLs can be allowed to access any other origin, based on settings.
+ if (origin.scheme() == url::kFileScheme) {
+ WebPreferences prefs = render_view_host_->GetWebkitPreferences();
+ if (prefs.allow_universal_access_from_file_urls)
+ return true;
+ }
+
+ // It is safe to commit into a unique origin, regardless of the URL, as it is
+ // restricted from accessing other origins.
+ if (origin.unique())
+ return true;
+
+ // Standard URLs must match the reported origin.
+ if (url.IsStandard() && !origin.IsSameOriginWith(url::Origin(url)))
+ return false;
+
+ // A non-unique origin must be a valid URL, which allows us to safely do a
+ // conversion to GURL.
+ GURL origin_url(origin.Serialize());
+
+ // Verify that the origin is allowed to commit in this process.
+ // Note: This also handles non-standard cases for |url|, such as
+ // about:blank, data, and blob URLs.
+ return CanCommitURL(origin_url);
+}
+
void RenderFrameHostImpl::Navigate(
const CommonNavigationParams& common_params,
const StartNavigationParams& start_params,
@@ -1877,8 +2016,8 @@ void RenderFrameHostImpl::Navigate(
new NavigationParams(common_params, start_params, request_params));
} else {
// Get back to a clean state, in case we start a new navigation without
- // completing a RFH swap or unload handler.
- SetState(RenderFrameHostImpl::STATE_DEFAULT);
+ // completing an unload handler.
+ ResetWaitingState();
SendNavigateMessage(common_params, start_params, request_params);
}
@@ -1894,7 +2033,7 @@ void RenderFrameHostImpl::Navigate(
// Blink doesn't send throb notifications for JavaScript URLs, so it is not
// done here either.
if (!common_params.url.SchemeIs(url::kJavaScriptScheme))
- frame_tree_node_->DidStartLoading(true);
+ OnDidStartLoading(true);
}
void RenderFrameHostImpl::NavigateToInterstitialURL(const GURL& data_url) {
@@ -1903,10 +2042,10 @@ void RenderFrameHostImpl::NavigateToInterstitialURL(const GURL& data_url) {
data_url, Referrer(), ui::PAGE_TRANSITION_LINK,
FrameMsg_Navigate_Type::NORMAL, false, false, base::TimeTicks::Now(),
FrameMsg_UILoadMetricsReportType::NO_REPORT, GURL(), GURL(), LOFI_OFF,
- base::TimeTicks::Now());
+ base::TimeTicks::Now(), "GET");
if (IsBrowserSideNavigationEnabled()) {
- CommitNavigation(nullptr, nullptr, common_params,
- RequestNavigationParams());
+ CommitNavigation(nullptr, nullptr, common_params, RequestNavigationParams(),
+ false);
} else {
Navigate(common_params, StartNavigationParams(), RequestNavigationParams());
}
@@ -2036,34 +2175,46 @@ void RenderFrameHostImpl::CommitNavigation(
ResourceResponse* response,
scoped_ptr<StreamHandle> body,
const CommonNavigationParams& common_params,
- const RequestNavigationParams& request_params) {
+ const RequestNavigationParams& request_params,
+ bool is_view_source) {
DCHECK((response && body.get()) ||
!ShouldMakeNetworkRequestForURL(common_params.url));
UpdatePermissionsForNavigation(common_params, request_params);
// Get back to a clean state, in case we start a new navigation without
- // completing a RFH swap or unload handler.
- SetState(RenderFrameHostImpl::STATE_DEFAULT);
+ // completing an unload handler.
+ ResetWaitingState();
+
+ // The renderer can exit view source mode when any error or cancellation
+ // happen. When reusing the same renderer, overwrite to recover the mode.
+ if (is_view_source &&
+ this == frame_tree_node_->render_manager()->current_frame_host()) {
+ DCHECK(!GetParent());
+ render_view_host()->Send(new FrameMsg_EnableViewSourceMode(routing_id_));
+ }
const GURL body_url = body.get() ? body->GetURL() : GURL();
const ResourceResponseHead head = response ?
response->head : ResourceResponseHead();
Send(new FrameMsg_CommitNavigation(routing_id_, head, body_url, common_params,
request_params));
- // TODO(clamy): Check if we should start the throbber for non javascript urls
- // here.
+
+ // If a network request was made, update the LoFi state.
+ if (ShouldMakeNetworkRequestForURL(common_params.url))
+ last_navigation_lofi_state_ = common_params.lofi_state;
// TODO(clamy): Release the stream handle once the renderer has finished
// reading it.
stream_handle_ = std::move(body);
// When navigating to a Javascript url, no commit is expected from the
- // RenderFrameHost, nor should the throbber start.
+ // RenderFrameHost, nor should the throbber start. The NavigationRequest is
+ // also not stored in the FrameTreeNode. Therefore do not reset it, as this
+ // could cancel an existing pending navigation.
if (!common_params.url.SchemeIs(url::kJavaScriptScheme)) {
pending_commit_ = true;
is_loading_ = true;
}
- frame_tree_node_->ResetNavigationRequest(true);
}
void RenderFrameHostImpl::FailedNavigation(
@@ -2072,8 +2223,8 @@ void RenderFrameHostImpl::FailedNavigation(
bool has_stale_copy_in_cache,
int error_code) {
// Get back to a clean state, in case a new navigation started without
- // completing a RFH swap or unload handler.
- SetState(RenderFrameHostImpl::STATE_DEFAULT);
+ // completing an unload handler.
+ ResetWaitingState();
Send(new FrameMsg_FailedNavigation(routing_id_, common_params, request_params,
has_stale_copy_in_cache, error_code));
@@ -2092,21 +2243,21 @@ void RenderFrameHostImpl::SetUpMojoIfNeeded() {
return;
RegisterMojoServices();
- RenderFrameSetupPtr setup;
+ mojom::RenderFrameSetupPtr setup;
GetProcess()->GetServiceRegistry()->ConnectToRemoteService(
mojo::GetProxy(&setup));
- mojo::ServiceProviderPtr exposed_services;
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services;
service_registry_->Bind(GetProxy(&exposed_services));
- mojo::ServiceProviderPtr services;
- setup->ExchangeServiceProviders(routing_id_, GetProxy(&services),
- std::move(exposed_services));
+ mojo::shell::mojom::InterfaceProviderPtr services;
+ setup->ExchangeInterfaceProviders(routing_id_, GetProxy(&services),
+ std::move(exposed_services));
service_registry_->BindRemoteServiceProvider(std::move(services));
#if defined(OS_ANDROID)
- service_registry_android_.reset(
- new ServiceRegistryAndroid(service_registry_.get()));
+ service_registry_android_ =
+ ServiceRegistryAndroid::Create(service_registry_.get());
ServiceRegistrarAndroid::RegisterFrameHostServices(
service_registry_android_.get());
#endif
@@ -2226,7 +2377,7 @@ void RenderFrameHostImpl::ClearAllWebUI() {
web_ui_.reset();
}
-const image_downloader::ImageDownloaderPtr&
+const content::mojom::ImageDownloaderPtr&
RenderFrameHostImpl::GetMojoImageDownloader() {
if (!mojo_image_downloader_.get() && GetServiceRegistry()) {
GetServiceRegistry()->ConnectToRemoteService(
@@ -2235,6 +2386,22 @@ RenderFrameHostImpl::GetMojoImageDownloader() {
return mojo_image_downloader_;
}
+void RenderFrameHostImpl::ResetLoadingState() {
+ if (is_loading()) {
+ // When pending deletion, just set the loading state to not loading.
+ // Otherwise, OnDidStopLoading will take care of that, as well as sending
+ // notification to the FrameTreeNode about the change in loading state.
+ if (!is_active())
+ is_loading_ = false;
+ else
+ OnDidStopLoading();
+ }
+}
+
+void RenderFrameHostImpl::SuppressFurtherDialogs() {
+ Send(new FrameMsg_SuppressFurtherDialogs(GetRoutingID()));
+}
+
bool RenderFrameHostImpl::IsSameSiteInstance(
RenderFrameHostImpl* other_render_frame_host) {
// As a sanity check, make sure the frame belongs to the same BrowserContext.
@@ -2256,10 +2423,31 @@ void RenderFrameHostImpl::RequestAXTreeSnapshot(
}
void RenderFrameHostImpl::SetAccessibilityCallbackForTesting(
- const base::Callback<void(ui::AXEvent, int)>& callback) {
+ const base::Callback<void(RenderFrameHostImpl*, ui::AXEvent, int)>&
+ callback) {
accessibility_testing_callback_ = callback;
}
+void RenderFrameHostImpl::UpdateAXTreeData() {
+ AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
+ if (accessibility_mode == AccessibilityModeOff || !is_active()) {
+ return;
+ }
+
+ std::vector<AXEventNotificationDetails> details;
+ details.reserve(1U);
+ AXEventNotificationDetails detail;
+ detail.ax_tree_id = GetAXTreeID();
+ detail.update.has_tree_data = true;
+ AXContentTreeDataToAXTreeData(&detail.update.tree_data);
+ details.push_back(detail);
+
+ if (browser_accessibility_manager_)
+ browser_accessibility_manager_->OnAccessibilityEvents(details);
+
+ delegate_->AccessibilityEventReceived(details);
+}
+
void RenderFrameHostImpl::SetTextTrackSettings(
const FrameMsg_TextTrackSettings_Params& params) {
DCHECK(!GetParent());
@@ -2276,8 +2464,9 @@ BrowserAccessibilityManager*
if (view &&
!browser_accessibility_manager_ &&
!no_create_browser_accessibility_manager_for_testing_) {
+ bool is_root_frame = !frame_tree_node()->parent();
browser_accessibility_manager_.reset(
- view->CreateBrowserAccessibilityManager(this));
+ view->CreateBrowserAccessibilityManager(this, is_root_frame));
if (browser_accessibility_manager_)
UMA_HISTOGRAM_COUNTS("Accessibility.FrameEnabledCount", 1);
else
@@ -2314,22 +2503,13 @@ bool RenderFrameHostImpl::IsRenderFrameLive() {
return is_live;
}
-#if defined(OS_WIN)
-
-void RenderFrameHostImpl::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {
- RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
- render_view_host_->GetWidget()->GetView());
- if (view)
- view->SetParentNativeViewAccessible(accessible_parent);
+int RenderFrameHostImpl::GetProxyCount() {
+ if (this != frame_tree_node_->current_frame_host())
+ return 0;
+ return frame_tree_node_->render_manager()->GetProxyCount();
}
-gfx::NativeViewAccessible
-RenderFrameHostImpl::GetParentNativeViewAccessible() const {
- return delegate_->GetParentNativeViewAccessible();
-}
-
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
void RenderFrameHostImpl::DidSelectPopupMenuItem(int selected_index) {
Send(new FrameMsg_SelectPopupMenuItem(routing_id_, selected_index));
@@ -2341,6 +2521,17 @@ void RenderFrameHostImpl::DidCancelPopupMenu() {
#elif defined(OS_ANDROID)
+void RenderFrameHostImpl::ActivateNearestFindResult(int request_id,
+ float x,
+ float y) {
+ Send(
+ new InputMsg_ActivateNearestFindResult(GetRoutingID(), request_id, x, y));
+}
+
+void RenderFrameHostImpl::RequestFindMatchRects(int current_version) {
+ Send(new FrameMsg_FindMatchRects(GetRoutingID(), current_version));
+}
+
void RenderFrameHostImpl::DidSelectPopupMenuItems(
const std::vector<int>& selected_indices) {
Send(new FrameMsg_SelectPopupMenuItems(routing_id_, false, selected_indices));
@@ -2370,9 +2561,8 @@ void RenderFrameHostImpl::SetNavigationsSuspended(
if (!suspend && suspended_nav_params_) {
// There's navigation message params waiting to be sent. Now that we're not
- // suspended anymore, resume navigation by sending them. If we were swapped
- // out, we should also stop filtering out the IPC messages now.
- SetState(RenderFrameHostImpl::STATE_DEFAULT);
+ // suspended anymore, resume navigation by sending them.
+ ResetWaitingState();
DCHECK(!proceed_time.is_null());
// TODO(csharrison): Make sure that PlzNavigate and the current architecture
@@ -2414,9 +2604,9 @@ void RenderFrameHostImpl::DidUseGeolocationPermission() {
permission_manager->RegisterPermissionUsage(
PermissionType::GEOLOCATION,
- GetLastCommittedURL().GetOrigin(),
+ last_committed_url().GetOrigin(),
frame_tree_node()->frame_tree()->GetMainFrame()
- ->GetLastCommittedURL().GetOrigin());
+ ->last_committed_url().GetOrigin());
}
void RenderFrameHostImpl::UpdatePermissionsForNavigation(
@@ -2488,11 +2678,13 @@ AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::RoutingIDToAXTreeID(
AXTreeIDRegistry::AXTreeID
RenderFrameHostImpl::BrowserPluginInstanceIDToAXTreeID(
int instance_id) {
- RenderFrameHost* guest = delegate()->GetGuestByInstanceID(
- this, instance_id);
+ RenderFrameHostImpl* guest = static_cast<RenderFrameHostImpl*>(
+ delegate()->GetGuestByInstanceID(this, instance_id));
if (!guest)
return AXTreeIDRegistry::kNoAXTreeID;
+ guest->set_browser_plugin_embedder_ax_tree_id(GetAXTreeID());
+
return guest->GetAXTreeID();
}
@@ -2525,8 +2717,9 @@ void RenderFrameHostImpl::AXContentNodeDataToAXNodeData(
}
void RenderFrameHostImpl::AXContentTreeDataToAXTreeData(
- const AXContentTreeData& src,
ui::AXTreeData* dst) {
+ const AXContentTreeData& src = ax_content_tree_data_;
+
// Copy the common fields.
*dst = src;
@@ -2535,6 +2728,29 @@ void RenderFrameHostImpl::AXContentTreeDataToAXTreeData(
if (src.parent_routing_id != -1)
dst->parent_tree_id = RoutingIDToAXTreeID(src.parent_routing_id);
+
+ if (browser_plugin_embedder_ax_tree_id_ != AXTreeIDRegistry::kNoAXTreeID)
+ dst->parent_tree_id = browser_plugin_embedder_ax_tree_id_;
+
+ // If this is not the root frame tree node, we're done.
+ if (frame_tree_node()->parent())
+ return;
+
+ // For the root frame tree node, also store the AXTreeID of the focused frame.
+ FrameTreeNode* focused_frame_tree_node = frame_tree_->GetFocusedFrame();
+ if (!focused_frame_tree_node)
+ return;
+ RenderFrameHostImpl* focused_frame =
+ focused_frame_tree_node->current_frame_host();
+ DCHECK(focused_frame);
+ dst->focused_tree_id = focused_frame->GetAXTreeID();
+}
+
+void RenderFrameHostImpl::CreateWebBluetoothService(
+ blink::mojom::WebBluetoothServiceRequest request) {
+ DCHECK(!web_bluetooth_service_);
+ web_bluetooth_service_.reset(
+ new WebBluetoothServiceImpl(this, std::move(request)));
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.h b/chromium/content/browser/frame_host/render_frame_host_impl.h
index b457a076e55..7376f298f58 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.h
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.h
@@ -23,6 +23,7 @@
#include "build/build_config.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/bad_message.h"
+#include "content/browser/loader/global_routing_id.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/common/accessibility_mode_enums.h"
@@ -43,7 +44,7 @@
#include "ui/base/page_transition_types.h"
#if defined(OS_ANDROID)
-#include "content/browser/mojo/service_registry_android.h"
+#include "content/public/browser/android/service_registry_android.h"
#endif
class GURL;
@@ -62,6 +63,12 @@ class FilePath;
class ListValue;
}
+namespace blink {
+namespace mojom {
+class WebBluetoothService;
+}
+}
+
namespace content {
class CrossProcessFrameConnector;
@@ -82,47 +89,20 @@ class RenderWidgetHostViewBase;
class ResourceRequestBody;
class StreamHandle;
class TimeoutMonitor;
+class WebBluetoothServiceImpl;
struct ContextMenuParams;
struct GlobalRequestID;
struct Referrer;
struct ResourceResponse;
-// Flag arguments for RenderFrameHost creation.
-enum CreateRenderFrameFlags {
- // The RFH will be initially placed on the swapped out hosts list.
- CREATE_RF_SWAPPED_OUT = 1 << 0,
- // The RenderFrame is initially hidden.
- CREATE_RF_HIDDEN = 1 << 1,
-};
-
-class CONTENT_EXPORT RenderFrameHostImpl
- : public RenderFrameHost,
- public BrowserAccessibilityDelegate {
+class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost,
+ public BrowserAccessibilityDelegate,
+ public SiteInstanceImpl::Observer {
public:
using AXTreeSnapshotCallback =
base::Callback<void(
const ui::AXTreeUpdate&)>;
- // Keeps track of the state of the RenderFrameHostImpl, particularly with
- // respect to swap out.
- enum RenderFrameHostImplState {
- // The standard state for a RFH handling the communication with an active
- // RenderFrame.
- STATE_DEFAULT = 0,
- // The RFH has not received the SwapOutACK yet, but the new page has
- // committed in a different RFH. Upon reception of the SwapOutACK, the RFH
- // will either enter STATE_SWAPPED_OUT (if it is a main frame and there are
- // other active frames in its SiteInstance) or it will be deleted.
- STATE_PENDING_SWAP_OUT,
- // The RFH is swapped out and stored inside a RenderFrameProxyHost, being
- // used as a placeholder to allow cross-process communication. Only main
- // frames can enter this state.
- STATE_SWAPPED_OUT,
- };
- // Helper function to determine whether the RFH state should contribute to the
- // number of active frames of a SiteInstance or not.
- static bool IsRFHStateActive(RenderFrameHostImplState rfh_state);
-
// An accessibility reset is only allowed to prevent very rare corner cases
// or race conditions where the browser and renderer get out of sync. If
// this happens more than this many times, kill the renderer.
@@ -139,11 +119,12 @@ class CONTENT_EXPORT RenderFrameHostImpl
AXTreeIDRegistry::AXTreeID GetAXTreeID() override;
SiteInstanceImpl* GetSiteInstance() override;
RenderProcessHost* GetProcess() override;
- RenderFrameHost* GetParent() override;
+ RenderWidgetHostView* GetView() override;
+ RenderFrameHostImpl* GetParent() override;
int GetFrameTreeNodeId() override;
const std::string& GetFrameName() override;
bool IsCrossProcessSubframe() override;
- GURL GetLastCommittedURL() override;
+ const GURL& GetLastCommittedURL() override;
url::Origin GetLastCommittedOrigin() override;
gfx::NativeView GetNativeView() override;
void AddMessageToConsole(ConsoleMessageLevel level,
@@ -151,23 +132,27 @@ class CONTENT_EXPORT RenderFrameHostImpl
void ExecuteJavaScript(const base::string16& javascript) override;
void ExecuteJavaScript(const base::string16& javascript,
const JavaScriptResultCallback& callback) override;
+ void ExecuteJavaScriptInIsolatedWorld(
+ const base::string16& javascript,
+ const JavaScriptResultCallback& callback,
+ int world_id) override;
void ExecuteJavaScriptForTests(const base::string16& javascript) override;
void ExecuteJavaScriptForTests(
const base::string16& javascript,
const JavaScriptResultCallback& callback) override;
void ExecuteJavaScriptWithUserGestureForTests(
const base::string16& javascript) override;
- void ExecuteJavaScriptInIsolatedWorld(
- const base::string16& javascript,
- const JavaScriptResultCallback& callback,
- int world_id) override;
void ActivateFindInPageResultForAccessibility(int request_id) override;
+ void InsertVisualStateCallback(const VisualStateCallback& callback) override;
RenderViewHost* GetRenderViewHost() override;
ServiceRegistry* GetServiceRegistry() override;
blink::WebPageVisibilityState GetVisibilityState() override;
- void InsertVisualStateCallback(
- const VisualStateCallback& callback) override;
bool IsRenderFrameLive() override;
+ int GetProxyCount() override;
+#if defined(OS_ANDROID)
+ void ActivateNearestFindResult(int request_id, float x, float y) override;
+ void RequestFindMatchRects(int current_version) override;
+#endif
// IPC::Sender
bool Send(IPC::Message* msg) override;
@@ -195,12 +180,18 @@ class CONTENT_EXPORT RenderFrameHostImpl
gfx::Rect AccessibilityGetViewBounds() const override;
gfx::Point AccessibilityOriginInScreen(
const gfx::Rect& bounds) const override;
+ gfx::Rect AccessibilityTransformToRootCoordSpace(
+ const gfx::Rect& bounds) override;
+ SiteInstance* AccessibilityGetSiteInstance() override;
void AccessibilityHitTest(const gfx::Point& point) override;
void AccessibilitySetAccessibilityFocus(int acc_obj_id) override;
void AccessibilityFatalError() override;
gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override;
gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
+ // SiteInstanceImpl::Observer
+ void RenderProcessGone(SiteInstanceImpl* site_instance) override;
+
// Creates a RenderFrame in the renderer process.
bool CreateRenderFrame(int proxy_routing_id,
int opener_routing_id,
@@ -221,6 +212,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
int new_routing_id,
blink::WebTreeScopeType scope,
const std::string& frame_name,
+ const std::string& frame_unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties);
@@ -228,6 +220,22 @@ class CONTENT_EXPORT RenderFrameHostImpl
RenderFrameHostDelegate* delegate() { return delegate_; }
FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
+ const GURL& last_committed_url() const { return last_committed_url_; }
+
+ // Allows FrameTreeNode::SetCurrentURL to update this frame's last committed
+ // URL. Do not call this directly, since we rely on SetCurrentURL to track
+ // whether a real load has committed or not.
+ void set_last_committed_url(const GURL& url) {
+ last_committed_url_ = url;
+ }
+
+ // The most recent non-net-error URL to commit in this frame. In almost all
+ // cases, use GetLastCommittedURL instead.
+ const GURL& last_successful_url() { return last_successful_url_; }
+ void set_last_successful_url(const GURL& url) {
+ last_successful_url_ = url;
+ }
+
// Returns the associated WebUI or null if none applies.
WebUIImpl* web_ui() const { return web_ui_.get(); }
@@ -241,15 +249,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
// call FrameTreeNode::IsLoading.
bool is_loading() const { return is_loading_; }
+ // Sets this RenderFrameHost loading state. This is only used in the case of
+ // transfer navigations, where no DidStart/DidStopLoading notifications
+ // should be sent during the transfer.
+ // TODO(clamy): Remove this once PlzNavigate ships.
+ void set_is_loading(bool is_loading) { is_loading_ = is_loading; }
+
// This returns the RenderFrameHost's owned RenderWidgetHost if it has one,
// or else it returns nullptr.
// If the RenderFrameHost is the page's main frame, this returns instead a
// pointer to the RenderViewHost (which inherits RenderWidgetHost).
RenderWidgetHostImpl* GetRenderWidgetHost();
- // This returns the RenderWidgetHostView that can be used to control
- // focus and visibility for this frame.
- RenderWidgetHostView* GetView();
+ GlobalFrameRoutingId GetGlobalFrameRoutingId();
// This function is called when this is a swapped out RenderFrameHost that
// lives in the same process as the parent frame. The
@@ -332,12 +344,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
// out.
void OnSwappedOut();
- // Whether this RenderFrameHost has been swapped out, such that the frame is
- // now rendered by a RenderFrameHost in a different process.
- bool is_swapped_out() const { return rfh_state_ == STATE_SWAPPED_OUT; }
-
- // The current state of this RFH.
- RenderFrameHostImplState rfh_state() const { return rfh_state_; }
+ // This method returns true from the time this RenderFrameHost is created
+ // until SwapOut is called, at which point it is pending deletion.
+ bool is_active() { return !is_waiting_for_swapout_ack_; }
// Sends the given navigation message. Use this rather than sending it
// yourself since this does the internal bookkeeping described below. This
@@ -435,7 +444,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
// renderer process, and the accessibility tree it sent can be
// retrieved using GetAXTreeForTesting().
void SetAccessibilityCallbackForTesting(
- const base::Callback<void(ui::AXEvent, int)>& callback);
+ const base::Callback<void(RenderFrameHostImpl*, ui::AXEvent, int)>&
+ callback);
+
+ // Called when the metadata about the accessibility tree for this frame
+ // changes due to a browser-side change, as opposed to due to an IPC from
+ // a renderer.
+ void UpdateAXTreeData();
+
+ // Set the AX tree ID of the embedder RFHI, if this is a browser plugin guest.
+ void set_browser_plugin_embedder_ax_tree_id(
+ AXTreeIDRegistry::AXTreeID ax_tree_id) {
+ browser_plugin_embedder_ax_tree_id_ = ax_tree_id;
+ }
// Send a message to the render process to change text track style settings.
void SetTextTrackSettings(const FrameMsg_TextTrackSettings_Params& params);
@@ -459,11 +480,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
no_create_browser_accessibility_manager_for_testing_ = flag;
}
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent);
- gfx::NativeViewAccessible GetParentNativeViewAccessible() const;
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
// Select popup menu related methods (for external popup menus).
void DidSelectPopupMenuItem(int selected_index);
void DidCancelPopupMenu();
@@ -477,7 +494,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
void CommitNavigation(ResourceResponse* response,
scoped_ptr<StreamHandle> body,
const CommonNavigationParams& common_params,
- const RequestNavigationParams& request_params);
+ const RequestNavigationParams& request_params,
+ bool is_view_source);
// PlzNavigate
// Indicates that a navigation failed and that this RenderFrame should display
@@ -521,7 +539,23 @@ class CONTENT_EXPORT RenderFrameHostImpl
void ClearAllWebUI();
// Returns the Mojo ImageDownloader service.
- const image_downloader::ImageDownloaderPtr& GetMojoImageDownloader();
+ const content::mojom::ImageDownloaderPtr& GetMojoImageDownloader();
+
+ // Resets the loading state. Following this call, the RenderFrameHost will be
+ // in a non-loading state.
+ void ResetLoadingState();
+
+ // Tells the renderer that this RenderFrame will soon be swapped out, and thus
+ // not to create any new modal dialogs until it happens. This must be done
+ // separately so that the ScopedPageLoadDeferrers of any current dialogs are
+ // no longer on the stack when we attempt to swap it out.
+ void SuppressFurtherDialogs();
+
+ // PlzNavigate: returns the LoFi state of the last successful navigation that
+ // made a network request.
+ LoFiState last_navigation_lofi_state() const {
+ return last_navigation_lofi_state_;
+ }
protected:
friend class RenderFrameHostFactory;
@@ -538,13 +572,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
FrameTreeNode* frame_tree_node,
int32_t routing_id,
int32_t widget_routing_id,
- int flags);
+ bool hidden);
private:
friend class TestRenderFrameHost;
friend class TestRenderViewHost;
+ FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest,
+ CreateRenderViewAfterProcessKillAndClosedProxy);
+ FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest,
+ RenderViewInitAfterNewProxyAndProcessKill);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrashSubframe);
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+ RenderViewHostPendingDeletionIsNotReused);
// IPC Message handlers.
void OnAddMessageToConsole(int32_t level,
@@ -568,7 +608,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
const base::string16& error_description,
bool was_ignored_by_handler);
void OnDidCommitProvisionalLoad(const IPC::Message& msg);
- void OnDidDropNavigation();
void OnUpdateState(const PageState& state);
void OnBeforeUnloadACK(
bool proceed,
@@ -585,16 +624,16 @@ class CONTENT_EXPORT RenderFrameHostImpl
JavaScriptMessageType type,
IPC::Message* reply_msg);
void OnRunBeforeUnloadConfirm(const GURL& frame_url,
- const base::string16& message,
bool is_reload,
IPC::Message* reply_msg);
void OnTextSurroundingSelectionResponse(const base::string16& content,
- size_t start_offset,
- size_t end_offset);
+ uint32_t start_offset,
+ uint32_t end_offset);
void OnDidAccessInitialDocument();
void OnDidChangeOpener(int32_t opener_routing_id);
- void OnDidChangeName(const std::string& name);
+ void OnDidChangeName(const std::string& name, const std::string& unique_name);
void OnEnforceStrictMixedContentChecking();
+ void OnUpdateToUniqueOrigin(bool is_potentially_trustworthy_unique_origin);
void OnDidAssignPageId(int32_t page_id);
void OnDidChangeSandboxFlags(int32_t frame_routing_id,
blink::WebSandboxFlags flags);
@@ -615,6 +654,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
void OnAccessibilityFindInPageResult(
const AccessibilityHostMsg_FindInPageResultParams& params);
+ void OnAccessibilityChildFrameHitTestResult(const gfx::Point& point,
+ int hit_obj_id);
void OnAccessibilitySnapshotResponse(
int callback_id,
const AXContentTreeUpdate& snapshot);
@@ -635,15 +676,22 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Registers Mojo services that this frame host makes available.
void RegisterMojoServices();
- // Updates the state of this RenderFrameHost and clears any waiting state
- // that is no longer relevant.
- void SetState(RenderFrameHostImplState rfh_state);
+ // Resets any waiting state of this RenderFrameHost that is no longer
+ // relevant.
+ void ResetWaitingState();
// Returns whether the given URL is allowed to commit in the current process.
// This is a more conservative check than RenderProcessHost::FilterURL, since
// it will be used to kill processes that commit unauthorized URLs.
bool CanCommitURL(const GURL& url);
+ // Returns whether the given origin is allowed to commit in the current
+ // RenderFrameHost. The |url| is used to ensure it matches the origin in cases
+ // where it is applicable. This is a more conservative check than
+ // RenderProcessHost::FilterURL, since it will be used to kill processes that
+ // commit unauthorized origins.
+ bool CanCommitOrigin(const url::Origin& origin, const GURL& url);
+
// Asserts that the given RenderFrameHostImpl is part of the same browser
// context (and crashes if not), then returns whether the given frame is
// part of the same site instance.
@@ -674,8 +722,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Convert the content-layer-specific AXContentTreeData to a general-purpose
// AXTreeData structure.
- void AXContentTreeDataToAXTreeData(const AXContentTreeData& src,
- ui::AXTreeData* dst);
+ void AXContentTreeDataToAXTreeData(ui::AXTreeData* dst);
// Returns the RenderWidgetHostView used for accessibility. For subframes,
// this function will return the platform view on the main frame; for main
@@ -697,6 +744,14 @@ class CONTENT_EXPORT RenderFrameHostImpl
FrameTreeNode* FindAndVerifyChild(int32_t child_frame_routing_id,
bad_message::BadMessageReason reason);
+ // Creates a Web Bluetooth Service owned by the frame.
+ void CreateWebBluetoothService(
+ mojo::InterfaceRequest<blink::mojom::WebBluetoothService> request);
+
+ // Allows tests to disable the swapout event timer to simulate bugs that
+ // happen before it fires (to avoid flakiness).
+ void ResetSwapOutTimerForTesting();
+
// For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a
// refcount that calls Shutdown when it reaches zero. This allows each
// RenderFrameHostManager to just care about RenderFrameHosts, while ensuring
@@ -744,6 +799,14 @@ class CONTENT_EXPORT RenderFrameHostImpl
// The FrameTreeNode which this RenderFrameHostImpl is hosted in.
FrameTreeNode* frame_tree_node_;
+ // Track this frame's last committed URL.
+ GURL last_committed_url_;
+
+ // The most recent non-error URL to commit in this frame. Remove this in
+ // favor of GetLastCommittedURL() once PlzNavigate is enabled or cross-process
+ // transfers work for net errors. See https://crbug.com/588314.
+ GURL last_successful_url_;
+
// The mapping of pending JavaScript calls created by
// ExecuteJavaScript and their corresponding callbacks.
std::map<int, JavaScriptResultCallback> javascript_callbacks_;
@@ -759,8 +822,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
int routing_id_;
- // The current state of this RenderFrameHost.
- RenderFrameHostImplState rfh_state_;
+ // Boolean indicating whether this RenderFrameHost is being actively used or
+ // is waiting for FrameHostMsg_SwapOut_ACK and thus pending deletion.
+ bool is_waiting_for_swapout_ack_;
// Tracks whether the RenderFrame for this RenderFrameHost has been created in
// the renderer process. Currently only used for subframes.
@@ -828,6 +892,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
scoped_ptr<ServiceRegistryAndroid> service_registry_android_;
#endif
+ scoped_ptr<WebBluetoothServiceImpl> web_bluetooth_service_;
+
// The object managing the accessibility tree for this frame.
scoped_ptr<BrowserAccessibilityManager> browser_accessibility_manager_;
@@ -840,12 +906,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
// we don't keep trying to reset forever.
int accessibility_reset_count_;
+ // The last AXContentTreeData for this frame received from the RenderFrame.
+ AXContentTreeData ax_content_tree_data_;
+
+ // The AX tree ID of the embedder, if this is a browser plugin guest.
+ AXTreeIDRegistry::AXTreeID browser_plugin_embedder_ax_tree_id_;
+
// The mapping from callback id to corresponding callback for pending
// accessibility tree snapshot calls created by RequestAXTreeSnapshot.
std::map<int, AXTreeSnapshotCallback> ax_tree_snapshot_callbacks_;
// Callback when an event is received, for testing.
- base::Callback<void(ui::AXEvent, int)> accessibility_testing_callback_;
+ base::Callback<void(RenderFrameHostImpl*, ui::AXEvent, int)>
+ accessibility_testing_callback_;
// The most recently received accessibility tree - for testing only.
scoped_ptr<ui::AXTree> ax_tree_for_testing_;
// Flag to not create a BrowserAccessibilityManager, for testing. If one
@@ -856,14 +929,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
// response once it has started.
scoped_ptr<StreamHandle> stream_handle_;
- // Context shared for each PermissionService instance created for this RFH.
+ // Context shared for each mojom::PermissionService instance created for this
+ // RFH.
scoped_ptr<PermissionServiceContext> permission_service_context_;
// The frame's Mojo Shell service.
scoped_ptr<FrameMojoShell> frame_mojo_shell_;
// Holder of Mojo connection with ImageDownloader service in RenderFrame.
- image_downloader::ImageDownloaderPtr mojo_image_downloader_;
+ content::mojom::ImageDownloaderPtr mojo_image_downloader_;
// Tracks a navigation happening in this frame. Note that while there can be
// two navigations in the same FrameTreeNode, there can only be one
@@ -888,6 +962,11 @@ class CONTENT_EXPORT RenderFrameHostImpl
// called (no pending instance should be set).
bool should_reuse_web_ui_;
+ // PlzNavigate: The LoFi state of the last navigation. This is used during
+ // history navigation of subframes to ensure that subframes navigate with the
+ // same LoFi status as the top-level frame.
+ LoFiState last_navigation_lofi_state_;
+
// NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager.cc b/chromium/content/browser/frame_host/render_frame_host_manager.cc
index 093dd4a5fa8..4358082af22 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.cc
@@ -10,6 +10,8 @@
#include <utility>
#include "base/command_line.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
@@ -48,61 +50,6 @@
namespace content {
-namespace {
-
-// Helper function to add the FrameTree of the given node's opener to the list
-// of |opener_trees|, if it doesn't exist there already. |visited_index|
-// indicates which FrameTrees in |opener_trees| have already been visited
-// (i.e., those at indices less than |visited_index|). |nodes_with_back_links|
-// collects FrameTreeNodes with openers in FrameTrees that have already been
-// visited (such as those with cycles). This function is intended to be used
-// with FrameTree::ForEach, so it always returns true to visit all nodes in the
-// tree.
-bool OpenerForFrameTreeNode(
- size_t visited_index,
- std::vector<FrameTree*>* opener_trees,
- base::hash_set<FrameTreeNode*>* nodes_with_back_links,
- FrameTreeNode* node) {
- if (!node->opener())
- return true;
-
- FrameTree* opener_tree = node->opener()->frame_tree();
-
- const auto& existing_tree_it =
- std::find(opener_trees->begin(), opener_trees->end(), opener_tree);
- if (existing_tree_it == opener_trees->end()) {
- // This is a new opener tree that we will need to process.
- opener_trees->push_back(opener_tree);
- } else {
- // If this tree is already on our processing list *and* we have visited it,
- // then this node's opener is a back link. This means the node will need
- // special treatment to process its opener.
- size_t position = std::distance(opener_trees->begin(), existing_tree_it);
- if (position < visited_index)
- nodes_with_back_links->insert(node);
- }
- return true;
-}
-
-} // namespace
-
-// static
-bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
- node->render_manager()->pending_delete_hosts_.clear();
- return true;
-}
-
-// static
-bool RenderFrameHostManager::ClearWebUIInstances(FrameTreeNode* node) {
- node->current_frame_host()->ClearAllWebUI();
- if (node->render_manager()->pending_render_frame_host_)
- node->render_manager()->pending_render_frame_host_->ClearAllWebUI();
- // PlzNavigate
- if (node->render_manager()->speculative_render_frame_host_)
- node->render_manager()->speculative_render_frame_host_->ClearAllWebUI();
- return true;
-}
-
RenderFrameHostManager::RenderFrameHostManager(
FrameTreeNode* frame_tree_node,
RenderFrameHostDelegate* render_frame_delegate,
@@ -147,10 +94,9 @@ void RenderFrameHostManager::Init(SiteInstance* site_instance,
// https://crbug.com/545684
DCHECK(!frame_tree_node_->IsMainFrame() ||
view_routing_id == widget_routing_id);
- int flags = delegate_->IsHidden() ? CREATE_RF_HIDDEN : 0;
SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id,
frame_routing_id, widget_routing_id,
- flags));
+ delegate_->IsHidden()));
// Notify the delegate of the creation of the current RenderFrameHost.
// Do this only for subframes, as the main frame case is taken care of by
@@ -346,9 +292,16 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
entry.transferred_global_request_id()) {
cross_site_transferring_request_->ReleaseRequest();
+ DCHECK(transfer_navigation_handle_);
+
+ // Update the pending NavigationEntry ID on the transferring handle.
+ // TODO(creis): Make this line unnecessary by avoiding having a pending
+ // entry for transfer navigations. See https://crbug.com/495161.
+ transfer_navigation_handle_->update_entry_id_for_transfer(
+ entry.GetUniqueID());
+
// The navigating RenderFrameHost should take ownership of the
// NavigationHandle that came from the transferring RenderFrameHost.
- DCHECK(transfer_navigation_handle_);
dest_render_frame_host->SetNavigationHandle(
std::move(transfer_navigation_handle_));
}
@@ -472,7 +425,7 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
}
void RenderFrameHostManager::OnCrossSiteResponse(
- RenderFrameHostImpl* pending_render_frame_host,
+ RenderFrameHostImpl* transferring_render_frame_host,
const GlobalRequestID& global_request_id,
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
@@ -484,12 +437,27 @@ void RenderFrameHostManager::OnCrossSiteResponse(
// swapping out) when the new navigation commits.
CHECK(cross_site_transferring_request);
- // A transfer should only have come from our pending or current RFH.
+ // A transfer should only have come from our pending or current RFH. If it
+ // started as a cross-process navigation via OpenURL, this is the pending
+ // one. If it wasn't cross-process until the transfer, this is the current
+ // one.
+ //
+ // Note that having a pending RFH does not imply that it was the one that
+ // made the request. Suppose that during a pending cross-site navigation,
+ // the frame performs a different same-site navigation which redirects
+ // cross-site. In this case, there will be a pending RFH, but this request
+ // is made by the current RFH. Later, this will create a new pending RFH and
+ // clean up the old one.
+ //
// TODO(creis): We need to handle the case that the pending RFH has changed
// in the mean time, while this was being posted from the IO thread. We
// should probably cancel the request in that case.
- DCHECK(pending_render_frame_host == pending_render_frame_host_.get() ||
- pending_render_frame_host == render_frame_host_.get());
+ DCHECK(transferring_render_frame_host == pending_render_frame_host_.get() ||
+ transferring_render_frame_host == render_frame_host_.get());
+
+ // Check if the FrameTreeNode is loading. This will be used later to notify
+ // the FrameTreeNode that the load stop if the transfer fails.
+ bool frame_tree_node_was_loading = frame_tree_node_->IsLoading();
// Store the transferring request so that we can release it if the transfer
// navigation matches.
@@ -498,22 +466,13 @@ void RenderFrameHostManager::OnCrossSiteResponse(
// Store the NavigationHandle to give it to the appropriate RenderFrameHost
// after it started navigating.
transfer_navigation_handle_ =
- pending_render_frame_host->PassNavigationHandleOwnership();
+ transferring_render_frame_host->PassNavigationHandleOwnership();
DCHECK(transfer_navigation_handle_);
- // Sanity check that the params are for the correct frame and process.
- // These should match the RenderFrameHost that made the request.
- // If it started as a cross-process navigation via OpenURL, this is the
- // pending one. If it wasn't cross-process until the transfer, this is
- // the current one.
- int render_frame_id = pending_render_frame_host_
- ? pending_render_frame_host_->GetRoutingID()
- : render_frame_host_->GetRoutingID();
- DCHECK_EQ(render_frame_id, pending_render_frame_host->GetRoutingID());
- int process_id = pending_render_frame_host_ ?
- pending_render_frame_host_->GetProcess()->GetID() :
- render_frame_host_->GetProcess()->GetID();
- DCHECK_EQ(process_id, global_request_id.child_id);
+ // Set the transferring RenderFrameHost as not loading, so that it does not
+ // emit a DidStopLoading notification if it is destroyed when creating the
+ // new navigating RenderFrameHost.
+ transferring_render_frame_host->set_is_loading(false);
// Treat the last URL in the chain as the destination and the remainder as
// the redirect chain.
@@ -522,9 +481,11 @@ void RenderFrameHostManager::OnCrossSiteResponse(
std::vector<GURL> rest_of_chain = transfer_url_chain;
rest_of_chain.pop_back();
- pending_render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
- pending_render_frame_host, transfer_url, rest_of_chain, referrer,
- page_transition, global_request_id, should_replace_current_entry);
+ transferring_render_frame_host->frame_tree_node()
+ ->navigator()
+ ->RequestTransferURL(transferring_render_frame_host, transfer_url,
+ nullptr, rest_of_chain, referrer, page_transition,
+ global_request_id, should_replace_current_entry);
// The transferring request was only needed during the RequestTransferURL
// call, so it is safe to clear at this point.
@@ -533,6 +494,11 @@ void RenderFrameHostManager::OnCrossSiteResponse(
// If the navigation continued, the NavigationHandle should have been
// transfered to a RenderFrameHost. In the other cases, it should be cleared.
transfer_navigation_handle_.reset();
+
+ // If the navigation in the new renderer did not start, inform the
+ // FrameTreeNode that it stopped loading.
+ if (!frame_tree_node_->IsLoading() && frame_tree_node_was_loading)
+ frame_tree_node_->DidStopLoading();
}
void RenderFrameHostManager::DidNavigateFrame(
@@ -579,15 +545,14 @@ void RenderFrameHostManager::CommitPendingIfNecessary(
if (render_frame_host_->pending_web_ui())
CommitPendingWebUI();
- // Decide on canceling the ongoing cross-process navigation.
- if (IsBrowserSideNavigationEnabled()) {
- CleanUpNavigation();
- } else {
- if (was_caused_by_user_gesture) {
- // A navigation in the original page has taken place. Cancel the
- // pending one. Only do it for user gesture originated navigations to
- // prevent page doing any shenanigans to prevent user from navigating.
- // See https://code.google.com/p/chromium/issues/detail?id=75195
+ // A navigation in the original page has taken place. Cancel the pending
+ // one. Only do it for user gesture originated navigations to prevent page
+ // doing any shenanigans to prevent user from navigating. See
+ // https://code.google.com/p/chromium/issues/detail?id=75195
+ if (was_caused_by_user_gesture) {
+ if (IsBrowserSideNavigationEnabled()) {
+ CleanUpNavigation();
+ } else {
CancelPending();
}
}
@@ -668,11 +633,10 @@ void RenderFrameHostManager::SwapOutOldFrame(
// Tell the renderer to suppress any further modal dialogs so that we can swap
// it out. This must be done before canceling any current dialog, in case
// there is a loop creating additional dialogs.
- // TODO(creis): Handle modal dialogs in subframe processes.
- old_render_frame_host->render_view_host()->SuppressDialogsUntilSwapOut();
+ old_render_frame_host->SuppressFurtherDialogs();
// Now close any modal dialogs that would prevent us from swapping out. This
- // must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
+ // must be done separately from SwapOut, so that the ScopedPageLoadDeferrer is
// no longer on the stack when we send the SwapOut message.
delegate_->CancelModalDialogsForRenderManager();
@@ -703,20 +667,7 @@ void RenderFrameHostManager::SwapOutOldFrame(
// SwapOut creates a RenderFrameProxy, so set the proxy to be initialized.
proxy->set_render_frame_proxy_created(true);
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- // In --site-per-process, frames delete their RFH rather than storing it
- // in the proxy. Schedule it for deletion once the SwapOutACK comes in.
- // TODO(creis): This will be the default when we remove swappedout://.
- MoveToPendingDeleteHosts(std::move(old_render_frame_host));
- } else {
- // We shouldn't get here for subframes, since we only swap subframes when
- // --site-per-process is used.
- DCHECK(frame_tree_node_->IsMainFrame());
-
- // The old RenderFrameHost will stay alive inside the proxy so that existing
- // JavaScript window references to it stay valid.
- proxy->TakeFrameHostOwnership(std::move(old_render_frame_host));
- }
+ MoveToPendingDeleteHosts(std::move(old_render_frame_host));
}
void RenderFrameHostManager::DiscardUnusedFrame(
@@ -743,20 +694,6 @@ void RenderFrameHostManager::DiscardUnusedFrame(
proxy = CreateRenderFrameProxyHost(site_instance,
render_frame_host->render_view_host());
}
-
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- DCHECK(frame_tree_node_->IsMainFrame());
-
- // When using swapped out RenderFrameHosts, it is possible for the pending
- // RenderFrameHost to be an existing one in swapped out state. Since it
- // has been used to start a navigation, it could have committed a
- // document. Check if |render_frame_host| is already swapped out, to avoid
- // swapping it out again.
- if (!render_frame_host->is_swapped_out())
- render_frame_host->SwapOut(proxy, false);
-
- proxy->TakeFrameHostOwnership(std::move(render_frame_host));
- }
}
render_frame_host.reset();
@@ -764,25 +701,26 @@ void RenderFrameHostManager::DiscardUnusedFrame(
void RenderFrameHostManager::MoveToPendingDeleteHosts(
scoped_ptr<RenderFrameHostImpl> render_frame_host) {
- // If this is the main frame going away and there are no more references to
- // its RenderViewHost, mark it for deletion as well so that we don't try to
- // reuse it.
- if (render_frame_host->frame_tree_node()->IsMainFrame() &&
- render_frame_host->render_view_host()->ref_count() <= 1) {
- render_frame_host->render_view_host()->set_pending_deletion();
- }
-
// |render_frame_host| will be deleted when its SwapOut ACK is received, or
// when the timer times out, or when the RFHM itself is deleted (whichever
// comes first).
- pending_delete_hosts_.push_back(
- linked_ptr<RenderFrameHostImpl>(render_frame_host.release()));
+ pending_delete_hosts_.push_back(std::move(render_frame_host));
}
-bool RenderFrameHostManager::IsPendingDeletion(
- RenderFrameHostImpl* render_frame_host) {
+bool RenderFrameHostManager::IsViewPendingDeletion(
+ RenderViewHostImpl* render_view_host) {
+ // Only safe to call this on the main frame.
+ CHECK(frame_tree_node_->IsMainFrame());
+
+ // The view is not pending deletion if more than one frame or proxy references
+ // it.
+ if (render_view_host->ref_count() > 1)
+ return false;
+
+ // If the only thing referencing it is a frame on the pending deletion list,
+ // then this view will go away when the frame goes away.
for (const auto& rfh : pending_delete_hosts_) {
- if (rfh == render_frame_host)
+ if (rfh->GetRenderViewHost() == render_view_host)
return true;
}
return false;
@@ -793,7 +731,7 @@ bool RenderFrameHostManager::DeleteFromPendingList(
for (RFHPendingDeleteList::iterator iter = pending_delete_hosts_.begin();
iter != pending_delete_hosts_.end();
iter++) {
- if (*iter == render_frame_host) {
+ if (iter->get() == render_frame_host) {
pending_delete_hosts_.erase(iter);
return true;
}
@@ -802,24 +740,36 @@ bool RenderFrameHostManager::DeleteFromPendingList(
}
void RenderFrameHostManager::ResetProxyHosts() {
- for (auto& pair : proxy_hosts_) {
+ for (const auto& pair : proxy_hosts_) {
static_cast<SiteInstanceImpl*>(pair.second->GetSiteInstance())
->RemoveObserver(this);
}
proxy_hosts_.clear();
}
+void RenderFrameHostManager::ClearRFHsPendingShutdown() {
+ pending_delete_hosts_.clear();
+}
+
+void RenderFrameHostManager::ClearWebUIInstances() {
+ current_frame_host()->ClearAllWebUI();
+ if (pending_render_frame_host_)
+ pending_render_frame_host_->ClearAllWebUI();
+ // PlzNavigate
+ if (speculative_render_frame_host_)
+ speculative_render_frame_host_->ClearAllWebUI();
+}
+
// PlzNavigate
void RenderFrameHostManager::DidCreateNavigationRequest(
- const NavigationRequest& request) {
+ NavigationRequest* request) {
CHECK(IsBrowserSideNavigationEnabled());
- // Clean up any state in case there's an ongoing navigation.
- // TODO(carlosk): remove this cleanup here once we properly cancel ongoing
- // navigations.
- CleanUpNavigation();
-
- RenderFrameHostImpl* dest_rfh = GetFrameHostForNavigation(request);
+ RenderFrameHostImpl* dest_rfh = GetFrameHostForNavigation(*request);
DCHECK(dest_rfh);
+ request->set_associated_site_instance_type(
+ dest_rfh == render_frame_host_.get()
+ ? NavigationRequest::AssociatedSiteInstanceType::CURRENT
+ : NavigationRequest::AssociatedSiteInstanceType::SPECULATIVE);
}
// PlzNavigate
@@ -844,27 +794,35 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
// The appropriate RenderFrameHost to commit the navigation.
RenderFrameHostImpl* navigation_rfh = nullptr;
- // Renderer-initiated main frame navigations that may require a SiteInstance
- // swap are sent to the browser via the OpenURL IPC and are afterwards treated
- // as browser-initiated navigations. NavigationRequests marked as
- // renderer-initiated are created by receiving a BeginNavigation IPC, and will
- // then proceed in the same renderer that sent the IPC due to the condition
- // below.
- // Subframe navigations will use the current renderer, unless
- // --site-per-process is enabled.
- // TODO(carlosk): Have renderer-initated main frame navigations swap processes
- // if needed when it no longer breaks OAuth popups (see
- // https://crbug.com/440266).
- bool is_main_frame = frame_tree_node_->IsMainFrame();
bool notify_webui_of_rv_creation = false;
- if (current_site_instance == dest_site_instance.get() ||
- (!request.browser_initiated() && is_main_frame) ||
- (!is_main_frame && !dest_site_instance->RequiresDedicatedProcess() &&
- !current_site_instance->RequiresDedicatedProcess())) {
- // Reuse the current RenderFrameHost if its SiteInstance matches the
- // navigation's or if this is a subframe navigation. We only swap
- // RenderFrameHosts for subframes when --site-per-process is enabled.
+ // Reuse the current RenderFrameHost if its SiteInstance matches the
+ // navigation's.
+ bool no_renderer_swap = current_site_instance == dest_site_instance.get();
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ // Check if the current renderer should be changed for the navigation.
+ no_renderer_swap |=
+ render_frame_host_->IsRenderFrameLive() &&
+ ShouldMakeNetworkRequestForURL(request.common_params().url) &&
+ !IsRendererTransferNeededForNavigation(render_frame_host_.get(),
+ request.common_params().url);
+ } else {
+ // Subframe navigations will use the current renderer.
+ no_renderer_swap |= !frame_tree_node_->IsMainFrame();
+
+ // Renderer-initiated main frame navigations that may require a
+ // SiteInstance swap are sent to the browser via the OpenURL IPC and are
+ // afterwards treated as browser-initiated navigations. NavigationRequests
+ // marked as renderer-initiated are created by receiving a BeginNavigation
+ // IPC, and will then proceed in the same renderer that sent the IPC due to
+ // the condition below.
+ // TODO(carlosk): Have renderer-initated main frame navigations swap
+ // processes if needed when it no longer breaks OAuth popups (see
+ // https://crbug.com/440266).
+ no_renderer_swap |= !request.browser_initiated();
+ }
+
+ if (no_renderer_swap) {
// GetFrameHostForNavigation will be called more than once during a
// navigation (currently twice, on request and when it's about to commit in
// the renderer). In the follow up calls an existing pending WebUI should
@@ -917,6 +875,15 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
// (Note that we don't care about on{before}unload handlers if the current
// RFH isn't live.)
CommitPending();
+
+ // Notify the WebUI of the creation of the RenderView if needed (the
+ // newly created WebUI has just been committed by CommitPending, so
+ // GetNavigatingWebUI() below will return false).
+ if (notify_webui_of_rv_creation && render_frame_host_->web_ui()) {
+ render_frame_host_->web_ui()->RenderViewCreated(
+ render_frame_host_->render_view_host());
+ notify_webui_of_rv_creation = false;
+ }
}
}
DCHECK(navigation_rfh &&
@@ -957,9 +924,12 @@ RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
// PlzNavigate
void RenderFrameHostManager::CleanUpNavigation() {
CHECK(IsBrowserSideNavigationEnabled());
- render_frame_host_->ClearPendingWebUI();
- if (speculative_render_frame_host_)
+ if (speculative_render_frame_host_) {
+ bool was_loading = speculative_render_frame_host_->is_loading();
DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
+ if (was_loading)
+ frame_tree_node_->DidStopLoading();
+ }
}
// PlzNavigate
@@ -983,18 +953,17 @@ void RenderFrameHostManager::OnDidStopLoading() {
}
}
-void RenderFrameHostManager::OnDidUpdateName(const std::string& name) {
+void RenderFrameHostManager::OnDidUpdateName(const std::string& name,
+ const std::string& unique_name) {
// The window.name message may be sent outside of --site-per-process when
// report_frame_name_changes renderer preference is set (used by
// WebView). Don't send the update to proxies in those cases.
- // TODO(nick,nasko): Should this be IsSwappedOutStateForbidden, to match
- // OnDidUpdateOrigin?
if (!SiteIsolationPolicy::AreCrossProcessFramesPossible())
return;
for (const auto& pair : proxy_hosts_) {
- pair.second->Send(
- new FrameMsg_DidUpdateName(pair.second->GetRoutingID(), name));
+ pair.second->Send(new FrameMsg_DidUpdateName(pair.second->GetRoutingID(),
+ name, unique_name));
}
}
@@ -1009,22 +978,21 @@ void RenderFrameHostManager::OnEnforceStrictMixedContentChecking(
}
}
-void RenderFrameHostManager::OnDidUpdateOrigin(const url::Origin& origin) {
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden())
- return;
-
+void RenderFrameHostManager::OnDidUpdateOrigin(
+ const url::Origin& origin,
+ bool is_potentially_trustworthy_unique_origin) {
for (const auto& pair : proxy_hosts_) {
pair.second->Send(
- new FrameMsg_DidUpdateOrigin(pair.second->GetRoutingID(), origin));
+ new FrameMsg_DidUpdateOrigin(pair.second->GetRoutingID(), origin,
+ is_potentially_trustworthy_unique_origin));
}
}
RenderFrameHostManager::SiteInstanceDescriptor::SiteInstanceDescriptor(
BrowserContext* browser_context,
GURL dest_url,
- bool related_to_current)
- : existing_site_instance(nullptr),
- new_is_related_to_current(related_to_current) {
+ SiteInstanceRelation relation_to_current)
+ : existing_site_instance(nullptr), relation(relation_to_current) {
new_site_url = SiteInstance::GetSiteForURL(browser_context, dest_url);
}
@@ -1039,30 +1007,20 @@ void RenderFrameHostManager::ActiveFrameCountIsZero(
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(site_instance);
CHECK(proxy);
- // Delete the proxy. If it is for a main frame (and the RFH is stored
- // in the proxy) and it was still pending swap out, move the RFH to the
- // pending deletion list first.
- if (frame_tree_node_->IsMainFrame() && proxy->render_frame_host() &&
- proxy->render_frame_host()->rfh_state() ==
- RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) {
- DCHECK(!SiteIsolationPolicy::IsSwappedOutStateForbidden());
- scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
- proxy->PassFrameHostOwnership();
- MoveToPendingDeleteHosts(std::move(swapped_out_rfh));
- }
-
DeleteRenderFrameProxyHost(site_instance);
}
RenderFrameProxyHost* RenderFrameHostManager::CreateRenderFrameProxyHost(
SiteInstance* site_instance,
RenderViewHostImpl* rvh) {
- auto result = proxy_hosts_.add(site_instance->GetId(),
- make_scoped_ptr(new RenderFrameProxyHost(
- site_instance, rvh, frame_tree_node_)));
- CHECK(result.second) << "A proxy already existed for this SiteInstance.";
+ int site_instance_id = site_instance->GetId();
+ CHECK(proxy_hosts_.find(site_instance_id) == proxy_hosts_.end())
+ << "A proxy already existed for this SiteInstance.";
+ RenderFrameProxyHost* proxy_host =
+ new RenderFrameProxyHost(site_instance, rvh, frame_tree_node_);
+ proxy_hosts_[site_instance_id] = make_scoped_ptr(proxy_host);
static_cast<SiteInstanceImpl*>(site_instance)->AddObserver(this);
- return result.first->second;
+ return proxy_host;
}
void RenderFrameHostManager::DeleteRenderFrameProxyHost(
@@ -1173,7 +1131,8 @@ bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
return false;
}
-SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
+scoped_refptr<SiteInstance>
+RenderFrameHostManager::GetSiteInstanceForNavigation(
const GURL& dest_url,
SiteInstance* source_instance,
SiteInstance* dest_instance,
@@ -1217,15 +1176,15 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
dest_is_restore, dest_is_view_source_mode, force_swap);
}
- SiteInstance* new_instance =
+ scoped_refptr<SiteInstance> new_instance =
ConvertToSiteInstance(new_instance_descriptor, candidate_instance);
-
// If |force_swap| is true, we must use a different SiteInstance than the
// current one. If we didn't, we would have two RenderFrameHosts in the same
// SiteInstance and the same frame, resulting in page_id conflicts for their
// NavigationEntries.
if (force_swap)
CHECK_NE(new_instance, current_instance);
+
return new_instance;
}
@@ -1258,7 +1217,8 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
// If a swap is required, we need to force the SiteInstance AND
// BrowsingInstance to be different ones, using CreateForURL.
if (force_browsing_instance_swap)
- return SiteInstanceDescriptor(browser_context, dest_url, false);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::UNRELATED);
// (UGLY) HEURISTIC, process-per-site only:
//
@@ -1297,7 +1257,8 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
if (current_instance_impl->HasRelatedSiteInstance(dest_url) ||
use_process_per_site) {
- return SiteInstanceDescriptor(browser_context, dest_url, true);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::RELATED);
}
// For extensions, Web UI URLs (such as the new tab page), and apps we do
@@ -1305,20 +1266,23 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
// will have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance
// for this URL instead (with the correct process type).
if (current_instance_impl->HasWrongProcessForURL(dest_url))
- return SiteInstanceDescriptor(browser_context, dest_url, true);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::RELATED);
// View-source URLs must use a new SiteInstance and BrowsingInstance.
// TODO(nasko): This is the same condition as later in the function. This
// should be taken into account when refactoring this method as part of
// http://crbug.com/123007.
if (dest_is_view_source_mode)
- return SiteInstanceDescriptor(browser_context, dest_url, false);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::UNRELATED);
// If we are navigating from a blank SiteInstance to a WebUI, make sure we
// create a new SiteInstance.
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
browser_context, dest_url)) {
- return SiteInstanceDescriptor(browser_context, dest_url, false);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::UNRELATED);
}
// Normally the "site" on the SiteInstance is set lazily when the load
@@ -1368,7 +1332,8 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
if (current_entry &&
current_entry->IsViewSourceMode() != dest_is_view_source_mode &&
!IsRendererDebugURL(dest_url)) {
- return SiteInstanceDescriptor(browser_context, dest_url, false);
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::UNRELATED);
}
// Use the source SiteInstance in case of data URLs or about:blank pages,
@@ -1380,22 +1345,43 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
return SiteInstanceDescriptor(source_instance);
}
- // Use the current SiteInstance for same site navigations, as long as the
- // process type is correct. (The URL may have been installed as an app since
- // the last time we visited it.)
- const GURL& current_url =
- GetCurrentURLForSiteInstance(current_instance_impl, current_entry);
- if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
- !current_instance_impl->HasWrongProcessForURL(dest_url)) {
- return SiteInstanceDescriptor(current_instance_impl);
+ // Use the current SiteInstance for same site navigations.
+ if (IsCurrentlySameSite(render_frame_host_.get(), dest_url))
+ return SiteInstanceDescriptor(render_frame_host_->GetSiteInstance());
+
+ if (SiteIsolationPolicy::IsTopDocumentIsolationEnabled()) {
+ // TODO(nick): Looking at the main frame and openers is required for TDI
+ // mode, but should be safe to enable unconditionally.
+ if (!frame_tree_node_->IsMainFrame()) {
+ RenderFrameHostImpl* main_frame =
+ frame_tree_node_->frame_tree()->root()->current_frame_host();
+ if (IsCurrentlySameSite(main_frame, dest_url))
+ return SiteInstanceDescriptor(main_frame->GetSiteInstance());
+ }
+
+ if (frame_tree_node_->opener()) {
+ RenderFrameHostImpl* opener_frame =
+ frame_tree_node_->opener()->current_frame_host();
+ if (IsCurrentlySameSite(opener_frame, dest_url))
+ return SiteInstanceDescriptor(opener_frame->GetSiteInstance());
+ }
+ }
+
+ if (!frame_tree_node_->IsMainFrame() &&
+ SiteIsolationPolicy::IsTopDocumentIsolationEnabled() &&
+ !SiteInstanceImpl::DoesSiteRequireDedicatedProcess(browser_context,
+ dest_url)) {
+ // This is a cross-site subframe of a non-isolated origin, so place this
+ // frame in the default subframe site instance.
+ return SiteInstanceDescriptor(
+ browser_context, dest_url,
+ SiteInstanceRelation::RELATED_DEFAULT_SUBFRAME);
}
// Start the new renderer in a new SiteInstance, but in the current
- // BrowsingInstance. It is important to immediately give this new
- // SiteInstance to a RenderViewHost (if it is different than our current
- // SiteInstance), so that it is ref counted. This will happen in
- // CreateRenderView.
- return SiteInstanceDescriptor(browser_context, dest_url, true);
+ // BrowsingInstance.
+ return SiteInstanceDescriptor(browser_context, dest_url,
+ SiteInstanceRelation::RELATED);
}
bool RenderFrameHostManager::IsRendererTransferNeededForNavigation(
@@ -1424,23 +1410,34 @@ bool RenderFrameHostManager::IsRendererTransferNeededForNavigation(
// TODO(nasko, nick): These following --site-per-process checks are
// overly simplistic. Update them to match all the cases
// considered by DetermineSiteInstanceForURL.
- if (SiteInstance::IsSameWebSite(rfh->GetSiteInstance()->GetBrowserContext(),
- rfh->GetSiteInstance()->GetSiteURL(),
- dest_url)) {
- return false; // The same site, no transition needed.
+ if (IsCurrentlySameSite(rfh, dest_url)) {
+ // The same site, no transition needed for security purposes, and we must
+ // keep the same SiteInstance for correctness of synchronous scripting.
+ return false;
}
// The sites differ. If either one requires a dedicated process,
// then a transfer is needed.
- return rfh->GetSiteInstance()->RequiresDedicatedProcess() ||
- SiteInstanceImpl::DoesSiteRequireDedicatedProcess(context,
- effective_url);
+ if (rfh->GetSiteInstance()->RequiresDedicatedProcess() ||
+ SiteInstanceImpl::DoesSiteRequireDedicatedProcess(context,
+ effective_url)) {
+ return true;
+ }
+
+ if (SiteIsolationPolicy::IsTopDocumentIsolationEnabled() &&
+ (!frame_tree_node_->IsMainFrame() ||
+ rfh->GetSiteInstance()->is_default_subframe_site_instance())) {
+ // Always attempt a transfer in these cases.
+ return true;
+ }
+
+ return false;
}
-SiteInstance* RenderFrameHostManager::ConvertToSiteInstance(
+scoped_refptr<SiteInstance> RenderFrameHostManager::ConvertToSiteInstance(
const SiteInstanceDescriptor& descriptor,
SiteInstance* candidate_instance) {
- SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
+ SiteInstanceImpl* current_instance = render_frame_host_->GetSiteInstance();
// Note: If the |candidate_instance| matches the descriptor, it will already
// be set to |descriptor.existing_site_instance|.
@@ -1449,9 +1446,12 @@ SiteInstance* RenderFrameHostManager::ConvertToSiteInstance(
// Note: If the |candidate_instance| matches the descriptor,
// GetRelatedSiteInstance will return it.
- if (descriptor.new_is_related_to_current)
+ if (descriptor.relation == SiteInstanceRelation::RELATED)
return current_instance->GetRelatedSiteInstance(descriptor.new_site_url);
+ if (descriptor.relation == SiteInstanceRelation::RELATED_DEFAULT_SUBFRAME)
+ return current_instance->GetDefaultSubframeSiteInstance();
+
// At this point we know an unrelated site instance must be returned. First
// check if the candidate matches.
if (candidate_instance &&
@@ -1466,40 +1466,54 @@ SiteInstance* RenderFrameHostManager::ConvertToSiteInstance(
descriptor.new_site_url);
}
-const GURL& RenderFrameHostManager::GetCurrentURLForSiteInstance(
- SiteInstance* current_instance, NavigationEntry* current_entry) {
- // If this is a subframe that is potentially out of process from its parent,
- // don't consider using current_entry's url for SiteInstance selection, since
- // current_entry's url is for the main frame and may be in a different site
- // than this frame.
- // TODO(creis): Remove this when we can check the FrameNavigationEntry's url.
- // See http://crbug.com/369654
- if (!frame_tree_node_->IsMainFrame() &&
- SiteIsolationPolicy::AreCrossProcessFramesPossible())
- return frame_tree_node_->current_url();
-
- // If there is no last non-interstitial entry (and current_instance already
- // has a site), then we must have been opened from another tab. We want
- // to compare against the URL of the page that opened us, but we can't
- // get to it directly. The best we can do is check against the site of
- // the SiteInstance. This will be correct when we intercept links and
- // script-based navigations, but for now, it could place some pages in a
- // new process unnecessarily. We should only hit this case if a page tries
- // to open a new tab to an interstitial-inducing URL, and then navigates
- // the page to a different same-site URL. (This seems very unlikely in
- // practice.)
- if (current_entry)
- return current_entry->GetURL();
- return current_instance->GetSiteURL();
+bool RenderFrameHostManager::IsCurrentlySameSite(RenderFrameHostImpl* candidate,
+ const GURL& dest_url) {
+ BrowserContext* browser_context =
+ delegate_->GetControllerForRenderManager().GetBrowserContext();
+
+ // If the process type is incorrect, reject the candidate even if |dest_url|
+ // is same-site. (The URL may have been installed as an app since
+ // the last time we visited it.)
+ if (candidate->GetSiteInstance()->HasWrongProcessForURL(dest_url))
+ return false;
+
+ // If we don't have a last successful URL, we can't trust the origin or URL
+ // stored on the frame, so we fall back to GetSiteURL(). This case occurs
+ // after commits of net errors, since net errors do not currently swap
+ // processes for transfer navigations. Note: browser-initiated net errors do
+ // swap processes, but the frame's last successful URL will still be empty in
+ // that case.
+ if (candidate->last_successful_url().is_empty()) {
+ // TODO(creis): GetSiteURL() is not 100% accurate. Eliminate this fallback.
+ return SiteInstance::IsSameWebSite(
+ browser_context, candidate->GetSiteInstance()->GetSiteURL(), dest_url);
+ }
+
+ // In the common case, we use the RenderFrameHost's last successful URL. Thus,
+ // we compare against the last successful commit when deciding whether to swap
+ // this time.
+ if (SiteInstance::IsSameWebSite(browser_context,
+ candidate->last_successful_url(), dest_url)) {
+ return true;
+ }
+
+ // It is possible that last_successful_url() was a nonstandard scheme (for
+ // example, "about:blank"). If so, examine the replicated origin to determine
+ // the site.
+ if (!candidate->GetLastCommittedOrigin().unique() &&
+ SiteInstance::IsSameWebSite(
+ browser_context,
+ GURL(candidate->GetLastCommittedOrigin().Serialize()), dest_url)) {
+ return true;
+ }
+
+ // Not same-site.
+ return false;
}
void RenderFrameHostManager::CreatePendingRenderFrameHost(
SiteInstance* old_instance,
SiteInstance* new_instance) {
- int create_render_frame_flags = 0;
- if (delegate_->IsHidden())
- create_render_frame_flags |= CREATE_RF_HIDDEN;
-
if (pending_render_frame_host_)
CancelPending();
@@ -1514,7 +1528,7 @@ void RenderFrameHostManager::CreatePendingRenderFrameHost(
// Create a non-swapped-out RFH with the given opener.
pending_render_frame_host_ =
- CreateRenderFrame(new_instance, create_render_frame_flags, nullptr);
+ CreateRenderFrame(new_instance, delegate_->IsHidden(), nullptr);
}
void RenderFrameHostManager::CreateProxiesForNewRenderFrameHost(
@@ -1570,19 +1584,16 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
int32_t view_routing_id,
int32_t frame_routing_id,
int32_t widget_routing_id,
- int flags) {
+ bool hidden) {
if (frame_routing_id == MSG_ROUTING_NONE)
frame_routing_id = site_instance->GetProcess()->GetNextRoutingID();
- bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
- bool hidden = !!(flags & CREATE_RF_HIDDEN);
-
// Create a RVH for main frames, or find the existing one for subframes.
FrameTree* frame_tree = frame_tree_node_->frame_tree();
RenderViewHostImpl* render_view_host = nullptr;
if (frame_tree_node_->IsMainFrame()) {
render_view_host = frame_tree->CreateRenderViewHost(
- site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
+ site_instance, view_routing_id, frame_routing_id, false, hidden);
// TODO(avi): It's a bit bizarre that this logic lives here instead of in
// CreateRenderFrame(). It turns out that FrameTree::CreateRenderViewHost
// doesn't /always/ create a new RenderViewHost. It first tries to find an
@@ -1605,7 +1616,7 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
return RenderFrameHostFactory::Create(
site_instance, render_view_host, render_frame_delegate_,
render_widget_delegate_, frame_tree, frame_tree_node_, frame_routing_id,
- widget_routing_id, flags);
+ widget_routing_id, hidden);
}
// PlzNavigate
@@ -1624,31 +1635,23 @@ bool RenderFrameHostManager::CreateSpeculativeRenderFrameHost(
CreateProxiesForNewRenderFrameHost(old_instance, new_instance);
- int create_render_frame_flags = 0;
- if (delegate_->IsHidden())
- create_render_frame_flags |= CREATE_RF_HIDDEN;
speculative_render_frame_host_ =
- CreateRenderFrame(new_instance, create_render_frame_flags, nullptr);
+ CreateRenderFrame(new_instance, delegate_->IsHidden(), nullptr);
return !!speculative_render_frame_host_;
}
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame(
SiteInstance* instance,
- int flags,
+ bool hidden,
int* view_routing_id_ptr) {
- bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
- bool swapped_out_forbidden =
- SiteIsolationPolicy::IsSwappedOutStateForbidden();
+ int32_t widget_routing_id = MSG_ROUTING_NONE;
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
CHECK(instance);
- CHECK(!swapped_out_forbidden || !swapped_out);
CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible() ||
frame_tree_node_->IsMainFrame());
- // Swapped out views should always be hidden.
- DCHECK(!swapped_out || (flags & CREATE_RF_HIDDEN));
-
scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
bool success = true;
if (view_routing_id_ptr)
@@ -1658,101 +1661,58 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrame(
// never create it in the same SiteInstance as our current RFH.
CHECK_NE(render_frame_host_->GetSiteInstance(), instance);
- // Check if we've already created an RFH for this SiteInstance. If so, try
- // to re-use the existing one, which has already been initialized. We'll
- // remove it from the list of proxy hosts below if it will be active.
- RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
- if (proxy && proxy->render_frame_host()) {
- RenderViewHost* render_view_host = proxy->GetRenderViewHost();
- CHECK(!swapped_out_forbidden);
- if (view_routing_id_ptr)
- *view_routing_id_ptr = proxy->GetRenderViewHost()->GetRoutingID();
- // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
- // Prevent the process from exiting while we're trying to use it.
- if (!swapped_out) {
- new_render_frame_host = proxy->PassFrameHostOwnership();
- new_render_frame_host->GetProcess()->AddPendingView();
-
- DeleteRenderFrameProxyHost(instance);
- // NB |proxy| is deleted at this point.
-
- // If we are reusing the RenderViewHost and it doesn't already have a
- // RenderWidgetHostView, we need to create one if this is the main frame.
- if (render_view_host->IsRenderViewLive() &&
- !render_view_host->GetWidget()->GetView() &&
- frame_tree_node_->IsMainFrame()) {
- delegate_->CreateRenderWidgetHostViewForRenderManager(render_view_host);
- }
- }
- } else {
- // Create a new RenderFrameHost if we don't find an existing one.
+ // A RenderFrame in a different process from its parent RenderFrame
+ // requires a RenderWidget for input/layout/painting.
+ if (frame_tree_node_->parent() &&
+ frame_tree_node_->parent()->current_frame_host()->GetSiteInstance() !=
+ instance) {
+ CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
+ widget_routing_id = instance->GetProcess()->GetNextRoutingID();
+ }
- int32_t widget_routing_id = MSG_ROUTING_NONE;
+ new_render_frame_host = CreateRenderFrameHost(
+ instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, widget_routing_id, hidden);
+ RenderViewHostImpl* render_view_host =
+ new_render_frame_host->render_view_host();
- // A RenderFrame in a different process from its parent RenderFrame
- // requires a RenderWidget for input/layout/painting.
- if (frame_tree_node_->parent() &&
- frame_tree_node_->parent()->current_frame_host()->GetSiteInstance() !=
- instance) {
- CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
- widget_routing_id = instance->GetProcess()->GetNextRoutingID();
- }
+ // Prevent the process from exiting while we're trying to navigate in it.
+ new_render_frame_host->GetProcess()->AddPendingView();
- new_render_frame_host = CreateRenderFrameHost(
- instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, widget_routing_id, flags);
- RenderViewHostImpl* render_view_host =
- new_render_frame_host->render_view_host();
+ if (frame_tree_node_->IsMainFrame()) {
+ success = InitRenderView(render_view_host, proxy);
- // Prevent the process from exiting while we're trying to navigate in it.
- // Otherwise, if the new RFH is swapped out already, store it.
- if (!swapped_out) {
- new_render_frame_host->GetProcess()->AddPendingView();
- } else {
- proxy =
- CreateRenderFrameProxyHost(new_render_frame_host->GetSiteInstance(),
- new_render_frame_host->render_view_host());
- proxy->TakeFrameHostOwnership(std::move(new_render_frame_host));
- }
+ // If we are reusing the RenderViewHost and it doesn't already have a
+ // RenderWidgetHostView, we need to create one if this is the main frame.
+ if (!render_view_host->GetWidget()->GetView())
+ delegate_->CreateRenderWidgetHostViewForRenderManager(render_view_host);
+ } else {
+ DCHECK(render_view_host->IsRenderViewLive());
+ }
+ if (success) {
if (frame_tree_node_->IsMainFrame()) {
- success = InitRenderView(render_view_host, proxy);
-
- // If we are reusing the RenderViewHost and it doesn't already have a
- // RenderWidgetHostView, we need to create one if this is the main frame.
- if (!swapped_out && !render_view_host->GetWidget()->GetView())
- delegate_->CreateRenderWidgetHostViewForRenderManager(render_view_host);
- } else {
- DCHECK(render_view_host->IsRenderViewLive());
- }
-
- if (success) {
- if (frame_tree_node_->IsMainFrame()) {
- // Don't show the main frame's view until we get a DidNavigate from it.
- // Only the RenderViewHost for the top-level RenderFrameHost has a
- // RenderWidgetHostView; RenderWidgetHosts for out-of-process iframes
- // will be created later and hidden.
- if (render_view_host->GetWidget()->GetView())
- render_view_host->GetWidget()->GetView()->Hide();
- }
- // RenderViewHost for |instance| might exist prior to calling
- // CreateRenderFrame. In such a case, InitRenderView will not create the
- // RenderFrame in the renderer process and it needs to be done
- // explicitly.
- if (swapped_out_forbidden) {
- // Init the RFH, so a RenderFrame is created in the renderer.
- DCHECK(new_render_frame_host);
- success = InitRenderFrame(new_render_frame_host.get());
- }
+ // Don't show the main frame's view until we get a DidNavigate from it.
+ // Only the RenderViewHost for the top-level RenderFrameHost has a
+ // RenderWidgetHostView; RenderWidgetHosts for out-of-process iframes
+ // will be created later and hidden.
+ if (render_view_host->GetWidget()->GetView())
+ render_view_host->GetWidget()->GetView()->Hide();
}
+ // RenderViewHost for |instance| might exist prior to calling
+ // CreateRenderFrame. In such a case, InitRenderView will not create the
+ // RenderFrame in the renderer process and it needs to be done
+ // explicitly.
+ DCHECK(new_render_frame_host);
+ success = InitRenderFrame(new_render_frame_host.get());
+ }
- if (success) {
- if (view_routing_id_ptr)
- *view_routing_id_ptr = render_view_host->GetRoutingID();
- }
+ if (success) {
+ if (view_routing_id_ptr)
+ *view_routing_id_ptr = render_view_host->GetRoutingID();
}
- // Returns the new RFH if it isn't swapped out.
- if (success && !swapped_out) {
+ // Return the new RenderFrameHost on successful creation.
+ if (success) {
DCHECK(new_render_frame_host->GetSiteInstance() == instance);
return new_render_frame_host;
}
@@ -1769,14 +1729,12 @@ int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
// Ensure a RenderViewHost exists for |instance|, as it creates the page
// level structure in Blink.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- render_view_host =
- frame_tree_node_->frame_tree()->GetRenderViewHost(instance);
- if (!render_view_host) {
- CHECK(frame_tree_node_->IsMainFrame());
- render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost(
- instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, true, true);
- }
+ render_view_host =
+ frame_tree_node_->frame_tree()->GetRenderViewHost(instance);
+ if (!render_view_host) {
+ CHECK(frame_tree_node_->IsMainFrame());
+ render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost(
+ instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, true, true);
}
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
@@ -1786,8 +1744,7 @@ int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
if (!proxy)
proxy = CreateRenderFrameProxyHost(instance, render_view_host);
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden() &&
- frame_tree_node_->IsMainFrame()) {
+ if (frame_tree_node_->IsMainFrame()) {
InitRenderView(render_view_host, proxy);
} else {
proxy->InitRenderFrameProxy();
@@ -1802,7 +1759,7 @@ void RenderFrameHostManager::CreateProxiesForChildFrame(FrameTreeNode* child) {
for (const auto& pair : proxy_hosts_) {
// Do not create proxies for subframes in the outer delegate's process,
// since the outer delegate does not need to interact with them.
- if (pair.second == outer_delegate_proxy)
+ if (pair.second.get() == outer_delegate_proxy)
continue;
child->render_manager()->CreateRenderFrameProxy(
@@ -1844,7 +1801,8 @@ void RenderFrameHostManager::CreateOuterDelegateProxy(
// investigate and fix.
render_frame_host->Send(new FrameMsg_SwapOut(
render_frame_host->GetRoutingID(), proxy->GetRoutingID(),
- false /* is_loading */, FrameReplicationState()));
+ false /* is_loading */,
+ render_frame_host->frame_tree_node()->current_replication_state()));
proxy->set_render_frame_proxy_created(true);
}
@@ -1925,8 +1883,95 @@ bool RenderFrameHostManager::InitRenderFrame(
if (existing_proxy) {
proxy_routing_id = existing_proxy->GetRoutingID();
CHECK_NE(proxy_routing_id, MSG_ROUTING_NONE);
- if (!existing_proxy->is_render_frame_proxy_live())
+ if (!existing_proxy->is_render_frame_proxy_live()) {
+ // Calling InitRenderFrameProxy on main frames seems to be causing
+ // https://crbug.com/575245, so track down how this can happen.
+ // TODO(creis): Remove this once we've found the cause.
+ if (!frame_tree_node_->parent()) {
+ base::debug::SetCrashKeyValue(
+ "initrf_frame_id",
+ base::IntToString(render_frame_host->GetRoutingID()));
+ base::debug::SetCrashKeyValue("initrf_proxy_id",
+ base::IntToString(proxy_routing_id));
+ base::debug::SetCrashKeyValue(
+ "initrf_view_id",
+ base::IntToString(
+ render_frame_host->render_view_host()->GetRoutingID()));
+ base::debug::SetCrashKeyValue(
+ "initrf_main_frame_id",
+ base::IntToString(render_frame_host->render_view_host()
+ ->main_frame_routing_id()));
+ base::debug::SetCrashKeyValue(
+ "initrf_view_is_live",
+ render_frame_host->render_view_host()->IsRenderViewLive() ? "yes"
+ : "no");
+ base::debug::DumpWithoutCrashing();
+ }
+
existing_proxy->InitRenderFrameProxy();
+ }
+ }
+
+ // TODO(alexmos): These crash keys are temporary to track down
+ // https://crbug.com/591478. Verify that the parent routing ID
+ // points to a live RenderFrameProxy when this is not a remote-to-local
+ // navigation (i.e., when there's no |existing_proxy|).
+ if (!existing_proxy && frame_tree_node_->parent()) {
+ RenderFrameProxyHost* parent_proxy = RenderFrameProxyHost::FromID(
+ render_frame_host->GetProcess()->GetID(), parent_routing_id);
+ if (!parent_proxy || !parent_proxy->is_render_frame_proxy_live()) {
+ base::debug::SetCrashKeyValue("initrf_parent_proxy_exists",
+ parent_proxy ? "yes" : "no");
+
+ SiteInstance* parent_instance =
+ frame_tree_node_->parent()->current_frame_host()->GetSiteInstance();
+ base::debug::SetCrashKeyValue(
+ "initrf_parent_is_in_same_site_instance",
+ site_instance == parent_instance ? "yes" : "no");
+ base::debug::SetCrashKeyValue("initrf_parent_process_is_live",
+ frame_tree_node_->parent()
+ ->current_frame_host()
+ ->GetProcess()
+ ->HasConnection()
+ ? "yes"
+ : "no");
+ base::debug::SetCrashKeyValue(
+ "initrf_render_view_is_live",
+ render_frame_host->render_view_host()->IsRenderViewLive() ? "yes"
+ : "no");
+
+ // Collect some additional information for root's proxy if it's different
+ // from the parent.
+ FrameTreeNode* root = frame_tree_node_->frame_tree()->root();
+ if (root != frame_tree_node_->parent()) {
+ SiteInstance* root_instance =
+ root->current_frame_host()->GetSiteInstance();
+ base::debug::SetCrashKeyValue(
+ "initrf_root_is_in_same_site_instance",
+ site_instance == root_instance ? "yes" : "no");
+ base::debug::SetCrashKeyValue(
+ "initrf_root_is_in_same_site_instance_as_parent",
+ parent_instance == root_instance ? "yes" : "no");
+ base::debug::SetCrashKeyValue("initrf_root_process_is_live",
+ frame_tree_node_->frame_tree()
+ ->root()
+ ->current_frame_host()
+ ->GetProcess()
+ ->HasConnection()
+ ? "yes"
+ : "no");
+
+ RenderFrameProxyHost* top_proxy =
+ root->render_manager()->GetRenderFrameProxyHost(site_instance);
+ if (top_proxy) {
+ base::debug::SetCrashKeyValue(
+ "initrf_root_proxy_is_live",
+ top_proxy->is_render_frame_proxy_live() ? "yes" : "no");
+ }
+ }
+
+ base::debug::DumpWithoutCrashing();
+ }
}
return delegate_->CreateRenderFrameForRenderManager(
@@ -1939,14 +1984,6 @@ int RenderFrameHostManager::GetRoutingIdForSiteInstance(
if (render_frame_host_->GetSiteInstance() == site_instance)
return render_frame_host_->GetRoutingID();
- // If there is a matching pending RFH, only return it if swapped out is
- // allowed, since otherwise there should be a proxy that should be used
- // instead.
- if (pending_render_frame_host_ &&
- pending_render_frame_host_->GetSiteInstance() == site_instance &&
- !SiteIsolationPolicy::IsSwappedOutStateForbidden())
- return pending_render_frame_host_->GetRoutingID();
-
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(site_instance);
if (proxy)
return proxy->GetRoutingID();
@@ -2022,6 +2059,7 @@ void RenderFrameHostManager::CommitPending() {
// now to make sure the sad tab shows up, etc.
DCHECK(!render_frame_host_->IsRenderFrameLive());
DCHECK(!render_frame_host_->render_view_host()->IsRenderViewLive());
+ render_frame_host_->ResetLoadingState();
delegate_->RenderProcessGoneFromRenderManager(
render_frame_host_->render_view_host());
}
@@ -2059,7 +2097,7 @@ void RenderFrameHostManager::CommitPending() {
// If this is committing a main frame navigation, update it and set the
// routing id in the RenderViewHost associated with the old RenderFrameHost
// to MSG_ROUTING_NONE.
- if (is_main_frame && SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
+ if (is_main_frame) {
render_frame_host_->render_view_host()->set_main_frame_routing_id(
render_frame_host_->routing_id());
old_render_frame_host->render_view_host()->set_main_frame_routing_id(
@@ -2067,18 +2105,13 @@ void RenderFrameHostManager::CommitPending() {
}
// Swap out the old frame now that the new one is visible.
- // This will swap it out and then put it on the proxy list (if there are other
- // active views in its SiteInstance) or schedule it for deletion when the swap
- // out ack arrives (or immediately if the process isn't live).
- // In the --site-per-process case, old subframe RFHs are not kept alive inside
- // the proxy.
+ // This will swap it out and schedule it for deletion when the swap out ack
+ // arrives (or immediately if the process isn't live).
SwapOutOldFrame(std::move(old_render_frame_host));
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- // Since the new RenderFrameHost is now committed, there must be no proxies
- // for its SiteInstance. Delete any existing ones.
- DeleteRenderFrameProxyHost(render_frame_host_->GetSiteInstance());
- }
+ // Since the new RenderFrameHost is now committed, there must be no proxies
+ // for its SiteInstance. Delete any existing ones.
+ DeleteRenderFrameProxyHost(render_frame_host_->GetSiteInstance());
// If this is a subframe, it should have a CrossProcessFrameConnector
// created already. Use it to link the new RFH's view to the proxy that
@@ -2232,9 +2265,9 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
// The renderer can exit view source mode when any error or cancellation
// happen. We must overwrite to recover the mode.
if (dest_is_view_source_mode) {
- render_frame_host_->render_view_host()->Send(
- new ViewMsg_EnableViewSourceMode(
- render_frame_host_->render_view_host()->GetRoutingID()));
+ DCHECK(!render_frame_host_->GetParent());
+ render_frame_host_->Send(
+ new FrameMsg_EnableViewSourceMode(render_frame_host_->GetRoutingID()));
}
return render_frame_host_.get();
@@ -2273,7 +2306,11 @@ void RenderFrameHostManager::CancelPending() {
TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending",
"FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
render_frame_host_->ClearPendingWebUI();
+
+ bool pending_was_loading = pending_render_frame_host_->is_loading();
DiscardUnusedFrame(UnsetPendingRenderFrameHost());
+ if (pending_was_loading)
+ frame_tree_node_->DidStopLoading();
}
scoped_ptr<RenderFrameHostImpl>
@@ -2352,16 +2389,12 @@ RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost(
SiteInstance* instance) const {
auto it = proxy_hosts_.find(instance->GetId());
if (it != proxy_hosts_.end())
- return it->second;
+ return it->second.get();
return nullptr;
}
-std::map<int, RenderFrameProxyHost*>
-RenderFrameHostManager::GetAllProxyHostsForTesting() {
- std::map<int, RenderFrameProxyHost*> result;
- for (const auto& pair : proxy_hosts_)
- result[pair.first] = pair.second;
- return result;
+int RenderFrameHostManager::GetProxyCount() {
+ return proxy_hosts_.size();
}
void RenderFrameHostManager::CollectOpenerFrameTrees(
@@ -2370,12 +2403,39 @@ void RenderFrameHostManager::CollectOpenerFrameTrees(
CHECK(opener_frame_trees);
opener_frame_trees->push_back(frame_tree_node_->frame_tree());
+ // Add the FrameTree of the given node's opener to the list of
+ // |opener_frame_trees| if it doesn't exist there already. |visited_index|
+ // indicates which FrameTrees in |opener_frame_trees| have already been
+ // visited (i.e., those at indices less than |visited_index|).
+ // |nodes_with_back_links| collects FrameTreeNodes with openers in FrameTrees
+ // that have already been visited (such as those with cycles).
size_t visited_index = 0;
while (visited_index < opener_frame_trees->size()) {
FrameTree* frame_tree = (*opener_frame_trees)[visited_index];
visited_index++;
- frame_tree->ForEach(base::Bind(&OpenerForFrameTreeNode, visited_index,
- opener_frame_trees, nodes_with_back_links));
+ for (FrameTreeNode* node : frame_tree->Nodes()) {
+ if (!node->opener())
+ continue;
+
+ FrameTree* opener_tree = node->opener()->frame_tree();
+ const auto& existing_tree_it = std::find(
+ opener_frame_trees->begin(), opener_frame_trees->end(), opener_tree);
+
+ if (existing_tree_it == opener_frame_trees->end()) {
+ // This is a new opener tree that we will need to process.
+ opener_frame_trees->push_back(opener_tree);
+ } else {
+ // If this tree is already on our processing list *and* we have visited
+ // it,
+ // then this node's opener is a back link. This means the node will
+ // need
+ // special treatment to process its opener.
+ size_t position =
+ std::distance(opener_frame_trees->begin(), existing_tree_it);
+ if (position < visited_index)
+ nodes_with_back_links->insert(node);
+ }
+ }
}
}
@@ -2443,29 +2503,29 @@ void RenderFrameHostManager::CreateOpenerProxiesForFrameTree(
} else {
// If any of the RenderViewHosts (current, pending, or swapped out) for this
// FrameTree has the same SiteInstance, then we can return early and reuse
- // them. An exception is if we are in IsSwappedOutStateForbidden mode and
- // find a pending RenderViewHost: in this case, we should still create a
- // proxy, which will allow communicating with the opener until the pending
- // RenderView commits, or if the pending navigation is canceled.
+ // them. An exception is if we find a pending RenderViewHost: in this case,
+ // we should still create a proxy, which will allow communicating with the
+ // opener until the pending RenderView commits, or if the pending navigation
+ // is canceled.
+ // PlzNavigate: similarly, if a speculative RenderViewHost is present, a
+ // proxy should be created.
RenderViewHostImpl* rvh = frame_tree->GetRenderViewHost(instance);
- bool need_proxy_for_pending_rvh =
- SiteIsolationPolicy::IsSwappedOutStateForbidden() &&
- (rvh == pending_render_view_host());
- if (rvh && rvh->IsRenderViewLive() && !need_proxy_for_pending_rvh)
+ bool need_proxy_for_pending_rvh = (rvh == pending_render_view_host());
+ bool need_proxy_for_speculative_rvh =
+ IsBrowserSideNavigationEnabled() && speculative_render_frame_host_ &&
+ speculative_render_frame_host_->GetRenderViewHost() == rvh;
+ if (rvh && rvh->IsRenderViewLive() && !need_proxy_for_pending_rvh &&
+ !need_proxy_for_speculative_rvh) {
return;
+ }
if (rvh && !rvh->IsRenderViewLive()) {
EnsureRenderViewInitialized(rvh, instance);
} else {
- // Create a swapped out RenderView in the given SiteInstance if none
+ // Create a RenderFrameProxyHost in the given SiteInstance if none
// exists. Since an opener can point to a subframe, do this on the root
// frame of the current opener's frame tree.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- frame_tree->root()->render_manager()->CreateRenderFrameProxy(instance);
- } else {
- frame_tree->root()->render_manager()->CreateRenderFrame(
- instance, CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
- }
+ frame_tree->root()->render_manager()->CreateRenderFrameProxy(instance);
}
}
}
@@ -2479,4 +2539,36 @@ int RenderFrameHostManager::GetOpenerRoutingID(SiteInstance* instance) {
->GetRoutingIdForSiteInstance(instance);
}
+void RenderFrameHostManager::SendPageMessage(IPC::Message* msg) {
+ DCHECK(IPC_MESSAGE_CLASS(*msg) == PageMsgStart);
+
+ // We should always deliver page messages through the main frame.
+ DCHECK(!frame_tree_node_->parent());
+
+ if ((IPC_MESSAGE_CLASS(*msg) != PageMsgStart) || frame_tree_node_->parent()) {
+ delete msg;
+ return;
+ }
+
+ auto send_msg = [](IPC::Sender* sender, int routing_id, IPC::Message* msg) {
+ IPC::Message* copy = new IPC::Message(*msg);
+ copy->set_routing_id(routing_id);
+ sender->Send(copy);
+ };
+
+ for (const auto& pair : proxy_hosts_)
+ send_msg(pair.second.get(), pair.second->GetRoutingID(), msg);
+
+ if (speculative_render_frame_host_) {
+ send_msg(speculative_render_frame_host_.get(),
+ speculative_render_frame_host_->GetRoutingID(), msg);
+ } else if (pending_render_frame_host_) {
+ send_msg(pending_render_frame_host_.get(),
+ pending_render_frame_host_->GetRoutingID(), msg);
+ }
+
+ msg->set_routing_id(render_frame_host_->GetRoutingID());
+ render_frame_host_->Send(msg);
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager.h b/chromium/content/browser/frame_host/render_frame_host_manager.h
index b3b1d7439ce..63a42776833 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.h
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.h
@@ -9,9 +9,9 @@
#include <list>
#include <map>
+#include <unordered_map>
#include "base/containers/hash_tables.h"
-#include "base/containers/scoped_ptr_hash_map.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
@@ -179,15 +179,6 @@ class CONTENT_EXPORT RenderFrameHostManager
virtual ~Delegate() {}
};
- // Used with FrameTree::ForEach to delete RenderFrameHosts pending shutdown
- // from a FrameTreeNode's RenderFrameHostManager. Used during destruction of
- // WebContentsImpl.
- static bool ClearRFHsPendingShutdown(FrameTreeNode* node);
-
- // Used with FrameTree::ForEach to destroy all WebUI instances associated with
- // RenderFrameHosts.
- static bool ClearWebUIInstances(FrameTreeNode* node);
-
// All three delegate pointers must be non-NULL and are not owned by this
// class. They must outlive this class. The RenderViewHostDelegate and
// RenderWidgetHostDelegate are what will be installed into all
@@ -344,13 +335,11 @@ class CONTENT_EXPORT RenderFrameHostManager
void DidChangeOpener(int opener_routing_id,
SiteInstance* source_site_instance);
- // Creates and initializes a RenderFrameHost. If |flags| has the
- // CREATE_RF_SWAPPED_OUT bit set from the CreateRenderFrameFlags enum, it will
- // initially be placed on the swapped out hosts list. If |view_routing_id_ptr|
+ // Creates and initializes a RenderFrameHost. If |view_routing_id_ptr|
// is not nullptr it will be set to the routing id of the view associated with
// the frame.
scoped_ptr<RenderFrameHostImpl> CreateRenderFrame(SiteInstance* instance,
- int flags,
+ bool hidden,
int* view_routing_id_ptr);
// Helper method to create and initialize a RenderFrameProxyHost and return
@@ -395,8 +384,9 @@ class CONTENT_EXPORT RenderFrameHostManager
RenderFrameProxyHost* GetRenderFrameProxyHost(
SiteInstance* instance) const;
- // Returns whether |render_frame_host| is on the pending deletion list.
- bool IsPendingDeletion(RenderFrameHostImpl* render_frame_host);
+ // Returns whether |render_view_host| will be deleted when its main
+ // RenderFrameHost is deleted from the pending deletion list.
+ bool IsViewPendingDeletion(RenderViewHostImpl* render_view_host);
// If |render_frame_host| is on the pending deletion list, this deletes it.
// Returns whether it was deleted.
@@ -406,6 +396,9 @@ class CONTENT_EXPORT RenderFrameHostManager
// of WebContentsImpl.
void ResetProxyHosts();
+ void ClearRFHsPendingShutdown();
+ void ClearWebUIInstances();
+
// Returns the routing id for a RenderFrameHost or RenderFrameProxyHost
// that has the given SiteInstance and is associated with this
// RenderFrameHostManager. Returns MSG_ROUTING_NONE if none is found.
@@ -415,7 +408,7 @@ class CONTENT_EXPORT RenderFrameHostManager
// Notifies the RenderFrameHostManager that a new NavigationRequest has been
// created and set in the FrameTreeNode so that it can speculatively create a
// new RenderFrameHost (and potentially a new process) if needed.
- void DidCreateNavigationRequest(const NavigationRequest& request);
+ void DidCreateNavigationRequest(NavigationRequest* request);
// PlzNavigate
// Called (possibly several times) during a navigation to select or create an
@@ -439,9 +432,10 @@ class CONTENT_EXPORT RenderFrameHostManager
void OnDidStartLoading();
void OnDidStopLoading();
- // Send updated frame name to all frame proxies when the frame changes its
- // window.name property.
- void OnDidUpdateName(const std::string& name);
+ // OnDidUpdateName gets called when a frame changes its name - it gets the new
+ // |name| and the recalculated |unique_name| and replicates them into all
+ // frame proxies.
+ void OnDidUpdateName(const std::string& name, const std::string& unique_name);
// Sends updated enforcement of strict mixed content checking to all
// frame proxies when the frame changes its setting.
@@ -449,7 +443,8 @@ class CONTENT_EXPORT RenderFrameHostManager
// Send updated origin to all frame proxies when the frame navigates to a new
// origin.
- void OnDidUpdateOrigin(const url::Origin& origin);
+ void OnDidUpdateOrigin(const url::Origin& origin,
+ bool is_potentially_trustworthy_unique_origin);
void EnsureRenderViewInitialized(RenderViewHostImpl* render_view_host,
SiteInstance* instance);
@@ -489,19 +484,45 @@ class CONTENT_EXPORT RenderFrameHostManager
// an inner WebContents.
void SetRWHViewForInnerContents(RenderWidgetHostView* child_rwhv);
- // Returns a copy of the map of proxy hosts. The keys are SiteInstance IDs,
- // the values are RenderFrameProxyHosts.
- std::map<int, RenderFrameProxyHost*> GetAllProxyHostsForTesting();
+ // Returns the number of RenderFrameProxyHosts for this frame.
+ int GetProxyCount();
+
+ // Sends an IPC message to every process in the FrameTree. This should only be
+ // called in the top-level RenderFrameHostManager.
+ void SendPageMessage(IPC::Message* msg);
+
+ // Returns a const reference to the map of proxy hosts. The keys are
+ // SiteInstance IDs, the values are RenderFrameProxyHosts.
+ const std::unordered_map<int32_t, scoped_ptr<RenderFrameProxyHost>>&
+ GetAllProxyHostsForTesting() const {
+ return proxy_hosts_;
+ }
// SiteInstanceImpl::Observer
void ActiveFrameCountIsZero(SiteInstanceImpl* site_instance) override;
void RenderProcessGone(SiteInstanceImpl* site_instance) override;
+ // Sets up the necessary state for a new RenderViewHost. If |proxy| is not
+ // null, it creates a RenderFrameProxy in the target renderer process which is
+ // used to route IPC messages when in swapped out state. Returns early if the
+ // RenderViewHost has already been initialized for another RenderFrameHost.
+ bool InitRenderView(RenderViewHostImpl* render_view_host,
+ RenderFrameProxyHost* proxy);
+
private:
friend class NavigatorTestWithBrowserSideNavigation;
friend class RenderFrameHostManagerTest;
friend class TestWebContents;
+ enum class SiteInstanceRelation {
+ // A SiteInstance in a different browsing instance from the current.
+ UNRELATED,
+ // A SiteInstance in the same browsing instance as the current.
+ RELATED,
+ // The default subframe SiteInstance for the current browsing instance.
+ RELATED_DEFAULT_SUBFRAME,
+ };
+
// Stores information regarding a SiteInstance targeted at a specific URL to
// allow for comparisons without having to actually create new instances. It
// can point to an existing one or store the details needed to create a new
@@ -509,11 +530,11 @@ class CONTENT_EXPORT RenderFrameHostManager
struct CONTENT_EXPORT SiteInstanceDescriptor {
explicit SiteInstanceDescriptor(content::SiteInstance* site_instance)
: existing_site_instance(site_instance),
- new_is_related_to_current(false) {}
+ relation(SiteInstanceRelation::UNRELATED) {}
SiteInstanceDescriptor(BrowserContext* browser_context,
GURL dest_url,
- bool related_to_current);
+ SiteInstanceRelation relation_to_current);
// Set with an existing SiteInstance to be reused.
content::SiteInstance* existing_site_instance;
@@ -521,9 +542,9 @@ class CONTENT_EXPORT RenderFrameHostManager
// In case |existing_site_instance| is null, specify a new site URL.
GURL new_site_url;
- // In case |existing_site_instance| is null, specify if the new site should
- // be created in a new BrowsingInstance or not.
- bool new_is_related_to_current;
+ // In case |existing_site_instance| is null, specify how the new site is
+ // related to the current BrowsingInstance.
+ SiteInstanceRelation relation;
};
// Create a RenderFrameProxyHost owned by this object.
@@ -558,13 +579,14 @@ class CONTENT_EXPORT RenderFrameHostManager
bool new_is_view_source_mode) const;
// Returns the SiteInstance to use for the navigation.
- SiteInstance* GetSiteInstanceForNavigation(const GURL& dest_url,
- SiteInstance* source_instance,
- SiteInstance* dest_instance,
- SiteInstance* candidate_instance,
- ui::PageTransition transition,
- bool dest_is_restore,
- bool dest_is_view_source_mode);
+ scoped_refptr<SiteInstance> GetSiteInstanceForNavigation(
+ const GURL& dest_url,
+ SiteInstance* source_instance,
+ SiteInstance* dest_instance,
+ SiteInstance* candidate_instance,
+ ui::PageTransition transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode);
// Returns a descriptor of the appropriate SiteInstance object for the given
// |dest_url|, possibly reusing the current, source or destination
@@ -593,14 +615,13 @@ class CONTENT_EXPORT RenderFrameHostManager
// Converts a SiteInstanceDescriptor to the actual SiteInstance it describes.
// If a |candidate_instance| is provided (is not nullptr) and it matches the
// description, it is returned as is.
- SiteInstance* ConvertToSiteInstance(const SiteInstanceDescriptor& descriptor,
- SiteInstance* candidate_instance);
+ scoped_refptr<SiteInstance> ConvertToSiteInstance(
+ const SiteInstanceDescriptor& descriptor,
+ SiteInstance* candidate_instance);
- // Determines the appropriate url to use as the current url for SiteInstance
- // selection.
- const GURL& GetCurrentURLForSiteInstance(
- SiteInstance* current_instance,
- NavigationEntry* current_entry);
+ // Returns true if |candidate| is currently on the same web site as dest_url.
+ bool IsCurrentlySameSite(RenderFrameHostImpl* candidate,
+ const GURL& dest_url);
// Creates a new RenderFrameHostImpl for the |new_instance| and assign it to
// |pending_render_frame_host_| while respecting the opener route if needed
@@ -641,7 +662,7 @@ class CONTENT_EXPORT RenderFrameHostManager
int32_t view_routing_id,
int32_t frame_routing_id,
int32_t widget_routing_id,
- int flags);
+ bool hidden);
// PlzNavigate
// Create and initialize a speculative RenderFrameHost for an ongoing
@@ -650,13 +671,6 @@ class CONTENT_EXPORT RenderFrameHostManager
bool CreateSpeculativeRenderFrameHost(SiteInstance* old_instance,
SiteInstance* new_instance);
- // Sets up the necessary state for a new RenderViewHost. If |proxy| is not
- // null, it creates a RenderFrameProxy in the target renderer process which is
- // used to route IPC messages when in swapped out state. Returns early if the
- // RenderViewHost has already been initialized for another RenderFrameHost.
- bool InitRenderView(RenderViewHostImpl* render_view_host,
- RenderFrameProxyHost* proxy);
-
// Initialization for RenderFrameHost uses the same sequence as InitRenderView
// above.
bool InitRenderFrame(RenderFrameHostImpl* render_frame_host);
@@ -757,13 +771,10 @@ class CONTENT_EXPORT RenderFrameHostManager
scoped_ptr<NavigationHandleImpl> transfer_navigation_handle_;
// Proxy hosts, indexed by site instance ID.
- base::ScopedPtrHashMap<int32_t, scoped_ptr<RenderFrameProxyHost>>
- proxy_hosts_;
+ std::unordered_map<int32_t, scoped_ptr<RenderFrameProxyHost>> proxy_hosts_;
- // A list of RenderFrameHosts waiting to shut down after swapping out. We use
- // a linked list since we expect frequent deletes and no indexed access, and
- // because sets don't appear to support linked_ptrs.
- typedef std::list<linked_ptr<RenderFrameHostImpl> > RFHPendingDeleteList;
+ // A list of RenderFrameHosts waiting to shut down after swapping out.
+ using RFHPendingDeleteList = std::list<scoped_ptr<RenderFrameHostImpl>>;
RFHPendingDeleteList pending_delete_hosts_;
// The intersitial page currently shown if any, not own by this class
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index afb1ca06df8..0e3bbedde79 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -35,6 +35,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/bindings_policy.h"
+#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/file_chooser_file_info.h"
#include "content/public/common/file_chooser_params.h"
@@ -47,10 +48,11 @@
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
-#include "net/base/net_util.h"
+#include "content/test/test_frame_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
using base::ASCIIToUTF16;
@@ -1400,75 +1402,6 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_BackForwardNotStale) {
}
}
-// Test for http://crbug.com/130016.
-// Swapping out a render view should update its visiblity state.
-IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
- SwappedOutViewHasCorrectVisibilityState) {
- // This test is invalid in when swapped out is disabled.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden())
- return;
- StartEmbeddedServer();
-
- // Load a page with links that open in a new window.
- NavigateToPageWithLinks(shell());
-
- // Open a same-site link in a new widnow.
- ShellAddedObserver new_shell_observer;
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- shell()->web_contents(),
- "window.domAutomationController.send(clickSameSiteTargetedLink());",
- &success));
- EXPECT_TRUE(success);
- Shell* new_shell = new_shell_observer.GetShell();
-
- // Wait for the navigation in the new tab to finish, if it hasn't.
- WaitForLoadStop(new_shell->web_contents());
- EXPECT_EQ("/navigate_opener.html",
- new_shell->web_contents()->GetLastCommittedURL().path());
-
- RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
-
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- rvh,
- "window.domAutomationController.send("
- " document.visibilityState == 'visible');",
- &success));
- EXPECT_TRUE(success);
-
- // Now navigate the new window to a different site. This should swap out the
- // tab's existing RenderView, causing it become hidden.
- NavigateToURL(new_shell,
- embedded_test_server()->GetURL("foo.com", "/title1.html"));
-
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- rvh,
- "window.domAutomationController.send("
- " document.visibilityState == 'hidden');",
- &success));
- EXPECT_TRUE(success);
-
- // Going back should make the previously swapped-out view to become visible
- // again.
- {
- TestNavigationObserver back_nav_load_observer(new_shell->web_contents());
- new_shell->web_contents()->GetController().GoBack();
- back_nav_load_observer.Wait();
- }
-
- EXPECT_EQ("/navigate_opener.html",
- new_shell->web_contents()->GetLastCommittedURL().path());
-
- EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
-
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- rvh,
- "window.domAutomationController.send("
- " document.visibilityState == 'visible');",
- &success));
- EXPECT_TRUE(success);
-}
-
// This class ensures that all the given RenderViewHosts have properly been
// shutdown.
class RenderViewHostDestructionObserver : public WebContentsObserver {
@@ -1693,8 +1626,17 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// Ensure that renderer-side debug URLs don't take effect on crashed renderers,
// even when going back/forward.
// See https://crbug.com/477606.
+
+// This test is flaky on Android. crbug.com/585327
+#if defined(OS_ANDROID)
+#define MAYBE_IgnoreForwardToRendererDebugURLsWhenCrashed \
+ DISABLED_IgnoreForwardToRendererDebugURLsWhenCrashed
+#else
+#define MAYBE_IgnoreForwardToRendererDebugURLsWhenCrashed \
+ IgnoreForwardToRendererDebugURLsWhenCrashed
+#endif
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
- IgnoreForwardToRendererDebugURLsWhenCrashed) {
+ MAYBE_IgnoreForwardToRendererDebugURLsWhenCrashed) {
// Visit a WebUI page with bindings.
GURL webui_url = GURL(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
@@ -2417,6 +2359,151 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
}
+// Ensure that we don't crash the renderer in CreateRenderView if a proxy goes
+// away between swapout and the next navigation. See https://crbug.com/581912.
+// Dr.Memory reports a use-after-free in this test, thus it may be flaky on
+// Windows. See https://crbug.com/600957.
+#if defined(OS_WIN)
+#define MAYBE_CreateRenderViewAfterProcessKillAndClosedProxy \
+ DISABLED_CreateRenderViewAfterProcessKillAndClosedProxy
+#else
+#define MAYBE_CreateRenderViewAfterProcessKillAndClosedProxy \
+ CreateRenderViewAfterProcessKillAndClosedProxy
+#endif
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ MAYBE_CreateRenderViewAfterProcessKillAndClosedProxy) {
+ StartEmbeddedServer();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Give an initial page an unload handler that never completes.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+ "window.onunload=function(e){ while(1); };\n"));
+
+ // Open a popup in the same process.
+ Shell* new_shell =
+ OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
+ FrameTreeNode* popup_root =
+ static_cast<WebContentsImpl*>(new_shell->web_contents())
+ ->GetFrameTree()
+ ->root();
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+
+ // Navigate the first tab to a different site, and only wait for commit, not
+ // load stop.
+ RenderFrameHostImpl* rfh_a = root->current_frame_host();
+ SiteInstanceImpl* site_instance_a = rfh_a->GetSiteInstance();
+ TestFrameNavigationObserver commit_observer(root);
+ shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ commit_observer.WaitForCommit();
+ rfh_a->ResetSwapOutTimerForTesting();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+
+ // The previous RFH should still be pending deletion, as we wait for either
+ // the SwapOut ACK or a timeout.
+ ASSERT_TRUE(rfh_a->IsRenderFrameLive());
+ ASSERT_FALSE(rfh_a->is_active());
+
+ // The corresponding RVH should not be pending deletion due to the proxy.
+ EXPECT_FALSE(root->render_manager()->IsViewPendingDeletion(
+ rfh_a->render_view_host()));
+
+ // Kill the old process.
+ RenderProcessHost* process = rfh_a->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ process->Shutdown(0, false);
+ crash_observer.Wait();
+ EXPECT_FALSE(popup_root->current_frame_host()->IsRenderFrameLive());
+ // |rfh_a| is now deleted, thanks to the bug fix.
+
+ // Close the popup so there is no proxy for a.com in the original tab.
+ new_shell->Close();
+ EXPECT_FALSE(
+ root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+
+ // Go back in the main frame from b.com to a.com. In https://crbug.com/581912,
+ // the browser process would crash here because there was no main frame
+ // routing ID or proxy in RVHI::CreateRenderView.
+ {
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ }
+}
+
+// Ensure that we don't crash in RenderViewImpl::Init if a proxy is created
+// after swapout and before navigation. See https://crbug.com/544755.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ RenderViewInitAfterNewProxyAndProcessKill) {
+ StartEmbeddedServer();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Give an initial page an unload handler that never completes.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+ "window.onunload=function(e){ while(1); };\n"));
+
+ // Navigate the tab to a different site, and only wait for commit, not load
+ // stop.
+ RenderFrameHostImpl* rfh_a = root->current_frame_host();
+ SiteInstanceImpl* site_instance_a = rfh_a->GetSiteInstance();
+ TestFrameNavigationObserver commit_observer(root);
+ shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ commit_observer.WaitForCommit();
+ rfh_a->ResetSwapOutTimerForTesting();
+ EXPECT_NE(site_instance_a, shell()->web_contents()->GetSiteInstance());
+
+ // The previous RFH and RVH should still be pending deletion, as we wait for
+ // either the SwapOut ACK or a timeout.
+ ASSERT_TRUE(rfh_a->IsRenderFrameLive());
+ ASSERT_FALSE(rfh_a->is_active());
+ EXPECT_TRUE(root->render_manager()->IsViewPendingDeletion(
+ rfh_a->render_view_host()));
+
+ // Open a popup in the new B process.
+ Shell* new_shell =
+ OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "foo");
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+
+ // Navigate the popup to the original site, but don't wait for commit (which
+ // won't happen). This creates a proxy in the original tab, alongside the
+ // RFH and RVH pending deletion.
+ new_shell->LoadURL(embedded_test_server()->GetURL("a.com", "/title2.html"));
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
+
+ // Kill the old process.
+ RenderProcessHost* process = rfh_a->GetProcess();
+ RenderProcessHostWatcher crash_observer(
+ process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ process->Shutdown(0, false);
+ crash_observer.Wait();
+ // |rfh_a| is now deleted, thanks to the bug fix.
+
+ // Go back in the main frame from b.com to a.com.
+ {
+ TestNavigationObserver back_nav_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_nav_load_observer.Wait();
+ }
+
+ // In https://crbug.com/581912, the renderer process would crash here because
+ // there was a frame, view, and proxy (and is_swapped_out was true).
+ EXPECT_EQ(site_instance_a, root->current_frame_host()->GetSiteInstance());
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(new_shell->web_contents()->GetMainFrame()->IsRenderFrameLive());
+}
+
// Ensure that we use the same pending RenderFrameHost if a second navigation to
// its site occurs before it commits. Otherwise the renderer process will have
// two competing pending RenderFrames that both try to swap with the same
@@ -2441,23 +2528,173 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
shell()->web_contents());
- RenderFrameHostImpl* pending_rfh =
- web_contents->GetRenderManagerForTesting()->pending_frame_host();
- ASSERT_TRUE(pending_rfh);
+ RenderFrameHostImpl* next_rfh =
+ IsBrowserSideNavigationEnabled()
+ ? web_contents->GetRenderManagerForTesting()->speculative_frame_host()
+ : web_contents->GetRenderManagerForTesting()->pending_frame_host();
+ ASSERT_TRUE(next_rfh);
// Navigate to the same new site and verify that we commit in the same RFH.
GURL cross_site_url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationObserver navigation_observer(web_contents, 1);
shell()->LoadURL(cross_site_url2);
- EXPECT_EQ(pending_rfh,
- web_contents->GetRenderManagerForTesting()->pending_frame_host());
+ if (IsBrowserSideNavigationEnabled()) {
+ EXPECT_EQ(
+ next_rfh,
+ web_contents->GetRenderManagerForTesting()->speculative_frame_host());
+ } else {
+ EXPECT_EQ(next_rfh,
+ web_contents->GetRenderManagerForTesting()->pending_frame_host());
+ }
navigation_observer.Wait();
EXPECT_EQ(cross_site_url2, web_contents->GetLastCommittedURL());
- EXPECT_EQ(pending_rfh, web_contents->GetMainFrame());
- EXPECT_FALSE(
- web_contents->GetRenderManagerForTesting()->pending_frame_host());
+ EXPECT_EQ(next_rfh, web_contents->GetMainFrame());
+ if (IsBrowserSideNavigationEnabled()) {
+ EXPECT_FALSE(
+ web_contents->GetRenderManagerForTesting()->speculative_frame_host());
+ } else {
+ EXPECT_FALSE(
+ web_contents->GetRenderManagerForTesting()->pending_frame_host());
+ }
ResourceDispatcherHost::Get()->SetDelegate(nullptr);
}
+// Check that if a sandboxed subframe opens a cross-process popup such that the
+// popup's opener won't be set, the popup still inherits the subframe's sandbox
+// flags. This matters for rel=noopener and rel=noreferrer links, as well as
+// for some situations in non-site-per-process mode where the popup would
+// normally maintain the opener, but loses it due to being placed in a new
+// process and not creating subframe proxies. The latter might happen when
+// opening the default search provider site. See https://crbug.com/576204.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ CrossProcessPopupInheritsSandboxFlagsWithNoOpener) {
+ StartEmbeddedServer();
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // Add a sandboxed about:blank iframe.
+ {
+ std::string script =
+ "var frame = document.createElement('iframe');\n"
+ "frame.sandbox = 'allow-scripts allow-popups';\n"
+ "document.body.appendChild(frame);\n";
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
+ }
+
+ // Navigate iframe to a page with target=_blank links, and rewrite the links
+ // to point to valid cross-site URLs.
+ GURL frame_url(
+ embedded_test_server()->GetURL("a.com", "/click-noreferrer-links.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ std::string script = "setOriginForLinks('http://b.com:" +
+ embedded_test_server()->base_url().port() + "/');";
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script));
+
+ // Helper to click on the 'rel=noreferrer target=_blank' and 'rel=noopener
+ // target=_blank' links. Checks that these links open a popup that ends up
+ // in a new SiteInstance even without site-per-process and then verifies that
+ // the popup is still sandboxed.
+ auto click_link_and_verify_popup = [this,
+ root](std::string link_opening_script) {
+ ShellAddedObserver new_shell_observer;
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(" + link_opening_script + ")",
+ &success));
+ EXPECT_TRUE(success);
+
+ Shell* new_shell = new_shell_observer.GetShell();
+ EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
+ EXPECT_NE(new_shell->web_contents()->GetSiteInstance(),
+ shell()->web_contents()->GetSiteInstance());
+
+ // Check that the popup is sandboxed by checking its document.origin, which
+ // should be unique.
+ std::string origin;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ new_shell->web_contents(),
+ "domAutomationController.send(document.origin)", &origin));
+ EXPECT_EQ("null", origin);
+ };
+
+ click_link_and_verify_popup("clickNoOpenerTargetBlankLink()");
+ click_link_and_verify_popup("clickNoRefTargetBlankLink()");
+}
+
+// When two frames are same-origin but cross-process, they should behave as if
+// they are not same-origin and should not crash.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ SameOriginFramesInDifferentProcesses) {
+ StartEmbeddedServer();
+
+ // Load a page with links that open in a new window.
+ NavigateToURL(shell(), embedded_test_server()->GetURL(
+ "a.com", "/click-noreferrer-links.html"));
+
+ // Get the original SiteInstance for later comparison.
+ scoped_refptr<SiteInstance> orig_site_instance(
+ shell()->web_contents()->GetSiteInstance());
+ EXPECT_NE(nullptr, orig_site_instance.get());
+
+ // Test clicking a target=foo link.
+ ShellAddedObserver new_shell_observer;
+ bool success = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send(clickSameSiteTargetedLink());"
+ "saveWindowReference();",
+ &success));
+ EXPECT_TRUE(success);
+ Shell* new_shell = new_shell_observer.GetShell();
+
+ // Wait for the navigation in the new tab to finish, if it hasn't.
+ WaitForLoadStop(new_shell->web_contents());
+ EXPECT_EQ("/navigate_opener.html",
+ new_shell->web_contents()->GetLastCommittedURL().path());
+
+ // Do a cross-site navigation that winds up same-site. The same-site
+ // navigation to a.com will commit in a different process than the original
+ // a.com window.
+ NavigateToURL(new_shell, embedded_test_server()->GetURL(
+ "b.com", "/cross-site/a.com/title1.html"));
+ if (AreAllSitesIsolatedForTesting()) {
+ // In --site-per-process mode, both windows will actually be in the same
+ // process.
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+ } else {
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ new_shell->web_contents()->GetSiteInstance());
+ }
+
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ shell()->web_contents(),
+ "window.domAutomationController.send((function() {\n"
+ " try {\n"
+ " return getLastOpenedWindowLocation();\n"
+ " } catch (e) {\n"
+ " return e.toString();\n"
+ " }\n"
+ "})())",
+ &result));
+ if (AreAllSitesIsolatedForTesting()) {
+ EXPECT_THAT(result,
+ ::testing::MatchesRegex("http://a.com:\\d+/title1.html"));
+ } else {
+ // Accessing a property with normal security checks should throw a
+ // SecurityError if the same-origin windows are in different processes.
+ EXPECT_THAT(result,
+ ::testing::MatchesRegex("SecurityError: Blocked a frame with "
+ "origin \"http://a.com:\\d+\" from "
+ "accessing a cross-origin frame."));
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc b/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
index e6e53607689..7556b4050ab 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -347,7 +347,7 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
TestRenderFrameHost* active_rfh = contents()->GetPendingMainFrame()
? contents()->GetPendingMainFrame()
: old_rfh;
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, old_rfh->rfh_state());
+ EXPECT_TRUE(old_rfh->is_active());
// Commit the navigation with a new page ID.
int32_t max_page_id =
@@ -360,32 +360,15 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
active_rfh->SendNavigate(max_page_id + 1, entry_id, true, url);
// Make sure that we start to run the unload handler at the time of commit.
- bool expecting_rfh_shutdown = false;
if (old_rfh != active_rfh && !rfh_observer.deleted()) {
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT,
- old_rfh->rfh_state());
- if (!old_rfh->GetSiteInstance()->active_frame_count() ||
- SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- expecting_rfh_shutdown = true;
- EXPECT_TRUE(
- old_rfh->frame_tree_node()->render_manager()->IsPendingDeletion(
- old_rfh));
- }
+ EXPECT_FALSE(old_rfh->is_active());
}
// Simulate the swap out ACK coming from the pending renderer. This should
// either shut down the old RFH or leave it in a swapped out state.
if (old_rfh != active_rfh) {
old_rfh->OnSwappedOut();
- if (expecting_rfh_shutdown) {
- EXPECT_TRUE(rfh_observer.deleted());
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(rvh_observer.deleted());
- }
- } else {
- EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT,
- old_rfh->rfh_state());
- }
+ EXPECT_TRUE(rfh_observer.deleted());
}
EXPECT_EQ(active_rfh, contents()->GetMainFrame());
EXPECT_EQ(NULL, contents()->GetPendingMainFrame());
@@ -411,8 +394,8 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
new_entry->IsViewSourceMode());
}
- // Creates a test RenderFrameHost that's swapped out.
- TestRenderFrameHost* CreateSwappedOutRenderFrameHost() {
+ // Creates a test RenderViewHost that's swapped out.
+ void CreateSwappedOutRenderViewHost() {
const GURL kChromeURL("chrome://foo");
const GURL kDestUrl("http://www.google.com/");
@@ -441,9 +424,6 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
dest_rfh->SendNavigate(101, entry_id, true, kDestUrl);
ntp_rfh->OnSwappedOut();
-
- EXPECT_TRUE(ntp_rfh->is_swapped_out());
- return ntp_rfh;
}
// Returns the RenderFrameHost that should be used in the navigation to
@@ -459,20 +439,19 @@ class RenderFrameHostManagerTest : public RenderViewHostImplTestHarness {
->frame_tree_node()
->navigator()
->GetController());
- // TODO(carlosk): This implementation below will not work with restore
- // navigations. Method GetNavigationType should be exposed from
- // navigator_impl.cc and used here to determine FrameMsg_Navigate_Type.
- CHECK(entry.restore_type() == NavigationEntryImpl::RESTORE_NONE);
+ FrameMsg_Navigate_Type::Value navigate_type =
+ entry.restore_type() == NavigationEntryImpl::RESTORE_NONE
+ ? FrameMsg_Navigate_Type::NORMAL
+ : FrameMsg_Navigate_Type::RESTORE;
scoped_ptr<NavigationRequest> navigation_request =
NavigationRequest::CreateBrowserInitiated(
manager->frame_tree_node_, frame_entry->url(),
- frame_entry->referrer(), *frame_entry, entry,
- FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(),
- controller);
+ frame_entry->referrer(), *frame_entry, entry, navigate_type,
+ LOFI_UNSPECIFIED, false, base::TimeTicks::Now(), controller);
// Simulates request creation that triggers the 1st internal call to
// GetFrameHostForNavigation.
- manager->DidCreateNavigationRequest(*navigation_request);
+ manager->DidCreateNavigationRequest(navigation_request.get());
// And also simulates the 2nd and final call to GetFrameHostForNavigation
// that determines the final frame that will commit the navigation.
@@ -643,50 +622,6 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
EXPECT_FALSE(observer.favicon_received());
}
-
- // In --site-per-process, the RenderFrameHost is deleted on cross-process
- // navigation, so the rest of the test case doesn't apply.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- return;
- }
-
-#if defined(ENABLE_PLUGINS)
- // The same logic should apply to RenderFrameHosts as well and routing through
- // swapped out RFH shouldn't be allowed. Use a PluginCrashObserver to check
- // if the IPC message is allowed through or not.
- {
- PluginFaviconMessageObserver observer(contents());
- EXPECT_TRUE(ntp_rfh->OnMessageReceived(
- FrameHostMsg_PluginCrashed(
- ntp_rfh->GetRoutingID(), base::FilePath(), 0)));
- EXPECT_FALSE(observer.plugin_crashed());
- }
-#endif
-
- // We cannot filter out synchronous IPC messages, because the renderer would
- // be left waiting for a reply. We pick RunBeforeUnloadConfirm as an example
- // that can run easily within a unit test, and that needs to receive a reply
- // without showing an actual dialog.
- MockRenderProcessHost* ntp_process_host = ntp_rfh->GetProcess();
- ntp_process_host->sink().ClearMessages();
- const base::string16 msg = base::ASCIIToUTF16("Message");
- bool result = false;
- base::string16 unused;
- FrameHostMsg_RunBeforeUnloadConfirm before_unload_msg(
- ntp_rfh->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
- // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
- before_unload_msg.EnableMessagePumping();
- EXPECT_TRUE(ntp_rfh->OnMessageReceived(before_unload_msg));
- EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
-
- // Also test RunJavaScriptMessage.
- ntp_process_host->sink().ClearMessages();
- FrameHostMsg_RunJavaScriptMessage js_msg(
- ntp_rfh->GetRoutingID(), msg, msg, kChromeURL,
- JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
- js_msg.EnableMessagePumping();
- EXPECT_TRUE(ntp_rfh->OnMessageReceived(js_msg));
- EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
}
// Test that the ViewHostMsg_UpdateFaviconURL IPC message is ignored if the
@@ -723,8 +658,8 @@ TEST_F(RenderFrameHostManagerTest, UpdateFaviconURLWhilePendingSwapOut) {
TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
contents()->TestDidNavigate(rfh2, 1, entry_id, true, kDestUrl,
ui::PAGE_TRANSITION_TYPED);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
+ EXPECT_FALSE(rfh1->is_active());
+ EXPECT_TRUE(rfh2->is_active());
// The new RVH should be able to update its favicons.
{
@@ -746,95 +681,13 @@ TEST_F(RenderFrameHostManagerTest, UpdateFaviconURLWhilePendingSwapOut) {
}
}
-// Ensure that frames aren't added to the frame tree, if the message is coming
-// from a process different than the parent frame's current RenderFrameHost
-// process. Otherwise it is possible to have collisions of routing ids, as they
-// are scoped per process. See https://crbug.com/415059.
-TEST_F(RenderFrameHostManagerTest, DropCreateChildFrameWhileSwappedOut) {
- const GURL kUrl1("http://foo.com");
- const GURL kUrl2("http://www.google.com/");
-
- // This test is invalid in --site-per-process mode, as swapped-out is no
- // longer used.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- return;
- }
-
- // Navigate to the first site.
- NavigateActiveAndCommit(kUrl1);
- TestRenderFrameHost* initial_rfh = contents()->GetMainFrame();
- {
- RenderFrameHostCreatedObserver observer(contents());
- initial_rfh->OnCreateChildFrame(
- initial_rfh->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
- EXPECT_TRUE(observer.created());
- }
-
- // Create one more frame in the same SiteInstance where initial_rfh
- // exists so that initial_rfh doesn't get deleted on navigation to another
- // site.
- initial_rfh->GetSiteInstance()->IncrementActiveFrameCount();
-
- // Navigate to a cross-site URL.
- NavigateActiveAndCommit(kUrl2);
- EXPECT_TRUE(initial_rfh->is_swapped_out());
-
- TestRenderFrameHost* dest_rfh = contents()->GetMainFrame();
- ASSERT_TRUE(dest_rfh);
- EXPECT_NE(initial_rfh, dest_rfh);
-
- {
- // Since the old RFH is now swapped out, it shouldn't process any messages
- // to create child frames.
- RenderFrameHostCreatedObserver observer(contents());
- initial_rfh->OnCreateChildFrame(
- initial_rfh->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
- EXPECT_FALSE(observer.created());
- }
-}
-
-TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
- // TODO(nasko): Check with kenrb whether this test can be rewritten and
- // whether it makes sense when swapped out is replaced with proxies.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- return;
- }
- TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
- TestRenderWidgetHostView* swapped_out_rwhv =
- static_cast<TestRenderWidgetHostView*>(
- swapped_out_rfh->GetRenderViewHost()->GetWidget()->GetView());
- EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
-
- MockRenderProcessHost* process_host = swapped_out_rfh->GetProcess();
- process_host->sink().ClearMessages();
-
- cc::CompositorFrame frame;
- ViewHostMsg_SwapCompositorFrame msg(
- rvh()->GetRoutingID(), 0, frame, std::vector<IPC::Message>());
-
- EXPECT_TRUE(
- swapped_out_rfh->render_view_host()->GetWidget()->OnMessageReceived(msg));
- EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
-}
-
// Test if RenderViewHost::GetRenderWidgetHosts() only returns active
// widgets.
TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
- // This test is invalid in --site-per-process mode, as swapped-out is no
- // longer used.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- return;
- }
-
- TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
- EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
-
+ CreateSwappedOutRenderViewHost();
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
+
// We know that there is the only one active widget. Another view is
// now swapped out, so the swapped out view is not included in the
// list.
@@ -851,15 +704,7 @@ TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
// including swapped out ones.
TEST_F(RenderFrameHostManagerTest,
GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
- // This test is invalid in --site-per-process mode, as swapped-out is no
- // longer used.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- return;
- }
-
- TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
- EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
-
+ CreateSwappedOutRenderViewHost();
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
@@ -1044,14 +889,14 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
// New message should be sent out to make sure to enter view-source mode.
EXPECT_TRUE(process()->sink().GetUniqueMessageMatching(
- ViewMsg_EnableViewSourceMode::ID));
+ FrameMsg_EnableViewSourceMode::ID));
}
// Tests the Init function by checking the initial RenderViewHost.
TEST_F(RenderFrameHostManagerTest, Init) {
// Using TestBrowserContext.
- SiteInstanceImpl* instance =
- static_cast<SiteInstanceImpl*>(SiteInstance::Create(browser_context()));
+ scoped_refptr<SiteInstanceImpl> instance =
+ SiteInstanceImpl::Create(browser_context());
EXPECT_FALSE(instance->HasSite());
scoped_ptr<TestWebContents> web_contents(
@@ -1073,10 +918,8 @@ TEST_F(RenderFrameHostManagerTest, Init) {
// Tests the Navigate function. We navigate three sites consecutively and check
// how the pending/committed RenderViewHost are modified.
TEST_F(RenderFrameHostManagerTest, Navigate) {
- SiteInstance* instance = SiteInstance::Create(browser_context());
-
- scoped_ptr<TestWebContents> web_contents(
- TestWebContents::Create(browser_context(), instance));
+ scoped_ptr<TestWebContents> web_contents(TestWebContents::Create(
+ browser_context(), SiteInstance::Create(browser_context())));
RenderViewHostChangedObserver change_observer(web_contents.get());
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
@@ -1151,7 +994,8 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
// Tests WebUI creation.
TEST_F(RenderFrameHostManagerTest, WebUI) {
set_should_create_webui(true);
- SiteInstance* instance = SiteInstance::Create(browser_context());
+ scoped_refptr<SiteInstance> instance =
+ SiteInstance::Create(browser_context());
scoped_ptr<TestWebContents> web_contents(
TestWebContents::Create(browser_context(), instance));
@@ -1209,7 +1053,8 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
// grant the correct bindings. http://crbug.com/189101.
TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
set_should_create_webui(true);
- SiteInstance* blank_instance = SiteInstance::Create(browser_context());
+ scoped_refptr<SiteInstance> blank_instance =
+ SiteInstance::Create(browser_context());
blank_instance->GetProcess()->Init();
// Create a blank tab.
@@ -1436,7 +1281,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
contents()->GetPendingMainFrame()->SendNavigate(
entry1->GetPageID(), entry1->GetUniqueID(), false, entry1->GetURL());
EXPECT_TRUE(rfh2->IsWaitingForUnloadACK());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh2->rfh_state());
+ EXPECT_FALSE(rfh2->is_active());
// We should be able to navigate forward.
contents()->GetController().GoForward();
@@ -1444,14 +1289,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
contents()->GetPendingMainFrame()->SendNavigate(
entry2->GetPageID(), entry2->GetUniqueID(), false, entry2->GetURL());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_EQ(rfh2, main_test_rfh());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
- rfh1->OnSwappedOut();
- EXPECT_TRUE(rfh1->is_swapped_out());
- EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT, rfh1->rfh_state());
- }
+ EXPECT_TRUE(main_test_rfh()->is_active());
}
// Test that we create swapped out RFHs for the opener chain when navigating an
@@ -1493,17 +1331,8 @@ TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRFHs) {
EXPECT_TRUE(site_instance1->IsRelatedSiteInstance(rfh2->GetSiteInstance()));
// Ensure rvh1 is placed on swapped out list of the current tab.
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(manager->IsRVHOnSwappedOutList(rvh1));
- EXPECT_FALSE(rfh1_deleted_observer.deleted());
- EXPECT_TRUE(manager->IsOnSwappedOutList(rfh1));
- EXPECT_EQ(rfh1,
- manager->GetRenderFrameProxyHost(site_instance1.get())
- ->render_frame_host());
- } else {
- EXPECT_TRUE(rfh1_deleted_observer.deleted());
- EXPECT_TRUE(manager->GetRenderFrameProxyHost(site_instance1.get()));
- }
+ EXPECT_TRUE(rfh1_deleted_observer.deleted());
+ EXPECT_TRUE(manager->GetRenderFrameProxyHost(site_instance1.get()));
EXPECT_EQ(rvh1,
manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
@@ -1513,13 +1342,7 @@ TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRFHs) {
RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
- EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
- EXPECT_TRUE(opener1_rfh->is_swapped_out());
- } else {
- EXPECT_FALSE(opener1_rfh);
- }
+ EXPECT_FALSE(opener1_rfh);
EXPECT_FALSE(opener1_rvh->is_active());
// Ensure a swapped out RFH and RVH is created in the second opener tab.
@@ -1528,13 +1351,7 @@ TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRFHs) {
RenderFrameHostImpl* opener2_rfh = opener2_proxy->render_frame_host();
TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rfh));
- EXPECT_TRUE(opener2_manager->IsRVHOnSwappedOutList(opener2_rvh));
- EXPECT_TRUE(opener2_rfh->is_swapped_out());
- } else {
- EXPECT_FALSE(opener2_rfh);
- }
+ EXPECT_FALSE(opener2_rfh);
EXPECT_FALSE(opener2_rvh->is_active());
// Navigate to a cross-BrowsingInstance URL.
@@ -1781,13 +1598,7 @@ TEST_F(RenderFrameHostManagerTest, EnableWebUIWithSwappedOutOpener) {
RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
- EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
- EXPECT_TRUE(opener1_rfh->is_swapped_out());
- } else {
- EXPECT_FALSE(opener1_rfh);
- }
+ EXPECT_FALSE(opener1_rfh);
EXPECT_FALSE(opener1_rvh->is_active());
// Ensure the new RVH has WebUI bindings.
@@ -1797,7 +1608,7 @@ TEST_F(RenderFrameHostManagerTest, EnableWebUIWithSwappedOutOpener) {
// Test that we reuse the same guest SiteInstance if we navigate across sites.
TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
GURL guest_url(std::string(kGuestScheme).append("://abc123"));
- SiteInstance* instance =
+ scoped_refptr<SiteInstance> instance =
SiteInstance::CreateForURL(browser_context(), guest_url);
scoped_ptr<TestWebContents> web_contents(
TestWebContents::Create(browser_context(), instance));
@@ -1852,7 +1663,8 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
TestNotificationTracker notifications;
- SiteInstance* instance = SiteInstance::Create(browser_context());
+ scoped_refptr<SiteInstance> instance =
+ SiteInstance::Create(browser_context());
BeforeUnloadFiredWebContentsDelegate delegate;
scoped_ptr<TestWebContents> web_contents(
@@ -1898,7 +1710,6 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
EXPECT_NE(host2, host);
EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
EXPECT_EQ(host2, GetPendingFrameHost(manager));
// 3) Close the tab. -------------------------
@@ -1951,7 +1762,7 @@ TEST_F(RenderFrameHostManagerTest, DeleteFrameAfterSwapOutACK) {
contents()->NavigateAndCommit(kUrl1);
TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
RenderFrameDeletedObserver rfh_deleted_observer(rfh1);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
// Navigate to new site, simulating onbeforeunload approval.
controller().LoadURL(
@@ -1959,14 +1770,14 @@ TEST_F(RenderFrameHostManagerTest, DeleteFrameAfterSwapOutACK) {
int entry_id = controller().GetPendingEntry()->GetUniqueID();
contents()->GetMainFrame()->PrepareForCommit();
EXPECT_TRUE(contents()->CrossProcessNavigationPending());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// Simulate the swap out ack, unexpectedly early (before commit). It should
// have no effect.
rfh1->OnSwappedOut();
EXPECT_TRUE(contents()->CrossProcessNavigationPending());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
// The new page commits.
contents()->TestDidNavigate(rfh2, 1, entry_id, true, kUrl2,
@@ -1974,10 +1785,8 @@ TEST_F(RenderFrameHostManagerTest, DeleteFrameAfterSwapOutACK) {
EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
- EXPECT_TRUE(
- rfh1->frame_tree_node()->render_manager()->IsPendingDeletion(rfh1));
+ EXPECT_TRUE(rfh2->is_active());
+ EXPECT_FALSE(rfh1->is_active());
// Simulate the swap out ack.
rfh1->OnSwappedOut();
@@ -1997,7 +1806,7 @@ TEST_F(RenderFrameHostManagerTest, SwapOutFrameAfterSwapOutACK) {
contents()->NavigateAndCommit(kUrl1);
TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
RenderFrameDeletedObserver rfh_deleted_observer(rfh1);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
// Increment the number of active frames in SiteInstanceImpl so that rfh1 is
// not deleted on swap out.
@@ -2009,7 +1818,7 @@ TEST_F(RenderFrameHostManagerTest, SwapOutFrameAfterSwapOutACK) {
int entry_id = controller().GetPendingEntry()->GetUniqueID();
contents()->GetMainFrame()->PrepareForCommit();
EXPECT_TRUE(contents()->CrossProcessNavigationPending());
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// The new page commits.
@@ -2018,19 +1827,14 @@ TEST_F(RenderFrameHostManagerTest, SwapOutFrameAfterSwapOutACK) {
EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
+ EXPECT_FALSE(rfh1->is_active());
+ EXPECT_TRUE(rfh2->is_active());
// Simulate the swap out ack.
rfh1->OnSwappedOut();
- // rfh1 should be swapped out or deleted in --site-per-process.
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_FALSE(rfh_deleted_observer.deleted());
- EXPECT_TRUE(rfh1->is_swapped_out());
- } else {
- EXPECT_TRUE(rfh_deleted_observer.deleted());
- }
+ // rfh1 should be deleted.
+ EXPECT_TRUE(rfh_deleted_observer.deleted());
}
// Test that the RenderViewHost is properly swapped out if a navigation in the
@@ -2046,7 +1850,7 @@ TEST_F(RenderFrameHostManagerTest,
contents()->NavigateAndCommit(kUrl1);
TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
RenderFrameDeletedObserver rfh_deleted_observer(rfh1);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
// Increment the number of active frames in SiteInstanceImpl so that rfh1 is
// not deleted on swap out.
@@ -2067,21 +1871,16 @@ TEST_F(RenderFrameHostManagerTest,
EXPECT_FALSE(contents()->CrossProcessNavigationPending());
EXPECT_EQ(rfh2, contents()->GetMainFrame());
EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
- EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
+ EXPECT_FALSE(rfh1->is_active());
+ EXPECT_TRUE(rfh2->is_active());
// Simulate the swap out ack.
rfh1->OnSwappedOut();
- // rfh1 should be swapped out.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(rfh_deleted_observer.deleted());
- EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
- ->GetRenderFrameProxyHost(site_instance.get()));
- } else {
- EXPECT_FALSE(rfh_deleted_observer.deleted());
- EXPECT_TRUE(rfh1->is_swapped_out());
- }
+ // rfh1 should be deleted.
+ EXPECT_TRUE(rfh_deleted_observer.deleted());
+ EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
+ ->GetRenderFrameProxyHost(site_instance.get()));
}
// Test that a RenderFrameHost is properly deleted when a cross-site navigation
@@ -2096,7 +1895,7 @@ TEST_F(RenderFrameHostManagerTest,
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
TestRenderFrameHost* rfh1 = main_test_rfh();
- EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ EXPECT_TRUE(rfh1->is_active());
// Navigate to a new site, starting a cross-site navigation.
controller().LoadURL(
@@ -2133,13 +1932,9 @@ TEST_F(RenderFrameHostManagerTest,
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
EXPECT_FALSE(contents()->CrossProcessNavigationPending());
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(rfh_deleted_observer.deleted());
- EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
- ->GetRenderFrameProxyHost(site_instance.get()));
- } else {
- EXPECT_FALSE(rfh_deleted_observer.deleted());
- }
+ EXPECT_TRUE(rfh_deleted_observer.deleted());
+ EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
+ ->GetRenderFrameProxyHost(site_instance.get()));
}
}
@@ -2162,11 +1957,11 @@ TEST_F(RenderFrameHostManagerTestWithSiteIsolation, DetachPendingChild) {
contents()->NavigateAndCommit(kUrlA);
contents()->GetMainFrame()->OnCreateChildFrame(
contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame_name",
+ blink::WebTreeScopeType::Document, "frame_name", "uniqueName1",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
contents()->GetMainFrame()->OnCreateChildFrame(
contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame_name",
+ blink::WebTreeScopeType::Document, "frame_name", "uniqueName2",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
RenderFrameHostManager* root_manager =
contents()->GetFrameTree()->root()->render_manager();
@@ -2207,10 +2002,8 @@ TEST_F(RenderFrameHostManagerTestWithSiteIsolation, DetachPendingChild) {
EXPECT_TRUE(GetPendingFrameHost(iframe2));
EXPECT_EQ(host1, GetPendingFrameHost(iframe1));
EXPECT_EQ(host2, GetPendingFrameHost(iframe2));
- EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
- GetPendingFrameHost(iframe1)->rfh_state()));
- EXPECT_TRUE(RenderFrameHostImpl::IsRFHStateActive(
- GetPendingFrameHost(iframe2)->rfh_state()));
+ EXPECT_TRUE(GetPendingFrameHost(iframe1)->is_active());
+ EXPECT_TRUE(GetPendingFrameHost(iframe2)->is_active());
EXPECT_NE(GetPendingFrameHost(iframe1), GetPendingFrameHost(iframe2));
EXPECT_EQ(GetPendingFrameHost(iframe1)->GetSiteInstance(),
GetPendingFrameHost(iframe2)->GetSiteInstance());
@@ -2303,7 +2096,7 @@ TEST_F(RenderFrameHostManagerTestWithSiteIsolation,
// |contents1| creates an out of process iframe.
contents1->GetMainFrame()->OnCreateChildFrame(
contents1->GetMainFrame()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame_name",
+ blink::WebTreeScopeType::Document, "frame_name", "uniqueName1",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
RenderFrameHostManager* iframe =
contents()->GetFrameTree()->root()->child_at(0)->render_manager();
@@ -2352,7 +2145,7 @@ TEST_F(RenderFrameHostManagerTestWithSiteIsolation,
EXPECT_TRUE(main_rfh->IsRenderFrameLive());
main_rfh->OnCreateChildFrame(main_rfh->GetProcess()->GetNextRoutingID(),
blink::WebTreeScopeType::Document, std::string(),
- blink::WebSandboxFlags::None,
+ "uniqueName1", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
RenderFrameHostManager* subframe_rfhm =
contents()->GetFrameTree()->root()->child_at(0)->render_manager();
@@ -2512,10 +2305,10 @@ TEST_F(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
FrameTreeNode* root1 = tree1->root();
int process_id = root1->current_frame_host()->GetProcess()->GetID();
tree1->AddFrame(root1, process_id, 12, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName0", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
tree1->AddFrame(root1, process_id, 13, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName1", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
scoped_ptr<TestWebContents> tab2(
@@ -2525,10 +2318,10 @@ TEST_F(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
FrameTreeNode* root2 = tree2->root();
process_id = root2->current_frame_host()->GetProcess()->GetID();
tree2->AddFrame(root2, process_id, 22, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName2", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
tree2->AddFrame(root2, process_id, 23, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName3", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
scoped_ptr<TestWebContents> tab3(
@@ -2543,7 +2336,7 @@ TEST_F(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
FrameTreeNode* root4 = tree4->root();
process_id = root4->current_frame_host()->GetProcess()->GetID();
tree4->AddFrame(root4, process_id, 42, blink::WebTreeScopeType::Document,
- std::string(), blink::WebSandboxFlags::None,
+ std::string(), "uniqueName4", blink::WebSandboxFlags::None,
blink::WebFrameOwnerProperties());
root1->child_at(1)->SetOpener(root1->child_at(1));
@@ -2592,15 +2385,15 @@ TEST_F(RenderFrameHostManagerTest, PageFocusPropagatesToSubframeProcesses) {
contents()->NavigateAndCommit(kUrlA);
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame1",
+ blink::WebTreeScopeType::Document, "frame1", "uniqueName1",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame2",
+ blink::WebTreeScopeType::Document, "frame2", "uniqueName2",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame3",
+ blink::WebTreeScopeType::Document, "frame3", "uniqueName3",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* root = contents()->GetFrameTree()->root();
@@ -2690,7 +2483,7 @@ TEST_F(RenderFrameHostManagerTest,
contents()->NavigateAndCommit(kUrlA);
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame1",
+ blink::WebTreeScopeType::Document, "frame1", "uniqueName1",
blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* root = contents()->GetFrameTree()->root();
@@ -2736,8 +2529,8 @@ TEST_F(RenderFrameHostManagerTest, RestoreNavigationToWebUI) {
set_should_create_webui(true);
const GURL kInitUrl("chrome://foo/");
- SiteInstanceImpl* initial_instance =
- static_cast<SiteInstanceImpl*>(SiteInstance::Create(browser_context()));
+ scoped_refptr<SiteInstanceImpl> initial_instance =
+ SiteInstanceImpl::Create(browser_context());
initial_instance->SetSite(kInitUrl);
scoped_ptr<TestWebContents> web_contents(
TestWebContents::Create(browser_context(), initial_instance));
@@ -2809,6 +2602,7 @@ void RenderFrameHostManagerTest::BaseSimultaneousNavigationWithOneWebUI(
// Starts a reload of the WebUI page.
contents()->GetController().Reload(true);
+ main_test_rfh()->PrepareForCommit();
// It should be a same-site navigation reusing the same WebUI.
EXPECT_EQ(web_ui, manager->GetNavigatingWebUI());
@@ -2974,6 +2768,67 @@ TEST_F(RenderFrameHostManagerTest, SimultaneousNavigationWithTwoWebUIs2) {
BaseSimultaneousNavigationWithTwoWebUIs(commit_new_frame_host);
}
+TEST_F(RenderFrameHostManagerTest, CanCommitOrigin) {
+ const GURL kUrl("http://a.com/");
+ const GURL kUrlBar("http://a.com/bar");
+
+ NavigateActiveAndCommit(kUrl);
+
+ controller().LoadURL(
+ kUrlBar, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->PrepareForCommit();
+
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 0;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.transition = ui::PAGE_TRANSITION_LINK;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureAuto;
+ params.was_within_same_page = false;
+ params.is_post = false;
+ params.page_state = PageState::CreateFromURL(kUrlBar);
+
+ struct TestCase {
+ const char* const url;
+ const char* const origin;
+ bool mismatch;
+ } cases[] = {
+ // Positive case where the two match.
+ { "http://a.com/foo.html", "http://a.com", false },
+
+ // Host mismatches.
+ { "http://a.com/", "http://b.com", true },
+ { "http://b.com/", "http://a.com", true },
+
+ // Scheme mismatches.
+ { "file://", "http://a.com", true },
+ { "https://a.com/", "http://a.com", true },
+
+ // about:blank URLs inherit the origin of the context that navigated them.
+ { "about:blank", "http://a.com", false },
+
+ // Unique origin.
+ { "http://a.com", "null", false },
+ };
+
+ for (const auto& test_case : cases) {
+ params.url = GURL(test_case.url);
+ params.origin = url::Origin(GURL(test_case.origin));
+
+ int expected_bad_msg_count = process()->bad_msg_count();
+ if (test_case.mismatch)
+ expected_bad_msg_count++;
+
+ main_test_rfh()->SendNavigateWithParams(&params);
+
+ EXPECT_EQ(expected_bad_msg_count, process()->bad_msg_count())
+ << " url:" << test_case.url
+ << " origin:" << test_case.origin
+ << " mismatch:" << test_case.mismatch;
+ }
+}
+
// RenderFrameHostManagerTest extension for PlzNavigate enabled tests.
class RenderFrameHostManagerTestWithBrowserSideNavigation
: public RenderFrameHostManagerTest {
@@ -3006,9 +2861,10 @@ TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation,
NavigationRequest::CreateBrowserInitiated(
contents()->GetFrameTree()->root(), frame_entry->url(),
frame_entry->referrer(), *frame_entry, entry,
- FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(),
+ FrameMsg_Navigate_Type::NORMAL, LOFI_UNSPECIFIED, false,
+ base::TimeTicks::Now(),
static_cast<NavigationControllerImpl*>(&controller()));
- manager->DidCreateNavigationRequest(*navigation_request);
+ manager->DidCreateNavigationRequest(navigation_request.get());
// As the initial RenderFrame was not live, the new RenderFrameHost should be
// made as active/current immediately along with its WebUI at request time.
@@ -3066,9 +2922,10 @@ TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation,
NavigationRequest::CreateBrowserInitiated(
contents()->GetFrameTree()->root(), frame_entry->url(),
frame_entry->referrer(), *frame_entry, entry,
- FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(),
+ FrameMsg_Navigate_Type::NORMAL, LOFI_UNSPECIFIED, false,
+ base::TimeTicks::Now(),
static_cast<NavigationControllerImpl*>(&controller()));
- manager->DidCreateNavigationRequest(*navigation_request);
+ manager->DidCreateNavigationRequest(navigation_request.get());
// The current WebUI should still be in place and the pending WebUI should be
// set to reuse it.
@@ -3123,9 +2980,10 @@ TEST_F(RenderFrameHostManagerTestWithBrowserSideNavigation,
NavigationRequest::CreateBrowserInitiated(
contents()->GetFrameTree()->root(), frame_entry->url(),
frame_entry->referrer(), *frame_entry, entry,
- FrameMsg_Navigate_Type::NORMAL, false, base::TimeTicks::Now(),
+ FrameMsg_Navigate_Type::NORMAL, LOFI_UNSPECIFIED, false,
+ base::TimeTicks::Now(),
static_cast<NavigationControllerImpl*>(&controller()));
- manager->DidCreateNavigationRequest(*navigation_request);
+ manager->DidCreateNavigationRequest(navigation_request.get());
// The current WebUI should still be in place and there should be a new
// active WebUI instance in the speculative RenderFrameHost.
@@ -3173,8 +3031,8 @@ TEST_F(RenderFrameHostManagerTestWithSiteIsolation,
// Create a child frame and navigate it cross-site.
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
- blink::WebTreeScopeType::Document, "frame1", blink::WebSandboxFlags::None,
- blink::WebFrameOwnerProperties());
+ blink::WebTreeScopeType::Document, "frame1", "uniqueName1",
+ blink::WebSandboxFlags::None, blink::WebFrameOwnerProperties());
FrameTreeNode* root = contents()->GetFrameTree()->root();
RenderFrameHostManager* child = root->child_at(0)->render_manager();
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.cc b/chromium/content/browser/frame_host/render_frame_message_filter.cc
index 21a811a85a9..98bd0fd5e37 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.cc
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.cc
@@ -21,6 +21,8 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
@@ -52,6 +54,7 @@ void CreateChildFrameOnUI(
int parent_routing_id,
blink::WebTreeScopeType scope,
const std::string& frame_name,
+ const std::string& frame_unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties,
int new_routing_id) {
@@ -62,7 +65,7 @@ void CreateChildFrameOnUI(
// processing a subframe creation message.
if (render_frame_host) {
render_frame_host->OnCreateChildFrame(new_routing_id, scope, frame_name,
- sandbox_flags,
+ frame_unique_name, sandbox_flags,
frame_owner_properties);
}
}
@@ -139,80 +142,6 @@ class RenderFrameMessageFilter::OpenChannelToPpapiBrokerCallback
int routing_id_;
};
-class RenderFrameMessageFilter::OpenChannelToNpapiPluginCallback
- : public RenderMessageCompletionCallback,
- public PluginProcessHost::Client {
- public:
- OpenChannelToNpapiPluginCallback(RenderFrameMessageFilter* filter,
- ResourceContext* context,
- IPC::Message* reply_msg)
- : RenderMessageCompletionCallback(filter, reply_msg),
- context_(context),
- host_(nullptr),
- sent_plugin_channel_request_(false) {
- }
-
- int ID() override { return filter()->render_process_id_; }
-
- ResourceContext* GetResourceContext() override { return context_; }
-
- bool OffTheRecord() override {
- if (filter()->incognito_)
- return true;
- if (GetContentClient()->browser()->AllowSaveLocalState(context_))
- return false;
-
- // For now, only disallow storing data for Flash <http://crbug.com/97319>.
- for (const auto& type : info_.mime_types) {
- if (type.mime_type == kFlashPluginSwfMimeType)
- return true;
- }
- return false;
- }
-
- void SetPluginInfo(const WebPluginInfo& info) override { info_ = info; }
-
- void OnFoundPluginProcessHost(PluginProcessHost* host) override {
- DCHECK(host);
- host_ = host;
- }
-
- void OnSentPluginChannelRequest() override {
- sent_plugin_channel_request_ = true;
- }
-
- void OnChannelOpened(const IPC::ChannelHandle& handle) override {
- WriteReplyAndDeleteThis(handle);
- }
-
- void OnError() override { WriteReplyAndDeleteThis(IPC::ChannelHandle()); }
-
- PluginProcessHost* host() const {
- return host_;
- }
-
- bool sent_plugin_channel_request() const {
- return sent_plugin_channel_request_;
- }
-
- void Cancel() {
- delete this;
- }
-
- private:
- void WriteReplyAndDeleteThis(const IPC::ChannelHandle& handle) {
- FrameHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg(),
- handle, info_);
- filter()->OnCompletedOpenChannelToNpapiPlugin(this);
- SendReplyAndDeleteThis();
- }
-
- ResourceContext* context_;
- WebPluginInfo info_;
- PluginProcessHost* host_;
- bool sent_plugin_channel_request_;
-};
-
class RenderFrameMessageFilter::OpenChannelToPpapiPluginCallback
: public RenderMessageCompletionCallback,
public PpapiPluginProcessHost::PluginClient {
@@ -269,27 +198,6 @@ RenderFrameMessageFilter::RenderFrameMessageFilter(
RenderFrameMessageFilter::~RenderFrameMessageFilter() {
// This function should be called on the IO thread.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-#if defined(ENABLE_PLUGINS)
- DCHECK(plugin_host_clients_.empty());
-#endif // ENABLE_PLUGINS
-}
-
-void RenderFrameMessageFilter::OnChannelClosing() {
-#if defined(ENABLE_PLUGINS)
- for (OpenChannelToNpapiPluginCallback* client : plugin_host_clients_) {
- if (client->host()) {
- if (client->sent_plugin_channel_request()) {
- client->host()->CancelSentRequest(client);
- } else {
- client->host()->CancelPendingRequest(client);
- }
- } else {
- plugin_service_->CancelOpenChannelToNpapiPlugin(client);
- }
- client->Cancel();
- }
- plugin_host_clients_.clear();
-#endif // ENABLE_PLUGINS
}
bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
@@ -300,14 +208,11 @@ bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_GetCookies, OnGetCookies)
IPC_MESSAGE_HANDLER(FrameHostMsg_CookiesEnabled, OnCookiesEnabled)
IPC_MESSAGE_HANDLER(FrameHostMsg_Are3DAPIsBlocked, OnAre3DAPIsBlocked)
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidLose3DContext, OnDidLose3DContext)
IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_RenderProcessGone,
OnRenderProcessGone())
#if defined(ENABLE_PLUGINS)
IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_GetPlugins, OnGetPlugins)
IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_OpenChannelToPlugin,
- OnOpenChannelToPlugin)
IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_OpenChannelToPepperPlugin,
OnOpenChannelToPepperPlugin)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidCreateOutOfProcessPepperInstance,
@@ -326,18 +231,15 @@ bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
}
void RenderFrameMessageFilter::OnCreateChildFrame(
- int parent_routing_id,
- blink::WebTreeScopeType scope,
- const std::string& frame_name,
- blink::WebSandboxFlags sandbox_flags,
- const blink::WebFrameOwnerProperties& frame_owner_properties,
+ const FrameHostMsg_CreateChildFrame_Params& params,
int* new_routing_id) {
*new_routing_id = render_widget_helper_->GetNextRoutingID();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&CreateChildFrameOnUI, render_process_id_, parent_routing_id,
- scope, frame_name, sandbox_flags, frame_owner_properties,
- *new_routing_id));
+ base::Bind(&CreateChildFrameOnUI, render_process_id_,
+ params.parent_routing_id, params.scope, params.frame_name,
+ params.frame_unique_name, params.sandbox_flags,
+ params.frame_owner_properties, *new_routing_id));
}
void RenderFrameMessageFilter::OnSetCookie(int render_frame_id,
@@ -393,10 +295,24 @@ void RenderFrameMessageFilter::OnGetCookies(int render_frame_id,
base::debug::Alias(url_buf);
net::URLRequestContext* context = GetRequestContextForURL(url);
- context->cookie_store()->GetAllCookiesForURLAsync(
- url, base::Bind(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
- render_frame_id, url, first_party_for_cookies,
- reply_msg));
+
+ net::CookieOptions options;
+ if (net::registry_controlled_domains::SameDomainOrHost(
+ url, first_party_for_cookies,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
+ // TODO(mkwst): This check ought to further distinguish between frames
+ // initiated in a strict or lax same-site context.
+ options.set_same_site_cookie_mode(
+ net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+ } else {
+ options.set_same_site_cookie_mode(
+ net::CookieOptions::SameSiteCookieMode::DO_NOT_INCLUDE);
+ }
+
+ context->cookie_store()->GetCookieListWithOptionsAsync(
+ url, options,
+ base::Bind(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
+ render_frame_id, url, first_party_for_cookies, reply_msg));
}
void RenderFrameMessageFilter::OnCookiesEnabled(
@@ -425,11 +341,8 @@ void RenderFrameMessageFilter::CheckPolicyForCookies(
GetContentClient()->browser()->AllowGetCookie(
url, first_party_for_cookies, cookie_list, resource_context_,
render_process_id_, render_frame_id)) {
- // Gets the cookies from cookie store if allowed.
- context->cookie_store()->GetCookiesWithOptionsAsync(
- url, net::CookieOptions(),
- base::Bind(&RenderFrameMessageFilter::SendGetCookiesResponse,
- this, reply_msg));
+ SendGetCookiesResponse(reply_msg,
+ net::CookieStore::BuildCookieLine(cookie_list));
} else {
SendGetCookiesResponse(reply_msg, std::string());
}
@@ -450,27 +363,6 @@ void RenderFrameMessageFilter::OnAre3DAPIsBlocked(int render_frame_id,
top_origin_url, render_process_id_, render_frame_id, requester);
}
-void RenderFrameMessageFilter::OnDidLose3DContext(
- const GURL& top_origin_url,
- ThreeDAPIType /* unused */,
- int arb_robustness_status_code) {
- GpuDataManagerImpl::DomainGuilt guilt;
- switch (arb_robustness_status_code) {
- case GL_GUILTY_CONTEXT_RESET_ARB:
- guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN;
- break;
- case GL_UNKNOWN_CONTEXT_RESET_ARB:
- guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN;
- break;
- default:
- // Ignore lost contexts known to be innocent.
- return;
- }
-
- GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(
- top_origin_url, guilt);
-}
-
void RenderFrameMessageFilter::OnRenderProcessGone() {
// FrameHostMessage_RenderProcessGone is a synthetic IPC message used by
// RenderProcessHostImpl to clean things up after a crash (it's injected
@@ -547,28 +439,6 @@ void RenderFrameMessageFilter::OnGetPluginInfo(
nullptr, info, actual_mime_type);
}
-void RenderFrameMessageFilter::OnOpenChannelToPlugin(
- int render_frame_id,
- const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg) {
- OpenChannelToNpapiPluginCallback* client =
- new OpenChannelToNpapiPluginCallback(this, resource_context_, reply_msg);
- DCHECK(!ContainsKey(plugin_host_clients_, client));
- plugin_host_clients_.insert(client);
- plugin_service_->OpenChannelToNpapiPlugin(
- render_process_id_, render_frame_id,
- url, policy_url, mime_type, client);
-}
-
-void RenderFrameMessageFilter::OnCompletedOpenChannelToNpapiPlugin(
- OpenChannelToNpapiPluginCallback* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ContainsKey(plugin_host_clients_, client));
- plugin_host_clients_.erase(client);
-}
-
void RenderFrameMessageFilter::OnOpenChannelToPepperPlugin(
const base::FilePath& path,
IPC::Message* reply_msg) {
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.h b/chromium/content/browser/frame_host/render_frame_message_filter.h
index 194e2079b44..16190cf3d67 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.h
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.h
@@ -20,6 +20,7 @@
#include "content/common/pepper_renderer_instance_data.h"
#endif
+struct FrameHostMsg_CreateChildFrame_Params;
class GURL;
namespace net {
@@ -48,26 +49,17 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
net::URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper);
- // IPC::MessageFilter methods:
- void OnChannelClosing() override;
-
// BrowserMessageFilter methods:
bool OnMessageReceived(const IPC::Message& message) override;
private:
- class OpenChannelToNpapiPluginCallback;
class OpenChannelToPpapiPluginCallback;
class OpenChannelToPpapiBrokerCallback;
~RenderFrameMessageFilter() override;
- void OnCreateChildFrame(
- int parent_routing_id,
- blink::WebTreeScopeType scope,
- const std::string& frame_name,
- blink::WebSandboxFlags sandbox_flags,
- const blink::WebFrameOwnerProperties& frame_owner_properties,
- int* new_render_frame_id);
+ void OnCreateChildFrame(const FrameHostMsg_CreateChildFrame_Params& params,
+ int* new_render_frame_id);
void OnSetCookie(int render_frame_id,
const GURL& url,
const GURL& first_party_for_cookies,
@@ -97,9 +89,6 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
const GURL& top_origin_url,
ThreeDAPIType requester,
bool* blocked);
- void OnDidLose3DContext(const GURL& top_origin_url,
- ThreeDAPIType context_type,
- int arb_robustness_status_code);
void OnRenderProcessGone();
@@ -114,13 +103,6 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
bool* found,
WebPluginInfo* info,
std::string* actual_mime_type);
- void OnOpenChannelToPlugin(int render_frame_id,
- const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg);
- void OnCompletedOpenChannelToNpapiPlugin(
- OpenChannelToNpapiPluginCallback* client);
void OnOpenChannelToPepperPlugin(const base::FilePath& path,
IPC::Message* reply_msg);
void OnDidCreateOutOfProcessPepperInstance(
@@ -149,8 +131,6 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
// Initialized to 0, accessed on FILE thread only.
base::TimeTicks last_plugin_refresh_time_;
-
- std::set<OpenChannelToNpapiPluginCallback*> plugin_host_clients_;
#endif // ENABLE_PLUGINS
// Contextual information to be used for requests created here.
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/chromium/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index 3362e96081c..1cd3cf0b240 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/chromium/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -24,6 +24,7 @@
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
namespace content {
@@ -38,7 +39,14 @@ std::string GetCookieFromJS(RenderFrameHost* frame) {
} // namespace
-using RenderFrameMessageFilterBrowserTest = ContentBrowserTest;
+class RenderFrameMessageFilterBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ ContentBrowserTest::SetUp();
+ }
+};
// Exercises basic cookie operations via javascript, including an http page
// interacting with secure cookies.
@@ -48,7 +56,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, Cookies) {
SetupCrossSiteRedirector(embedded_test_server());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
- https_server.ServeFilesFromSourceDirectory("content/test/data");
+ https_server.AddDefaultHandlers(
+ base::FilePath(FILE_PATH_LITERAL("content/test/data")));
ASSERT_TRUE(https_server.Start());
// The server sends a HttpOnly cookie. The RenderFrameMessageFilter should
@@ -78,30 +87,74 @@ IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, Cookies) {
// Non-TLS page writes secure cookie.
EXPECT_TRUE(ExecuteScript(web_contents_http->GetMainFrame(),
"document.cookie = 'A=1; secure;';"));
- EXPECT_EQ("A=1", GetCookieFromJS(web_contents_https->GetMainFrame()));
+ EXPECT_EQ("", GetCookieFromJS(web_contents_https->GetMainFrame()));
EXPECT_EQ("", GetCookieFromJS(web_contents_http->GetMainFrame()));
// TLS page writes not-secure cookie.
EXPECT_TRUE(ExecuteScript(web_contents_http->GetMainFrame(),
"document.cookie = 'B=2';"));
- EXPECT_EQ("A=1; B=2", GetCookieFromJS(web_contents_https->GetMainFrame()));
+ EXPECT_EQ("B=2", GetCookieFromJS(web_contents_https->GetMainFrame()));
EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetMainFrame()));
- // Non-TLS page writes secure cookie.
+ // TLS page writes secure cookie.
EXPECT_TRUE(ExecuteScript(web_contents_https->GetMainFrame(),
"document.cookie = 'C=3;secure;';"));
- EXPECT_EQ("A=1; B=2; C=3",
+ EXPECT_EQ("B=2; C=3",
GetCookieFromJS(web_contents_https->GetMainFrame()));
EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetMainFrame()));
// TLS page writes not-secure cookie.
EXPECT_TRUE(ExecuteScript(web_contents_https->GetMainFrame(),
"document.cookie = 'D=4';"));
- EXPECT_EQ("A=1; B=2; C=3; D=4",
+ EXPECT_EQ("B=2; C=3; D=4",
GetCookieFromJS(web_contents_https->GetMainFrame()));
EXPECT_EQ("B=2; D=4", GetCookieFromJS(web_contents_http->GetMainFrame()));
}
+// SameSite cookies (that aren't marked as http-only) should be available to
+// JavaScript.
+IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, SameSiteCookies) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ SetupCrossSiteRedirector(embedded_test_server());
+
+ // The server sets five cookies on 'a.com' and on 'b.com', then loads a
+ // page that frames both 'a.com' and 'b.com' under 'a.com'.
+ std::string cookies_to_set =
+ "/set-cookie?normal=1"
+ "&strict=1;SameSite=Strict"
+ "&lax=1;SameSite=Lax"
+ "&strict-http=1;SameSite=Strict;httponly"
+ "&lax-http=1;SameSite=Lax;httponly";
+
+ GURL url = embedded_test_server()->GetURL("a.com", cookies_to_set);
+ NavigateToURL(shell(), url);
+ url = embedded_test_server()->GetURL("b.com", cookies_to_set);
+ NavigateToURL(shell(), url);
+ url = embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a(),b())");
+ NavigateToURL(shell(), url);
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderFrameHost* main_frame = web_contents->GetMainFrame();
+ RenderFrameHost* a_iframe =
+ web_contents->GetFrameTree()->root()->child_at(0)->current_frame_host();
+ RenderFrameHost* b_iframe =
+ web_contents->GetFrameTree()->root()->child_at(1)->current_frame_host();
+
+ // The top-level frame should get both kinds of same-site cookies.
+ EXPECT_EQ("normal=1; strict=1; lax=1", GetCookieFromJS(main_frame));
+
+ // Same-site cookies will be delievered to the 'a.com' frame, as it is same-
+ // site with its ancestors.
+ EXPECT_EQ("normal=1; strict=1; lax=1", GetCookieFromJS(a_iframe));
+
+ // Same-site cookies should not be delievered to the 'b.com' frame, as it
+ // isn't same-site with its ancestors.
+ EXPECT_EQ("normal=1", GetCookieFromJS(b_iframe));
+}
+
// The RenderFrameMessageFilter will kill processes when they access the cookies
// of sites other than the site the process is dedicated to, under site
// isolation.
diff --git a/chromium/content/browser/frame_host/render_frame_proxy_host.cc b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
index 49bcfc9093a..f4ba295b7ad 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
@@ -11,6 +11,7 @@
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
@@ -121,18 +122,6 @@ RenderWidgetHostView* RenderFrameProxyHost::GetRenderWidgetHostView() {
->GetRenderWidgetHostView();
}
-void RenderFrameProxyHost::TakeFrameHostOwnership(
- scoped_ptr<RenderFrameHostImpl> render_frame_host) {
- CHECK(render_frame_host_ == nullptr);
- render_frame_host_ = std::move(render_frame_host);
- render_frame_host_->set_render_frame_proxy_host(this);
-}
-
-scoped_ptr<RenderFrameHostImpl> RenderFrameProxyHost::PassFrameHostOwnership() {
- render_frame_host_->set_render_frame_proxy_host(NULL);
- return std::move(render_frame_host_);
-}
-
bool RenderFrameProxyHost::Send(IPC::Message *msg) {
return GetProcess()->Send(msg);
}
@@ -247,9 +236,25 @@ void RenderFrameProxyHost::OnDetach() {
void RenderFrameProxyHost::OnOpenURL(
const FrameHostMsg_OpenURL_Params& params) {
- // TODO(creis): Verify that we are in the same BrowsingInstance as the current
- // RenderFrameHost. See NavigatorImpl::RequestOpenURL.
- frame_tree_node_->current_frame_host()->OpenURL(params, site_instance_.get());
+ GURL validated_url(params.url);
+ GetProcess()->FilterURL(false, &validated_url);
+
+ // Verify that we are in the same BrowsingInstance as the current
+ // RenderFrameHost.
+ RenderFrameHostImpl* current_rfh = frame_tree_node_->current_frame_host();
+ if (!site_instance_->IsRelatedSiteInstance(current_rfh->GetSiteInstance()))
+ return;
+
+ // Since this navigation targeted a specific RenderFrameProxy, it should stay
+ // in the current tab.
+ DCHECK_EQ(CURRENT_TAB, params.disposition);
+
+ // TODO(alexmos, creis): Figure out whether |params.user_gesture| needs to be
+ // passed in as well.
+ frame_tree_node_->navigator()->RequestTransferURL(
+ current_rfh, validated_url, site_instance_.get(), std::vector<GURL>(),
+ params.referrer, ui::PAGE_TRANSITION_LINK, GlobalRequestID(),
+ params.should_replace_current_entry);
}
void RenderFrameProxyHost::OnRouteMessageEvent(
diff --git a/chromium/content/browser/frame_host/render_frame_proxy_host.h b/chromium/content/browser/frame_host/render_frame_proxy_host.h
index 390de28e6b8..6aa2848c3c7 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.h
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.h
@@ -96,10 +96,6 @@ class RenderFrameProxyHost
RenderViewHostImpl* GetRenderViewHost();
RenderWidgetHostView* GetRenderWidgetHostView();
- void TakeFrameHostOwnership(
- scoped_ptr<RenderFrameHostImpl> render_frame_host);
- scoped_ptr<RenderFrameHostImpl> PassFrameHostOwnership();
-
// IPC::Sender
bool Send(IPC::Message* msg) override;
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc b/chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc
index e8d384e7233..6c022fba3f6 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -9,6 +9,8 @@
#include <vector>
#include "build/build_config.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_manager.h"
@@ -22,10 +24,10 @@
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/browser_plugin_guest_mode.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
@@ -34,20 +36,14 @@ namespace content {
RenderWidgetHostViewChildFrame::RenderWidgetHostViewChildFrame(
RenderWidgetHost* widget_host)
: host_(RenderWidgetHostImpl::From(widget_host)),
- use_surfaces_(UseSurfacesEnabled()),
next_surface_sequence_(1u),
last_output_surface_id_(0),
current_surface_scale_factor_(1.f),
ack_pending_count_(0),
frame_connector_(nullptr),
weak_factory_(this) {
- if (use_surfaces_) {
- id_allocator_ = CreateSurfaceIdAllocator();
- if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
- host_->delegate()->GetInputEventRouter()->AddSurfaceIdNamespaceOwner(
- GetSurfaceIdNamespace(), this);
- }
- }
+ id_allocator_ = CreateSurfaceIdAllocator();
+ RegisterSurfaceNamespaceId();
host_->SetView(this);
}
@@ -72,6 +68,11 @@ void RenderWidgetHostViewChildFrame::SetSize(const gfx::Size& size) {
void RenderWidgetHostViewChildFrame::SetBounds(const gfx::Rect& rect) {
SetSize(rect.size());
+
+ if (rect != last_screen_rect_) {
+ last_screen_rect_ = rect;
+ host_->SendScreenRects();
+ }
}
void RenderWidgetHostViewChildFrame::Focus() {
@@ -84,8 +85,7 @@ bool RenderWidgetHostViewChildFrame::HasFocus() const {
}
bool RenderWidgetHostViewChildFrame::IsSurfaceAvailableForCopy() const {
- NOTIMPLEMENTED();
- return false;
+ return surface_factory_ && !surface_id_.is_null();
}
void RenderWidgetHostViewChildFrame::Show() {
@@ -106,11 +106,42 @@ bool RenderWidgetHostViewChildFrame::IsShowing() {
gfx::Rect RenderWidgetHostViewChildFrame::GetViewBounds() const {
gfx::Rect rect;
- if (frame_connector_)
+ if (frame_connector_) {
rect = frame_connector_->ChildFrameRect();
+
+ RenderWidgetHostView* parent_view =
+ frame_connector_->GetParentRenderWidgetHostView();
+
+ // The parent_view can be null in tests when using a TestWebContents.
+ if (parent_view) {
+ // Translate frame_rect by the parent's RenderWidgetHostView offset.
+ rect.Offset(parent_view->GetViewBounds().OffsetFromOrigin());
+ }
+ }
return rect;
}
+gfx::Size RenderWidgetHostViewChildFrame::GetVisibleViewportSize() const {
+ // For subframes, the visual viewport corresponds to the main frame size, so
+ // this bubbles up to the parent until it hits the main frame's
+ // RenderWidgetHostView.
+ //
+ // Currently this excludes webview guests, since they expect the visual
+ // viewport to return the guest's size rather than the page's; one reason why
+ // is that Blink ends up using the visual viewport to calculate things like
+ // window.innerWidth/innerHeight for main frames, and a guest is considered
+ // to be a main frame. This should be cleaned up eventually.
+ bool is_guest = BrowserPluginGuest::IsGuest(RenderViewHostImpl::From(host_));
+ if (frame_connector_ && !is_guest) {
+ RenderWidgetHostView* parent_view =
+ frame_connector_->GetParentRenderWidgetHostView();
+ // The parent_view can be null in unit tests when using a TestWebContents.
+ if (parent_view)
+ return parent_view->GetVisibleViewportSize();
+ }
+ return GetViewBounds().size();
+}
+
gfx::Vector2dF RenderWidgetHostViewChildFrame::GetLastScrollOffset() const {
return last_scroll_offset_;
}
@@ -167,10 +198,6 @@ void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
// TODO(kenrb): Fix OOPIF Ime.
}
-void RenderWidgetHostViewChildFrame::MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) {
-}
-
void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
if (frame_connector_)
frame_connector_->UpdateCursor(cursor);
@@ -205,16 +232,18 @@ void RenderWidgetHostViewChildFrame::RenderProcessGone(
}
void RenderWidgetHostViewChildFrame::Destroy() {
+ // SurfaceIdNamespaces registered with RenderWidgetHostInputEventRouter
+ // have already been cleared when RenderWidgetHostViewBase notified its
+ // observers of our impending destruction.
if (frame_connector_) {
frame_connector_->set_view(NULL);
frame_connector_ = NULL;
}
- if (use_surfaces_ && host_->delegate() &&
- host_->delegate()->GetInputEventRouter()) {
- host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
- GetSurfaceIdNamespace());
- }
+ // We notify our observers about shutdown here since we are about to release
+ // host_ and do not want any event calls coming from
+ // RenderWidgetHostInputEventRouter afterwards.
+ NotifyObserversAboutShutdown();
host_->SetView(NULL);
host_ = NULL;
@@ -243,6 +272,24 @@ void RenderWidgetHostViewChildFrame::UnlockCompositingSurface() {
NOTIMPLEMENTED();
}
+void RenderWidgetHostViewChildFrame::RegisterSurfaceNamespaceId() {
+ DCHECK(host_);
+ if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
+ RenderWidgetHostInputEventRouter* router =
+ host_->delegate()->GetInputEventRouter();
+ if (!router->is_registered(GetSurfaceIdNamespace()))
+ router->AddSurfaceIdNamespaceOwner(GetSurfaceIdNamespace(), this);
+ }
+}
+
+void RenderWidgetHostViewChildFrame::UnregisterSurfaceNamespaceId() {
+ DCHECK(host_);
+ if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
+ host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
+ GetSurfaceIdNamespace());
+ }
+}
+
void RenderWidgetHostViewChildFrame::SurfaceDrawn(uint32_t output_surface_id,
cc::SurfaceDrawStatus drawn) {
cc::CompositorFrameAck ack;
@@ -259,20 +306,14 @@ void RenderWidgetHostViewChildFrame::SurfaceDrawn(uint32_t output_surface_id,
void RenderWidgetHostViewChildFrame::OnSwapCompositorFrame(
uint32_t output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
+ TRACE_EVENT0("content",
+ "RenderWidgetHostViewChildFrame::OnSwapCompositorFrame");
+
last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (!frame_connector_)
return;
- // When not using surfaces, the frame just gets proxied to
- // the embedder's renderer to be composited.
- if (!frame->delegated_frame_data || !use_surfaces_) {
- frame_connector_->ChildFrameCompositorFrameSwapped(
- output_surface_id, host_->GetProcess()->GetID(), host_->GetRoutingID(),
- std::move(frame));
- return;
- }
-
cc::RenderPass* root_pass =
frame->delegated_frame_data->render_pass_list.back().get();
@@ -321,6 +362,17 @@ void RenderWidgetHostViewChildFrame::OnSwapCompositorFrame(
DCHECK_LT(ack_pending_count_, 1000U);
surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
ack_callback);
+
+ ProcessFrameSwappedCallbacks();
+}
+
+void RenderWidgetHostViewChildFrame::ProcessFrameSwappedCallbacks() {
+ // We only use callbacks once, therefore we make a new list for registration
+ // before we start, and discard the old list entries when we are done.
+ FrameSwappedCallbackList process_callbacks;
+ process_callbacks.swap(frame_swapped_callbacks_);
+ for (scoped_ptr<base::Closure>& callback : process_callbacks)
+ callback->Run();
}
void RenderWidgetHostViewChildFrame::GetScreenInfo(
@@ -340,16 +392,26 @@ bool RenderWidgetHostViewChildFrame::GetScreenColorProfile(
}
gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
- // We do not have any root window specific parts in this view.
- return GetViewBounds();
+ gfx::Rect rect;
+ if (frame_connector_) {
+ RenderWidgetHostViewBase* root_view =
+ frame_connector_->GetRootRenderWidgetHostView();
+
+ // The root_view can be null in tests when using a TestWebContents.
+ if (root_view)
+ rect = root_view->GetBoundsInRootWindow();
+ }
+ return rect;
}
-#if defined(USE_AURA)
void RenderWidgetHostViewChildFrame::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
+ if (!frame_connector_)
+ return;
+
+ frame_connector_->ForwardProcessAckedTouchEvent(touch, ack_result);
}
-#endif // defined(USE_AURA)
bool RenderWidgetHostViewChildFrame::LockMouse() {
return false;
@@ -359,9 +421,6 @@ void RenderWidgetHostViewChildFrame::UnlockMouse() {
}
uint32_t RenderWidgetHostViewChildFrame::GetSurfaceIdNamespace() {
- if (!use_surfaces_)
- return 0;
-
return id_allocator_->id_namespace();
}
@@ -381,25 +440,33 @@ void RenderWidgetHostViewChildFrame::ProcessMouseWheelEvent(
host_->ForwardWheelEvent(event);
}
-void RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace(
- const gfx::Point& point,
- gfx::Point* transformed_point) {
- *transformed_point = point;
- if (!frame_connector_ || !use_surfaces_)
- return;
+void RenderWidgetHostViewChildFrame::ProcessTouchEvent(
+ const blink::WebTouchEvent& event,
+ const ui::LatencyInfo& latency) {
+ if (event.type == blink::WebInputEvent::TouchStart &&
+ frame_connector_ && !frame_connector_->HasFocus()) {
+ frame_connector_->FocusRootView();
+ }
- frame_connector_->TransformPointToRootCoordSpace(point, surface_id_,
- transformed_point);
+ host_->ForwardTouchEventWithLatencyInfo(event, latency);
}
-#if defined(OS_MACOSX)
-void RenderWidgetHostViewChildFrame::SetActive(bool active) {
+void RenderWidgetHostViewChildFrame::ProcessGestureEvent(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) {
+ host_->ForwardGestureEventWithLatencyInfo(event, latency);
}
-void RenderWidgetHostViewChildFrame::SetWindowVisibility(bool visible) {
+gfx::Point RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace(
+ const gfx::Point& point) {
+ if (!frame_connector_)
+ return point;
+
+ return frame_connector_->TransformPointToRootCoordSpace(point, surface_id_);
}
-void RenderWidgetHostViewChildFrame::WindowFrameChanged() {
+#if defined(OS_MACOSX)
+void RenderWidgetHostViewChildFrame::SetActive(bool active) {
}
void RenderWidgetHostViewChildFrame::ShowDefinitionForSelection() {
@@ -418,19 +485,46 @@ bool RenderWidgetHostViewChildFrame::IsSpeaking() const {
void RenderWidgetHostViewChildFrame::StopSpeaking() {
}
+#endif // defined(OS_MACOSX)
-bool RenderWidgetHostViewChildFrame::PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) {
- return false;
+void RenderWidgetHostViewChildFrame::RegisterFrameSwappedCallback(
+ scoped_ptr<base::Closure> callback) {
+ frame_swapped_callbacks_.push_back(std::move(callback));
}
-#endif // defined(OS_MACOSX)
void RenderWidgetHostViewChildFrame::CopyFromCompositingSurface(
- const gfx::Rect& /* src_subrect */,
- const gfx::Size& /* dst_size */,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& output_size,
const ReadbackRequestCallback& callback,
- const SkColorType /* preferred_color_type */) {
- callback.Run(SkBitmap(), READBACK_FAILED);
+ const SkColorType preferred_color_type) {
+ if (!IsSurfaceAvailableForCopy()) {
+ // Defer submitting the copy request until after a frame is drawn, at which
+ // point we should be guaranteed that the surface is available.
+ RegisterFrameSwappedCallback(make_scoped_ptr(new base::Closure(base::Bind(
+ &RenderWidgetHostViewChildFrame::SubmitSurfaceCopyRequest, AsWeakPtr(),
+ src_subrect, output_size, callback, preferred_color_type))));
+ return;
+ }
+
+ SubmitSurfaceCopyRequest(src_subrect, output_size, callback,
+ preferred_color_type);
+}
+
+void RenderWidgetHostViewChildFrame::SubmitSurfaceCopyRequest(
+ const gfx::Rect& src_subrect,
+ const gfx::Size& output_size,
+ const ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type) {
+ DCHECK(IsSurfaceAvailableForCopy());
+
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
+ preferred_color_type, callback));
+ if (!src_subrect.IsEmpty())
+ request->set_area(src_subrect);
+
+ surface_factory_->RequestCopyOfSurface(surface_id_, std::move(request));
}
void RenderWidgetHostViewChildFrame::CopyFromCompositingSurfaceToVideoFrame(
@@ -450,17 +544,6 @@ bool RenderWidgetHostViewChildFrame::HasAcceleratedSurface(
return false;
}
-#if defined(OS_WIN)
-void RenderWidgetHostViewChildFrame::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {
-}
-
-gfx::NativeViewId RenderWidgetHostViewChildFrame::GetParentForWindowlessPlugin()
- const {
- return NULL;
-}
-#endif // defined(OS_WIN)
-
// cc::SurfaceFactoryClient implementation.
void RenderWidgetHostViewChildFrame::ReturnResources(
const cc::ReturnedResourceArray& resources) {
@@ -481,20 +564,15 @@ void RenderWidgetHostViewChildFrame::ReturnResources(
}
void RenderWidgetHostViewChildFrame::SetBeginFrameSource(
- cc::SurfaceId surface_id,
cc::BeginFrameSource* begin_frame_source) {
// TODO(tansell): Hook this up.
}
BrowserAccessibilityManager*
RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) {
-#if defined(OS_ANDROID) && defined(USE_AURA)
- return nullptr;
-#else
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
return BrowserAccessibilityManager::Create(
BrowserAccessibilityManager::GetEmptyDocument(), delegate);
-#endif
}
void RenderWidgetHostViewChildFrame::ClearCompositorSurfaceIfNecessary() {
@@ -503,4 +581,12 @@ void RenderWidgetHostViewChildFrame::ClearCompositorSurfaceIfNecessary() {
surface_id_ = cc::SurfaceId();
}
+bool RenderWidgetHostViewChildFrame::IsChildFrameForTesting() const {
+ return true;
+}
+
+cc::SurfaceId RenderWidgetHostViewChildFrame::SurfaceIdForTesting() const {
+ return surface_id_;
+};
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h b/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h
index 4bacd21f3d8..825ca060805 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/chromium/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -8,8 +8,10 @@
#include <stddef.h>
#include <stdint.h>
+#include <deque>
#include <vector>
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
@@ -17,8 +19,10 @@
#include "cc/surfaces/surface_factory_client.h"
#include "cc/surfaces/surface_id_allocator.h"
#include "content/browser/compositor/image_transport_factory.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
+#include "content/common/input/input_event_ack_state.h"
#include "content/public/browser/readback_types.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/geometry/rect.h"
@@ -58,6 +62,15 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
frame_connector_ = frame_connector;
}
+ // This functions registers single-use callbacks that want to be notified when
+ // the next frame is swapped. The callback is triggered by
+ // OnSwapCompositorFrame, which is the appropriate time to request pixel
+ // readback for the frame that is about to be drawn. Once called, the callback
+ // pointer is released.
+ // TODO(wjmaclean): We should consider making this available in other view
+ // types, such as RenderWidgetHostViewAura.
+ void RegisterFrameSwappedCallback(scoped_ptr<base::Closure> callback);
+
// RenderWidgetHostView implementation.
void InitAsChild(gfx::NativeView parent_view) override;
RenderWidgetHost* GetRenderWidgetHost() const override;
@@ -70,6 +83,7 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void Hide() override;
bool IsShowing() override;
gfx::Rect GetViewBounds() const override;
+ gfx::Size GetVisibleViewportSize() const override;
gfx::Vector2dF GetLastScrollOffset() const override;
gfx::NativeView GetNativeView() const override;
gfx::NativeViewId GetNativeViewId() const override;
@@ -81,7 +95,6 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void UpdateCursor(const WebCursor& cursor) override;
void SetIsLoading(bool is_loading) override;
void TextInputStateChanged(
@@ -118,56 +131,55 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void GetScreenInfo(blink::WebScreenInfo* results) override;
bool GetScreenColorProfile(std::vector<char>* color_profile) override;
gfx::Rect GetBoundsInRootWindow() override;
-#if defined(USE_AURA)
void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) override;
-#endif // defined(USE_AURA)
bool LockMouse() override;
void UnlockMouse() override;
uint32_t GetSurfaceIdNamespace() override;
void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event) override;
void ProcessMouseEvent(const blink::WebMouseEvent& event) override;
void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
- void TransformPointToRootCoordSpace(const gfx::Point& point,
- gfx::Point* transformed_point) override;
+ void ProcessTouchEvent(const blink::WebTouchEvent& event,
+ const ui::LatencyInfo& latency) override;
+ void ProcessGestureEvent(const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) override;
+ gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point) override;
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
void SetActive(bool active) override;
- void SetWindowVisibility(bool visible) override;
- void WindowFrameChanged() override;
void ShowDefinitionForSelection() override;
bool SupportsSpeech() const override;
void SpeakSelection() override;
bool IsSpeaking() const override;
void StopSpeaking() override;
-
- // RenderWidgetHostViewBase implementation.
- bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) override;
#endif // defined(OS_MACOSX)
// RenderWidgetHostViewBase implementation.
void LockCompositingSurface() override;
void UnlockCompositingSurface() override;
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) override;
- gfx::NativeViewId GetParentForWindowlessPlugin() const override;
-#endif
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) override;
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) override;
// cc::SurfaceFactoryClient implementation.
void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void SetBeginFrameSource(cc::SurfaceId surface_id,
- cc::BeginFrameSource* begin_frame_source) override;
+ void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
// Declared 'public' instead of 'protected' here to allow derived classes
// to Bind() to it.
void SurfaceDrawn(uint32_t output_surface_id, cc::SurfaceDrawStatus drawn);
+ // Exposed for tests.
+ bool IsChildFrameForTesting() const override;
+ cc::SurfaceId SurfaceIdForTesting() const override;
+ CrossProcessFrameConnector* FrameConnectorForTesting() const {
+ return frame_connector_;
+ }
+
+ void RegisterSurfaceNamespaceId();
+ void UnregisterSurfaceNamespaceId();
+
protected:
friend class RenderWidgetHostView;
friend class RenderWidgetHostViewChildFrameTest;
@@ -176,6 +188,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
// Clears current compositor surface, if one is in use.
void ClearCompositorSurfaceIfNecessary();
+ void ProcessFrameSwappedCallbacks();
+
// The last scroll offset of the view.
gfx::Vector2dF last_scroll_offset_;
@@ -183,9 +197,6 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
// The model object.
RenderWidgetHostImpl* host_;
- // Flag determining whether we render into a compositing Surface.
- bool use_surfaces_;
-
// Surface-related state.
scoped_ptr<cc::SurfaceIdAllocator> id_allocator_;
scoped_ptr<cc::SurfaceFactory> surface_factory_;
@@ -194,6 +205,7 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
uint32_t last_output_surface_id_;
gfx::Size current_surface_size_;
float current_surface_scale_factor_;
+ gfx::Rect last_screen_rect_;
uint32_t ack_pending_count_;
cc::ReturnedResourceArray surface_returned_resources_;
@@ -206,6 +218,16 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
}
private:
+ void SubmitSurfaceCopyRequest(const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ const ReadbackRequestCallback& callback,
+ const SkColorType preferred_color_type);
+
+ using FrameSwappedCallbackList = std::deque<scoped_ptr<base::Closure>>;
+ // Since frame-drawn callbacks are "fire once", we use std::deque to make
+ // it convenient to swap() when processing the list.
+ FrameSwappedCallbackList frame_swapped_callbacks_;
+
base::WeakPtrFactory<RenderWidgetHostViewChildFrame> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrame);
};
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc b/chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
index fbf418b38c0..4584e084c71 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
@@ -42,23 +42,9 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
class MockCrossProcessFrameConnector : public CrossProcessFrameConnector {
public:
MockCrossProcessFrameConnector()
- : CrossProcessFrameConnector(nullptr),
- last_scale_factor_received_(0.f),
- received_delegated_frame_(false) {}
+ : CrossProcessFrameConnector(nullptr), last_scale_factor_received_(0.f) {}
~MockCrossProcessFrameConnector() override {}
- void ChildFrameCompositorFrameSwapped(
- uint32_t output_surface_id,
- int host_id,
- int route_id,
- scoped_ptr<cc::CompositorFrame> frame) override {
- received_delegated_frame_ = true;
- last_frame_size_received_ =
- frame->delegated_frame_data->render_pass_list.back()
- ->output_rect.size();
- last_scale_factor_received_ = frame->metadata.device_scale_factor;
- }
-
void SetChildFrameSurface(const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
float scale_factor,
@@ -71,8 +57,6 @@ class MockCrossProcessFrameConnector : public CrossProcessFrameConnector {
cc::SurfaceId last_surface_id_received_;
gfx::Size last_frame_size_received_;
float last_scale_factor_received_;
-
- bool received_delegated_frame_;
};
} // namespace
@@ -168,27 +152,20 @@ TEST_F(RenderWidgetHostViewChildFrameTest, SwapCompositorFrame) {
view_->OnSwapCompositorFrame(
0, CreateDelegatedFrame(scale_factor, view_size, view_rect));
- if (UseSurfacesEnabled()) {
- cc::SurfaceId id = surface_id();
- if (!id.is_null()) {
+ cc::SurfaceId id = surface_id();
+ if (!id.is_null()) {
#if !defined(OS_ANDROID)
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- cc::SurfaceManager* manager = factory->GetSurfaceManager();
- cc::Surface* surface = manager->GetSurfaceForId(id);
- EXPECT_TRUE(surface);
- // There should be a SurfaceSequence created by the RWHVChildFrame.
- EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ cc::Surface* surface = manager->GetSurfaceForId(id);
+ EXPECT_TRUE(surface);
+ // There should be a SurfaceSequence created by the RWHVChildFrame.
+ EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
#endif
- // Surface ID should have been passed to CrossProcessFrameConnector to
- // be sent to the embedding renderer.
- EXPECT_EQ(id, test_frame_connector_->last_surface_id_received_);
- EXPECT_EQ(view_size, test_frame_connector_->last_frame_size_received_);
- EXPECT_EQ(scale_factor,
- test_frame_connector_->last_scale_factor_received_);
- }
- } else {
- EXPECT_TRUE(test_frame_connector_->received_delegated_frame_);
+ // Surface ID should have been passed to CrossProcessFrameConnector to
+ // be sent to the embedding renderer.
+ EXPECT_EQ(id, test_frame_connector_->last_surface_id_received_);
EXPECT_EQ(view_size, test_frame_connector_->last_frame_size_received_);
EXPECT_EQ(scale_factor, test_frame_connector_->last_scale_factor_received_);
}
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
index 9240afb45a9..e90f44bd0b1 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -22,11 +22,11 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/frame_messages.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/input/web_touch_event_traits.h"
+#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
-#include "content/common/webplugin_geometry.h"
#include "content/public/common/content_switches.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
@@ -40,20 +40,6 @@
namespace content {
-namespace {
-
-#if defined(USE_AURA)
-blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) {
- blink::WebGestureEvent gesture_event;
- gesture_event.timeStampSeconds = time_stamp;
- gesture_event.type = blink::WebGestureEvent::GestureFlingCancel;
- gesture_event.sourceDevice = blink::WebGestureDeviceTouchscreen;
- return gesture_event;
-}
-#endif // defined(USE_AURA)
-
-} // namespace
-
RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
RenderWidgetHost* widget_host,
BrowserPluginGuest* guest,
@@ -62,10 +48,11 @@ RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
// |guest| is NULL during test.
guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
platform_view_(platform_view) {
+ // Inputs for guest view are already scaled.
+ host_->set_scale_input_to_viewport(false);
}
-RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
-}
+RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {}
bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
const IPC::Message& message,
@@ -166,24 +153,6 @@ void RenderWidgetHostViewGuest::ProcessTouchEvent(
host_->ForwardTouchEventWithLatencyInfo(event, latency);
}
-void RenderWidgetHostViewGuest::RegisterSurfaceNamespaceId() {
- DCHECK(host_);
- if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
- RenderWidgetHostInputEventRouter* router =
- host_->delegate()->GetInputEventRouter();
- if (!router->is_registered(GetSurfaceIdNamespace()))
- router->AddSurfaceIdNamespaceOwner(GetSurfaceIdNamespace(), this);
- }
-}
-
-void RenderWidgetHostViewGuest::UnregisterSurfaceNamespaceId() {
- DCHECK(host_);
- if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
- host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
- GetSurfaceIdNamespace());
- }
-}
-
gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
if (!guest_)
return gfx::Rect();
@@ -196,6 +165,10 @@ gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
guest_->GetScreenCoordinates(embedder_bounds.origin()), size_);
}
+gfx::Rect RenderWidgetHostViewGuest::GetBoundsInRootWindow() {
+ return GetViewBounds();
+}
+
void RenderWidgetHostViewGuest::RenderProcessGone(
base::TerminationStatus status,
int error_code) {
@@ -234,14 +207,9 @@ void RenderWidgetHostViewGuest::SetTooltipText(
void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
uint32_t output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
+ TRACE_EVENT0("content", "RenderWidgetHostViewGuest::OnSwapCompositorFrame");
+
last_scroll_offset_ = frame->metadata.root_scroll_offset;
- // When not using surfaces, the frame just gets proxied to
- // the embedder's renderer to be composited.
- if (!frame->delegated_frame_data || !use_surfaces_) {
- guest_->SwapCompositorFrame(output_surface_id, host_->GetProcess()->GetID(),
- host_->GetRoutingID(), std::move(frame));
- return;
- }
cc::RenderPass* root_pass =
frame->delegated_frame_data->render_pass_list.back().get();
@@ -292,6 +260,9 @@ void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
DCHECK(ack_pending_count_ < 1000);
surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
ack_callback);
+
+ ProcessFrameSwappedCallbacks();
+
// If after detaching we are sent a frame, we should finish processing it, and
// then we should clear the surface so that we are not holding resources we
// no longer need.
@@ -356,11 +327,6 @@ gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
return rwhv->GetNativeViewAccessible();
}
-void RenderWidgetHostViewGuest::MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) {
- platform_view_->MovePluginWindows(moves);
-}
-
void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
// InterstitialPages are not WebContents so we cannot intercept
// ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
@@ -368,10 +334,14 @@ void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
// and so we will always hit this code path.
if (!guest_)
return;
- guest_->SendMessageToEmbedder(
- new BrowserPluginMsg_SetCursor(guest_->browser_plugin_instance_id(),
- cursor));
-
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible()) {
+ RenderWidgetHostViewBase* rwhvb = GetOwnerRenderWidgetHostView();
+ if (rwhvb)
+ rwhvb->UpdateCursor(cursor);
+ } else {
+ guest_->SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(
+ guest_->browser_plugin_instance_id(), cursor));
+ }
}
void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
@@ -476,14 +446,6 @@ void RenderWidgetHostViewGuest::SetActive(bool active) {
platform_view_->SetActive(active);
}
-void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
- platform_view_->SetWindowVisibility(visible);
-}
-
-void RenderWidgetHostViewGuest::WindowFrameChanged() {
- platform_view_->WindowFrameChanged();
-}
-
void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
if (!guest_)
return;
@@ -522,12 +484,6 @@ bool RenderWidgetHostViewGuest::IsSpeaking() const {
void RenderWidgetHostViewGuest::StopSpeaking() {
platform_view_->StopSpeaking();
}
-
-bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) {
- return false;
-}
-
#endif // defined(OS_MACOSX)
#if defined(OS_ANDROID) || defined(USE_AURA)
@@ -545,69 +501,16 @@ void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
NOTIMPLEMENTED();
}
-#if defined(OS_WIN)
-void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {
-}
-
-gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
- const {
- return NULL;
-}
-#endif
-
void RenderWidgetHostViewGuest::DestroyGuestView() {
+ // Let our observers know we're going away, since we don't want any event
+ // processing calls coming in after we release host_.
+ NotifyObserversAboutShutdown();
+
host_->SetView(NULL);
host_ = NULL;
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
-bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
- ui::GestureEvent* gesture) {
-#if defined(USE_AURA)
- if (!host_)
- return false;
-
- if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
- gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
- gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
- return true;
- }
-
- blink::WebGestureEvent web_gesture =
- MakeWebGestureEventFromUIEvent(*gesture);
- const gfx::Point& client_point = gesture->location();
- const gfx::Point& screen_point = gesture->location();
-
- web_gesture.x = client_point.x();
- web_gesture.y = client_point.y();
- web_gesture.globalX = screen_point.x();
- web_gesture.globalY = screen_point.y();
-
- if (web_gesture.type == blink::WebGestureEvent::Undefined)
- return false;
- if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
- host_->ForwardGestureEvent(
- CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
- }
- host_->ForwardGestureEvent(web_gesture);
- return true;
-#else
- return false;
-#endif
-}
-
-void RenderWidgetHostViewGuest::ProcessGestures(
- ui::GestureRecognizer::Gestures* gestures) {
- if ((gestures == NULL) || gestures->empty())
- return;
- for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
- g_it != gestures->end();
- ++g_it) {
- ForwardGestureEventToRenderer(*g_it);
- }
-}
-
RenderWidgetHostViewBase*
RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
return static_cast<RenderWidgetHostViewBase*>(
@@ -637,7 +540,6 @@ void RenderWidgetHostViewGuest::GestureEventAck(
void RenderWidgetHostViewGuest::OnHandleInputEvent(
RenderWidgetHostImpl* embedder,
int browser_plugin_instance_id,
- const gfx::Rect& guest_window_rect,
const blink::WebInputEvent* event) {
if (blink::WebInputEvent::isMouseEventType(event->type)) {
// The mouse events for BrowserPlugin are modified by all
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.h b/chromium/content/browser/frame_host/render_widget_host_view_guest.h
index f9d4b1663ce..4e800c8dd94 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.h
@@ -68,6 +68,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
gfx::NativeViewId GetNativeViewId() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::Rect GetViewBounds() const override;
+ gfx::Rect GetBoundsInRootWindow() override;
gfx::Size GetPhysicalBackingSize() const override;
base::string16 GetSelectedText() const override;
@@ -75,7 +76,6 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void UpdateCursor(const WebCursor& cursor) override;
void SetIsLoading(bool is_loading) override;
void TextInputStateChanged(
@@ -103,8 +103,6 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
#endif
void ProcessTouchEvent(const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) override;
- void RegisterSurfaceNamespaceId();
- void UnregisterSurfaceNamespaceId();
bool LockMouse() override;
void UnlockMouse() override;
@@ -114,17 +112,11 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
void SetActive(bool active) override;
- void SetWindowVisibility(bool visible) override;
- void WindowFrameChanged() override;
void ShowDefinitionForSelection() override;
bool SupportsSpeech() const override;
void SpeakSelection() override;
bool IsSpeaking() const override;
void StopSpeaking() override;
-
- // RenderWidgetHostViewBase implementation.
- bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) override;
#endif // defined(OS_MACOSX)
#if defined(OS_ANDROID) || defined(USE_AURA)
@@ -136,12 +128,6 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
void LockCompositingSurface() override;
void UnlockCompositingSurface() override;
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) override;
- gfx::NativeViewId GetParentForWindowlessPlugin() const override;
-#endif
-
void WheelEventAck(const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) override;
@@ -155,17 +141,10 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
// Destroys this view without calling |Destroy| on |platform_view_|.
void DestroyGuestView();
- // Builds and forwards a WebKitGestureEvent to the renderer.
- bool ForwardGestureEventToRenderer(ui::GestureEvent* gesture);
-
- // Process all of the given gestures (passes them on to renderer)
- void ProcessGestures(ui::GestureRecognizer::Gestures* gestures);
-
RenderWidgetHostViewBase* GetOwnerRenderWidgetHostView() const;
void OnHandleInputEvent(RenderWidgetHostImpl* embedder,
int browser_plugin_instance_id,
- const gfx::Rect& guest_window_rect,
const blink::WebInputEvent* event);
// BrowserPluginGuest and RenderWidgetHostViewGuest's lifetimes are not tied
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc b/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
index 119eb38a840..3d772d46b47 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
@@ -106,17 +106,15 @@ TEST_F(RenderWidgetHostViewGuestTest, VisibilityTest) {
class TestBrowserPluginGuest : public BrowserPluginGuest {
public:
TestBrowserPluginGuest(WebContentsImpl* web_contents,
- BrowserPluginGuestDelegate* delegate):
- BrowserPluginGuest(web_contents->HasOpener(), web_contents, delegate),
- last_scale_factor_received_(0.f),
- received_delegated_frame_(false) {}
+ BrowserPluginGuestDelegate* delegate)
+ : BrowserPluginGuest(web_contents->HasOpener(), web_contents, delegate),
+ last_scale_factor_received_(0.f) {}
~TestBrowserPluginGuest() override {}
void ResetTestData() {
last_surface_id_received_ = cc::SurfaceId();
last_frame_size_received_ = gfx::Size();
last_scale_factor_received_ = 0.f;
- received_delegated_frame_ = false;
}
void set_has_attached_since_surface_set(bool has_attached_since_surface_set) {
@@ -128,21 +126,6 @@ class TestBrowserPluginGuest : public BrowserPluginGuest {
BrowserPluginGuest::set_attached_for_test(attached);
}
- void SwapCompositorFrame(uint32_t output_surface_id,
- int host_process_id,
- int host_routing_id,
- scoped_ptr<cc::CompositorFrame> frame) override {
- received_delegated_frame_ = true;
- last_frame_size_received_ =
- frame->delegated_frame_data->render_pass_list.back()
- ->output_rect.size();
- last_scale_factor_received_ = frame->metadata.device_scale_factor;
-
- // Call base-class version so that we can test UpdateGuestSizeIfNecessary().
- BrowserPluginGuest::SwapCompositorFrame(output_surface_id, host_process_id,
- host_routing_id, std::move(frame));
- }
-
void SetChildFrameSurface(const cc::SurfaceId& surface_id,
const gfx::Size& frame_size,
float scale_factor,
@@ -156,8 +139,6 @@ class TestBrowserPluginGuest : public BrowserPluginGuest {
gfx::Size last_frame_size_received_;
float last_scale_factor_received_;
float update_scale_factor_received_;
-
- bool received_delegated_frame_;
};
// TODO(wjmaclean): we should restructure RenderWidgetHostViewChildFrameTest to
@@ -259,26 +240,19 @@ TEST_F(RenderWidgetHostViewGuestSurfaceTest, TestGuestSurface) {
view_->OnSwapCompositorFrame(
0, CreateDelegatedFrame(scale_factor, view_size, view_rect));
- if (UseSurfacesEnabled()) {
- cc::SurfaceId id = surface_id();
- if (!id.is_null()) {
+ cc::SurfaceId id = surface_id();
+ if (!id.is_null()) {
#if !defined(OS_ANDROID)
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- cc::SurfaceManager* manager = factory->GetSurfaceManager();
- cc::Surface* surface = manager->GetSurfaceForId(id);
- EXPECT_TRUE(surface);
- // There should be a SurfaceSequence created by the RWHVGuest.
- EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ cc::Surface* surface = manager->GetSurfaceForId(id);
+ EXPECT_TRUE(surface);
+ // There should be a SurfaceSequence created by the RWHVGuest.
+ EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
#endif
- // Surface ID should have been passed to BrowserPluginGuest to
- // be sent to the embedding renderer.
- EXPECT_EQ(id, browser_plugin_guest_->last_surface_id_received_);
- EXPECT_EQ(view_size, browser_plugin_guest_->last_frame_size_received_);
- EXPECT_EQ(scale_factor,
- browser_plugin_guest_->last_scale_factor_received_);
- }
- } else {
- EXPECT_TRUE(browser_plugin_guest_->received_delegated_frame_);
+ // Surface ID should have been passed to BrowserPluginGuest to
+ // be sent to the embedding renderer.
+ EXPECT_EQ(id, browser_plugin_guest_->last_surface_id_received_);
EXPECT_EQ(view_size, browser_plugin_guest_->last_frame_size_received_);
EXPECT_EQ(scale_factor, browser_plugin_guest_->last_scale_factor_received_);
}
@@ -289,28 +263,22 @@ TEST_F(RenderWidgetHostViewGuestSurfaceTest, TestGuestSurface) {
view_->OnSwapCompositorFrame(
0, CreateDelegatedFrame(scale_factor, view_size, view_rect));
- if (UseSurfacesEnabled()) {
- cc::SurfaceId id = surface_id();
- if (!id.is_null()) {
+ id = surface_id();
+ if (!id.is_null()) {
#if !defined(OS_ANDROID)
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- cc::SurfaceManager* manager = factory->GetSurfaceManager();
- cc::Surface* surface = manager->GetSurfaceForId(id);
- EXPECT_TRUE(surface);
- // There should be a SurfaceSequence created by the RWHVGuest.
- EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ cc::Surface* surface = manager->GetSurfaceForId(id);
+ EXPECT_TRUE(surface);
+ // There should be a SurfaceSequence created by the RWHVGuest.
+ EXPECT_EQ(1u, surface->GetDestructionDependencyCount());
#endif
- // Surface ID should have been passed to BrowserPluginGuest to
- // be sent to the embedding renderer.
- EXPECT_EQ(id, browser_plugin_guest_->last_surface_id_received_);
- EXPECT_EQ(view_size, browser_plugin_guest_->last_frame_size_received_);
- EXPECT_EQ(scale_factor,
- browser_plugin_guest_->last_scale_factor_received_);
- }
- } else {
- EXPECT_TRUE(browser_plugin_guest_->received_delegated_frame_);
+ // Surface ID should have been passed to BrowserPluginGuest to
+ // be sent to the embedding renderer.
+ EXPECT_EQ(id, browser_plugin_guest_->last_surface_id_received_);
EXPECT_EQ(view_size, browser_plugin_guest_->last_frame_size_received_);
- EXPECT_EQ(scale_factor, browser_plugin_guest_->last_scale_factor_received_);
+ EXPECT_EQ(scale_factor,
+ browser_plugin_guest_->last_scale_factor_received_);
}
browser_plugin_guest_->set_attached(false);
@@ -318,8 +286,7 @@ TEST_F(RenderWidgetHostViewGuestSurfaceTest, TestGuestSurface) {
view_->OnSwapCompositorFrame(
0, CreateDelegatedFrame(scale_factor, view_size, view_rect));
- if (UseSurfacesEnabled())
- EXPECT_TRUE(surface_id().is_null());
+ EXPECT_TRUE(surface_id().is_null());
}
} // namespace content
diff --git a/chromium/content/browser/frame_host/traced_frame_tree_node.cc b/chromium/content/browser/frame_host/traced_frame_tree_node.cc
new file mode 100644
index 00000000000..0141b38e854
--- /dev/null
+++ b/chromium/content/browser/frame_host/traced_frame_tree_node.cc
@@ -0,0 +1,69 @@
+// 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 "content/browser/frame_host/traced_frame_tree_node.h"
+
+#include "base/command_line.h"
+#include "base/json/json_writer.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/public/common/content_switches.h"
+#include "url/gurl.h"
+
+namespace content {
+
+TracedFrameTreeNode::TracedFrameTreeNode(const FrameTreeNode& node)
+ : parent_node_id_(-1),
+ process_id_(-1),
+ routing_id_(-1) {
+ FrameTreeNode* parent = node.parent();
+ if (parent)
+ parent_node_id_ = parent->frame_tree_node_id();
+
+ RenderFrameHostImpl* current_frame_host = node.current_frame_host();
+
+ if (current_frame_host->last_committed_url().is_valid())
+ url_ = current_frame_host->last_committed_url().spec();
+
+ // On Windows, |rph->GetHandle()| does not duplicate ownership
+ // of the process handle and the render host still retains it. Therefore, we
+ // cannot create a base::Process object, which provides a proper way to get a
+ // process id, from the handle. For a stopgap, we use this deprecated
+ // function that does not require the ownership (http://crbug.com/417532).
+ process_id_ = base::GetProcId(current_frame_host->GetProcess()->GetHandle());
+
+ routing_id_ = current_frame_host->GetRoutingID();
+ DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
+}
+
+TracedFrameTreeNode::~TracedFrameTreeNode() {
+}
+
+void TracedFrameTreeNode::AppendAsTraceFormat(std::string* out) const {
+ scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
+
+ if (parent_node_id_ >= 0) {
+ scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue());
+ ref->SetString("id_ref", base::StringPrintf("0x%x", parent_node_id_));
+ ref->SetString("scope", "FrameTreeNode");
+ value->Set("parent", std::move(ref));
+ }
+
+ if (process_id_ >= 0) {
+ scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue());
+ ref->SetInteger("pid_ref", process_id_);
+ ref->SetString("id_ref", base::StringPrintf("0x%x", routing_id_));
+ ref->SetString("scope", "RenderFrame");
+ value->Set("RenderFrame", std::move(ref));
+ }
+
+ if (!url_.empty())
+ value->SetString("url", url_);
+
+ std::string tmp;
+ base::JSONWriter::Write(*value, &tmp);
+ *out += tmp;
+}
+
+} // content
diff --git a/chromium/content/browser/frame_host/traced_frame_tree_node.h b/chromium/content/browser/frame_host/traced_frame_tree_node.h
new file mode 100644
index 00000000000..79c2a80e911
--- /dev/null
+++ b/chromium/content/browser/frame_host/traced_frame_tree_node.h
@@ -0,0 +1,36 @@
+// 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 "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/values.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class FrameTree;
+class FrameTreeNode;
+
+// This is a temporary container used when tracing snapshots of FrameTree
+// objects. When a snapshot of a FrameTree is taken, a TracedFrameTreeNode is
+// created and stored by the tracing system until the trace is dumped.
+class CONTENT_EXPORT TracedFrameTreeNode :
+ public base::trace_event::ConvertableToTraceFormat {
+ public:
+ TracedFrameTreeNode(const FrameTreeNode& node);
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ private:
+ ~TracedFrameTreeNode() override;
+
+ int parent_node_id_;
+ std::string url_;
+ int process_id_;
+ int routing_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracedFrameTreeNode);
+};
+
+} // content
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
index f6fd2d4ef39..87ec3714b66 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -19,8 +19,8 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
-#include "content/browser/udev_linux.h"
#include "device/udev_linux/scoped_udev.h"
+#include "device/udev_linux/udev_linux.h"
namespace {
@@ -77,12 +77,12 @@ GamepadPlatformDataFetcherLinux::GamepadPlatformDataFetcherLinux() {
pad_state_[i].button_mask = 0;
}
- std::vector<UdevLinux::UdevMonitorFilter> filters;
- filters.push_back(UdevLinux::UdevMonitorFilter(kInputSubsystem, NULL));
- udev_.reset(
- new UdevLinux(filters,
- base::Bind(&GamepadPlatformDataFetcherLinux::RefreshDevice,
- base::Unretained(this))));
+ std::vector<device::UdevLinux::UdevMonitorFilter> filters;
+ filters.push_back(
+ device::UdevLinux::UdevMonitorFilter(kInputSubsystem, NULL));
+ udev_.reset(new device::UdevLinux(
+ filters, base::Bind(&GamepadPlatformDataFetcherLinux::RefreshDevice,
+ base::Unretained(this))));
EnumerateDevices();
}
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
index b98646a4e7f..763f1911dd6 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
@@ -18,9 +18,11 @@ extern "C" {
struct udev_device;
}
-namespace content {
-
+namespace device {
class UdevLinux;
+}
+
+namespace content {
class GamepadPlatformDataFetcherLinux : public GamepadDataFetcher {
public:
@@ -39,7 +41,7 @@ class GamepadPlatformDataFetcherLinux : public GamepadDataFetcher {
// File descriptor for the /dev/input/js* devices. -1 if not in use.
int device_fd_[blink::WebGamepads::itemsLengthCap];
- scoped_ptr<UdevLinux> udev_;
+ scoped_ptr<device::UdevLinux> udev_;
DISALLOW_COPY_AND_ASSIGN(GamepadPlatformDataFetcherLinux);
};
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
index 3983694f110..c761e83858f 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -53,10 +53,25 @@ const WebUChar* GamepadSubTypeName(BYTE sub_type) {
}
}
+const WebUChar* XInputDllFileName() {
+ // Xinput.h defines filename (XINPUT_DLL) on different Windows versions, but
+ // Xinput.h specifies it in build time. Approach here uses the same values
+ // and it is resolving dll filename based on Windows version it is running on.
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ // For Windows 8 and 10, XINPUT_DLL is xinput1_4.dll.
+ return FILE_PATH_LITERAL("xinput1_4.dll");
+ } else if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+ return FILE_PATH_LITERAL("xinput9_1_0.dll");
+ } else {
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
} // namespace
GamepadPlatformDataFetcherWin::GamepadPlatformDataFetcherWin()
- : xinput_dll_(base::FilePath(FILE_PATH_LITERAL("xinput1_3.dll"))),
+ : xinput_dll_(base::FilePath(XInputDllFileName())),
xinput_available_(GetXInputDllFunctions()) {
for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
platform_pad_state_[i].status = DISCONNECTED;
@@ -317,10 +332,8 @@ void GamepadPlatformDataFetcherWin::GetRawInputPadData(
bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
xinput_get_capabilities_ = NULL;
xinput_get_state_ = NULL;
- xinput_enable_ = reinterpret_cast<XInputEnableFunc>(
+ XInputEnableFunc xinput_enable = reinterpret_cast<XInputEnableFunc>(
xinput_dll_.GetFunctionPointer("XInputEnable"));
- if (!xinput_enable_)
- return false;
xinput_get_capabilities_ = reinterpret_cast<XInputGetCapabilitiesFunc>(
xinput_dll_.GetFunctionPointer("XInputGetCapabilities"));
if (!xinput_get_capabilities_)
@@ -329,7 +342,10 @@ bool GamepadPlatformDataFetcherWin::GetXInputDllFunctions() {
xinput_dll_.GetFunctionPointer("XInputGetState"));
if (!xinput_get_state_)
return false;
- xinput_enable_(true);
+ if (xinput_enable) {
+ // XInputEnable is unavailable before Win8 and deprecated in Win10.
+ xinput_enable(true);
+ }
return true;
}
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
index f1efab3440b..53356698bfb 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
@@ -49,10 +49,8 @@ class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
typedef DWORD (WINAPI *XInputGetStateFunc)(
DWORD dwUserIndex, XINPUT_STATE* pState);
- // Get functions from dynamically loaded xinput1_3.dll. We don't use
- // DELAYLOAD because the import library for Win8 SDK pulls xinput1_4 which
- // isn't redistributable. Returns true if loading was successful. We include
- // xinput1_3.dll with Chrome.
+ // Get functions from dynamically loading the xinput dll.
+ // Returns true if loading was successful.
bool GetXInputDllFunctions();
// Scan for connected XInput and DirectInput gamepads.
@@ -71,7 +69,6 @@ class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
// Function pointers to XInput functionality, retrieved in
// |GetXinputDllFunctions|.
- XInputEnableFunc xinput_enable_;
XInputGetCapabilitiesFunc xinput_get_capabilities_;
XInputGetStateFunc xinput_get_state_;
diff --git a/chromium/content/browser/gamepad/gamepad_provider.cc b/chromium/content/browser/gamepad/gamepad_provider.cc
index 682afc51d35..fea94e012bd 100644
--- a/chromium/content/browser/gamepad/gamepad_provider.cc
+++ b/chromium/content/browser/gamepad/gamepad_provider.cc
@@ -39,6 +39,9 @@ GamepadProvider::ClosureAndThread::ClosureAndThread(
: closure(c), task_runner(m) {
}
+GamepadProvider::ClosureAndThread::ClosureAndThread(
+ const ClosureAndThread& other) = default;
+
GamepadProvider::ClosureAndThread::~ClosureAndThread() {
}
diff --git a/chromium/content/browser/gamepad/gamepad_provider.h b/chromium/content/browser/gamepad/gamepad_provider.h
index f2dcad245bb..fa154111847 100644
--- a/chromium/content/browser/gamepad/gamepad_provider.h
+++ b/chromium/content/browser/gamepad/gamepad_provider.h
@@ -106,6 +106,7 @@ class CONTENT_EXPORT GamepadProvider :
struct ClosureAndThread {
ClosureAndThread(const base::Closure& c,
const scoped_refptr<base::SingleThreadTaskRunner>& m);
+ ClosureAndThread(const ClosureAndThread& other);
~ClosureAndThread();
base::Closure closure;
diff --git a/chromium/content/browser/geofencing/geofencing_manager.cc b/chromium/content/browser/geofencing/geofencing_manager.cc
index 1fce30f3b4d..e420d5fafd6 100644
--- a/chromium/content/browser/geofencing/geofencing_manager.cc
+++ b/chromium/content/browser/geofencing/geofencing_manager.cc
@@ -395,11 +395,12 @@ void GeofencingManager::DeliverGeofencingEvent(
// until the callback dies. Otherwise the registration could be released when
// this method returns - before the event is delivered to the service worker.
active_version->RunAfterStartWorker(
- base::Bind(&GeofencingManager::OnEventError, this),
+ ServiceWorkerMetrics::EventType::GEOFENCING,
base::Bind(&GeofencingManager::DeliverEventToRunningWorker, this,
service_worker_registration, event_type,
registration->region_id, registration->region,
- make_scoped_refptr(active_version)));
+ make_scoped_refptr(active_version)),
+ base::Bind(&GeofencingManager::OnEventError, this));
}
void GeofencingManager::DeliverEventToRunningWorker(
@@ -424,7 +425,8 @@ void GeofencingManager::OnEventResponse(
const scoped_refptr<ServiceWorkerRegistration>& registration,
int request_id,
blink::WebServiceWorkerEventResult result) {
- bool finish_result = worker->FinishRequest(request_id);
+ bool finish_result = worker->FinishRequest(
+ request_id, result == blink::WebServiceWorkerEventResultCompleted);
DCHECK(finish_result)
<< "No messages should be passed to handler if request had "
"already finished";
diff --git a/chromium/content/browser/geofencing/geofencing_service.h b/chromium/content/browser/geofencing/geofencing_service.h
index 8c91193703f..dddbcfb1c70 100644
--- a/chromium/content/browser/geofencing/geofencing_service.h
+++ b/chromium/content/browser/geofencing/geofencing_service.h
@@ -9,6 +9,7 @@
#include <map>
+#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/geolocation/fake_access_token_store.cc b/chromium/content/browser/geolocation/fake_access_token_store.cc
index 9e8704a0792..176513d2530 100644
--- a/chromium/content/browser/geolocation/fake_access_token_store.cc
+++ b/chromium/content/browser/geolocation/fake_access_token_store.cc
@@ -14,7 +14,7 @@ using testing::Invoke;
namespace content {
-FakeAccessTokenStore::FakeAccessTokenStore() : originating_task_runner_(NULL) {
+FakeAccessTokenStore::FakeAccessTokenStore() {
ON_CALL(*this, LoadAccessTokens(_))
.WillByDefault(Invoke(this,
&FakeAccessTokenStore::DefaultLoadAccessTokens));
@@ -33,19 +33,19 @@ void FakeAccessTokenStore::NotifyDelegateTokensLoaded() {
}
net::URLRequestContextGetter* context_getter = NULL;
- callback_.Run(access_token_set_, context_getter);
+ callback_.Run(access_token_map_, context_getter);
}
void FakeAccessTokenStore::DefaultLoadAccessTokens(
- const LoadAccessTokensCallbackType& callback) {
- originating_task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
+ const LoadAccessTokensCallback& callback) {
+ originating_task_runner_ = base::ThreadTaskRunnerHandle::Get();
callback_ = callback;
}
void FakeAccessTokenStore::DefaultSaveAccessToken(
const GURL& server_url, const base::string16& access_token) {
DCHECK(server_url.is_valid());
- access_token_set_[server_url] = access_token;
+ access_token_map_[server_url] = access_token;
}
FakeAccessTokenStore::~FakeAccessTokenStore() {}
diff --git a/chromium/content/browser/geolocation/fake_access_token_store.h b/chromium/content/browser/geolocation/fake_access_token_store.h
index b6b674dfe73..276f5c5b107 100644
--- a/chromium/content/browser/geolocation/fake_access_token_store.h
+++ b/chromium/content/browser/geolocation/fake_access_token_store.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_GEOLOCATION_FAKE_ACCESS_TOKEN_STORE_H_
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "content/public/browser/access_token_store.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -22,18 +23,18 @@ class FakeAccessTokenStore : public AccessTokenStore {
// AccessTokenStore
MOCK_METHOD1(LoadAccessTokens,
- void(const LoadAccessTokensCallbackType& callback));
+ void(const LoadAccessTokensCallback& callback));
MOCK_METHOD2(SaveAccessToken,
void(const GURL& server_url,
const base::string16& access_token));
- void DefaultLoadAccessTokens(const LoadAccessTokensCallbackType& callback);
+ void DefaultLoadAccessTokens(const LoadAccessTokensCallback& callback);
void DefaultSaveAccessToken(const GURL& server_url,
const base::string16& access_token);
- AccessTokenSet access_token_set_;
- LoadAccessTokensCallbackType callback_;
+ AccessTokenMap access_token_map_;
+ LoadAccessTokensCallback callback_;
protected:
// Protected instead of private so we can have NiceMocks.
@@ -43,7 +44,7 @@ class FakeAccessTokenStore : public AccessTokenStore {
// In some tests, NotifyDelegateTokensLoaded() is called on a thread
// other than the originating thread, in which case we must post
// back to it.
- base::SingleThreadTaskRunner* originating_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> originating_task_runner_;
DISALLOW_COPY_AND_ASSIGN(FakeAccessTokenStore);
};
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl.cc b/chromium/content/browser/geolocation/geolocation_provider_impl.cc
index 60d9efbfc44..c490907c792 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl.cc
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl.cc
@@ -22,10 +22,11 @@ GeolocationProvider* GeolocationProvider::GetInstance() {
scoped_ptr<GeolocationProvider::Subscription>
GeolocationProviderImpl::AddLocationUpdateCallback(
- const LocationUpdateCallback& callback, bool use_high_accuracy) {
+ const LocationUpdateCallback& callback,
+ bool enable_high_accuracy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_ptr<GeolocationProvider::Subscription> subscription;
- if (use_high_accuracy) {
+ if (enable_high_accuracy) {
subscription = high_accuracy_callbacks_.Add(callback);
} else {
subscription = low_accuracy_callbacks_.Add(callback);
@@ -74,8 +75,7 @@ GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() {
GeolocationProviderImpl::GeolocationProviderImpl()
: base::Thread("Geolocation"),
user_did_opt_into_location_services_(false),
- ignore_location_updates_(false),
- arbitrator_(NULL) {
+ ignore_location_updates_(false) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
high_accuracy_callbacks_.set_removal_callback(
base::Bind(&GeolocationProviderImpl::OnClientsChanged,
@@ -113,12 +113,11 @@ void GeolocationProviderImpl::OnClientsChanged() {
InformProvidersPermissionGranted();
}
// Determine a set of options that satisfies all clients.
- bool use_high_accuracy = !high_accuracy_callbacks_.empty();
+ bool enable_high_accuracy = !high_accuracy_callbacks_.empty();
// Send the current options to the providers as they may have changed.
task = base::Bind(&GeolocationProviderImpl::StartProviders,
- base::Unretained(this),
- use_high_accuracy);
+ base::Unretained(this), enable_high_accuracy);
}
task_runner()->PostTask(FROM_HERE, task);
@@ -130,10 +129,10 @@ void GeolocationProviderImpl::StopProviders() {
arbitrator_->StopProviders();
}
-void GeolocationProviderImpl::StartProviders(bool use_high_accuracy) {
+void GeolocationProviderImpl::StartProviders(bool enable_high_accuracy) {
DCHECK(OnGeolocationThread());
DCHECK(arbitrator_);
- arbitrator_->StartProviders(use_high_accuracy);
+ arbitrator_->StartProviders(enable_high_accuracy);
}
void GeolocationProviderImpl::InformProvidersPermissionGranted() {
@@ -167,14 +166,13 @@ void GeolocationProviderImpl::Init() {
void GeolocationProviderImpl::CleanUp() {
DCHECK(OnGeolocationThread());
- delete arbitrator_;
- arbitrator_ = NULL;
+ arbitrator_.reset();
}
-LocationArbitrator* GeolocationProviderImpl::CreateArbitrator() {
+scoped_ptr<LocationArbitrator> GeolocationProviderImpl::CreateArbitrator() {
LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind(
&GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this));
- return new LocationArbitratorImpl(callback);
+ return make_scoped_ptr(new LocationArbitratorImpl(callback));
}
} // namespace content
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl.h b/chromium/content/browser/geolocation/geolocation_provider_impl.h
index fe07da7822f..92129c5093f 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl.h
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl.h
@@ -11,6 +11,7 @@
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
#include "content/public/browser/geolocation_provider.h"
@@ -30,7 +31,7 @@ class CONTENT_EXPORT GeolocationProviderImpl
// GeolocationProvider implementation:
scoped_ptr<GeolocationProvider::Subscription> AddLocationUpdateCallback(
const LocationUpdateCallback& callback,
- bool use_high_accuracy) override;
+ bool enable_high_accuracy) override;
void UserDidOptIntoLocationServices() override;
void OverrideLocationForTesting(const Geoposition& position) override;
@@ -53,7 +54,8 @@ class CONTENT_EXPORT GeolocationProviderImpl
~GeolocationProviderImpl() override;
// Useful for injecting mock geolocation arbitrator in tests.
- virtual LocationArbitrator* CreateArbitrator();
+ // TODO(mvanouwerkerk): Use something like SetArbitratorForTesting instead.
+ virtual scoped_ptr<LocationArbitrator> CreateArbitrator();
private:
bool OnGeolocationThread() const;
@@ -68,7 +70,7 @@ class CONTENT_EXPORT GeolocationProviderImpl
// Starts the geolocation providers or updates their options (delegates to
// arbitrator).
- void StartProviders(bool use_high_accuracy);
+ void StartProviders(bool enable_high_accuracy);
// Updates the providers on the geolocation thread, which must be running.
void InformProvidersPermissionGranted();
@@ -90,7 +92,7 @@ class CONTENT_EXPORT GeolocationProviderImpl
bool ignore_location_updates_;
// Only to be used on the geolocation thread.
- LocationArbitrator* arbitrator_;
+ scoped_ptr<LocationArbitrator> arbitrator_;
DISALLOW_COPY_AND_ASSIGN(GeolocationProviderImpl);
};
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
index 0b354fd01d5..f1c7323f5a4 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
@@ -38,16 +38,18 @@ class LocationProviderForTestArbitrator : public GeolocationProviderImpl {
protected:
// GeolocationProviderImpl implementation:
- LocationArbitrator* CreateArbitrator() override;
+ scoped_ptr<LocationArbitrator> CreateArbitrator() override;
private:
+ // An alias to the arbitrator stored in the super class, where it is owned.
MockLocationArbitrator* mock_arbitrator_;
};
-LocationArbitrator* LocationProviderForTestArbitrator::CreateArbitrator() {
+scoped_ptr<LocationArbitrator>
+LocationProviderForTestArbitrator::CreateArbitrator() {
DCHECK(mock_arbitrator_ == NULL);
mock_arbitrator_ = new MockLocationArbitrator;
- return mock_arbitrator_;
+ return make_scoped_ptr(mock_arbitrator_);
}
class GeolocationObserver {
diff --git a/chromium/content/browser/geolocation/geolocation_service_context.cc b/chromium/content/browser/geolocation/geolocation_service_context.cc
index 7cdeb354faf..aeb6e621034 100644
--- a/chromium/content/browser/geolocation/geolocation_service_context.cc
+++ b/chromium/content/browser/geolocation/geolocation_service_context.cc
@@ -16,7 +16,7 @@ GeolocationServiceContext::~GeolocationServiceContext() {
void GeolocationServiceContext::CreateService(
const base::Closure& update_callback,
- mojo::InterfaceRequest<GeolocationService> request) {
+ mojo::InterfaceRequest<blink::mojom::GeolocationService> request) {
GeolocationServiceImpl* service =
new GeolocationServiceImpl(std::move(request), this, update_callback);
services_.push_back(service);
diff --git a/chromium/content/browser/geolocation/geolocation_service_context.h b/chromium/content/browser/geolocation/geolocation_service_context.h
index 843fd3827cb..2e494a12228 100644
--- a/chromium/content/browser/geolocation/geolocation_service_context.h
+++ b/chromium/content/browser/geolocation/geolocation_service_context.h
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "content/browser/geolocation/geolocation_service_impl.h"
+#include "third_party/WebKit/public/platform/modules/geolocation/geolocation.mojom.h"
namespace content {
@@ -22,8 +23,9 @@ class GeolocationServiceContext {
// Creates a GeolocationServiceImpl that is weakly bound to |request|.
// |update_callback| will be called when services send
// location updates to their clients.
- void CreateService(const base::Closure& update_callback,
- mojo::InterfaceRequest<GeolocationService> request);
+ void CreateService(
+ const base::Closure& update_callback,
+ mojo::InterfaceRequest<blink::mojom::GeolocationService> request);
// Called when a service has a connection error. After this call, it is no
// longer safe to access |service|.
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.cc b/chromium/content/browser/geolocation/geolocation_service_impl.cc
index 764ff10abdd..5424c141e58 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl.cc
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "content/browser/geolocation/geolocation_service_context.h"
-#include "content/public/common/mojo_geoposition.mojom.h"
namespace content {
@@ -79,7 +78,7 @@ GeolocationServiceImpl::~GeolocationServiceImpl() {
// Make sure to respond to any pending callback even without a valid position.
if (!position_callback_.is_null()) {
if (!current_position_.valid) {
- current_position_.error_code = MojoGeoposition::ErrorCode(
+ current_position_.error_code = blink::mojom::Geoposition::ErrorCode(
GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE);
current_position_.error_message = mojo::String("");
}
@@ -178,7 +177,7 @@ void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
current_position_.speed = position.speed;
current_position_.timestamp = position.timestamp.ToDoubleT();
current_position_.error_code =
- MojoGeoposition::ErrorCode(position.error_code);
+ blink::mojom::Geoposition::ErrorCode(position.error_code);
current_position_.error_message = position.error_message;
has_position_to_report_ = true;
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.h b/chromium/content/browser/geolocation/geolocation_service_impl.h
index d72706e5b3c..e0565eed8d5 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl.h
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.h
@@ -5,9 +5,8 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/geolocation/geolocation_provider_impl.h"
-#include "content/common/geolocation_service.mojom.h"
-#include "content/public/common/mojo_geoposition.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/WebKit/public/platform/modules/geolocation/geolocation.mojom.h"
#ifndef CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
#define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
@@ -18,14 +17,15 @@ class GeolocationProvider;
class GeolocationServiceContext;
// Implements the GeolocationService Mojo interface.
-class GeolocationServiceImpl : public GeolocationService {
+class GeolocationServiceImpl : public blink::mojom::GeolocationService {
public:
// |context| must outlive this object. |update_callback| will be called when
// location updates are sent, allowing the client to know when the service
// is being used.
- GeolocationServiceImpl(mojo::InterfaceRequest<GeolocationService> request,
- GeolocationServiceContext* context,
- const base::Closure& update_callback);
+ GeolocationServiceImpl(
+ mojo::InterfaceRequest<blink::mojom::GeolocationService> request,
+ GeolocationServiceContext* context,
+ const base::Closure& update_callback);
~GeolocationServiceImpl() override;
// Starts listening for updates.
@@ -40,9 +40,9 @@ class GeolocationServiceImpl : public GeolocationService {
void ClearOverride();
private:
- typedef mojo::Callback<void(MojoGeopositionPtr)> PositionCallback;
+ typedef mojo::Callback<void(blink::mojom::GeopositionPtr)> PositionCallback;
- // GeolocationService:
+ // blink::mojom::GeolocationService:
void SetHighAccuracy(bool high_accuracy) override;
void QueryNextPosition(const PositionCallback& callback) override;
@@ -52,7 +52,7 @@ class GeolocationServiceImpl : public GeolocationService {
void ReportCurrentPosition();
// The binding between this object and the other end of the pipe.
- mojo::Binding<GeolocationService> binding_;
+ mojo::Binding<blink::mojom::GeolocationService> binding_;
// Owns this object.
GeolocationServiceContext* context_;
@@ -69,7 +69,7 @@ class GeolocationServiceImpl : public GeolocationService {
// subsequently been called.
Geoposition position_override_;
- MojoGeoposition current_position_;
+ blink::mojom::Geoposition current_position_;
// Whether this instance is currently observing location updates with high
// accuracy.
diff --git a/chromium/content/browser/geolocation/location_api_adapter_android.cc b/chromium/content/browser/geolocation/location_api_adapter_android.cc
index 4037ab6e36c..e1472ea7d11 100644
--- a/chromium/content/browser/geolocation/location_api_adapter_android.cc
+++ b/chromium/content/browser/geolocation/location_api_adapter_android.cc
@@ -151,7 +151,7 @@ bool AndroidLocationApiAdapter::RegisterGeolocationService(JNIEnv* env) {
}
void AndroidLocationApiAdapter::CreateJavaObject(JNIEnv* env) {
- // Create the Java AndroidLocationProvider object.
+ // Create the Java LocationProviderAdapter object.
java_location_provider_android_object_.Reset(
Java_LocationProviderAdapter_create(env,
base::android::GetApplicationContext()));
diff --git a/chromium/content/browser/geolocation/location_api_adapter_android.h b/chromium/content/browser/geolocation/location_api_adapter_android.h
index c58e26d6612..6e48109a090 100644
--- a/chromium/content/browser/geolocation/location_api_adapter_android.h
+++ b/chromium/content/browser/geolocation/location_api_adapter_android.h
@@ -19,18 +19,18 @@ namespace content {
class LocationProviderAndroid;
struct Geoposition;
-// Interacts with JNI and reports back to AndroidLocationProvider.
-// This class creates a LocationProvider java object and listens for
-// updates.
+// Interacts with JNI and reports back to LocationProviderAndroid. This class
+// creates a LocationProvider java object and listens for updates.
// The simplified flow is:
-// GeolocationProvider runs in a Geolocation Thread and fetches geolocation data
-// from a LocationProvider.
-// AndroidLocationProvider access a singleton AndroidLocationApiAdapter
-// AndroidLocationApiAdapter calls via JNI and uses the main thread Looper
-// in the java side to listen for location updates. We then bounce these updates
-// to the Geolocation thread.
+// - GeolocationProvider runs in a Geolocation Thread and fetches geolocation
+// data from a LocationProvider.
+// - LocationProviderAndroid accesses a singleton AndroidLocationApiAdapter.
+// - AndroidLocationApiAdapter calls via JNI and uses the main thread Looper
+// in the java side to listen for location updates. We then bounce these
+// updates to the Geolocation thread.
+//
// Note that AndroidLocationApiAdapter is a singleton and there's at most only
-// one AndroidLocationProvider that has called Start().
+// one LocationProviderAndroid that has called Start().
class AndroidLocationApiAdapter {
public:
// Starts the underlying location provider, returns true if successful.
@@ -71,7 +71,8 @@ class AndroidLocationApiAdapter {
base::android::ScopedJavaGlobalRef<jobject>
java_location_provider_android_object_;
- LocationProviderAndroid* location_provider_;
+ // TODO(mvanouwerkerk): Use a callback instead of holding a pointer.
+ LocationProviderAndroid* location_provider_; // Owned by the arbitrator.
// Guards against the following member which is accessed on Geolocation
// thread and the JNI main thread looper.
diff --git a/chromium/content/browser/geolocation/location_arbitrator.h b/chromium/content/browser/geolocation/location_arbitrator.h
index feb42e519dc..3f9c6326e22 100644
--- a/chromium/content/browser/geolocation/location_arbitrator.h
+++ b/chromium/content/browser/geolocation/location_arbitrator.h
@@ -17,7 +17,7 @@ public:
virtual ~LocationArbitrator() {};
// See more details in geolocation_provider.
- virtual void StartProviders(bool use_high_accuracy) = 0;
+ virtual void StartProviders(bool enable_high_accuracy) = 0;
virtual void StopProviders() = 0;
// Called everytime permission is granted to a page for using geolocation.
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.cc b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
index 03e3676f7e6..d6cb78b1657 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl.cc
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
@@ -47,13 +47,11 @@ GURL LocationArbitratorImpl::DefaultNetworkProviderURL() {
void LocationArbitratorImpl::OnPermissionGranted() {
is_permission_granted_ = true;
- for (ScopedVector<LocationProvider>::iterator i = providers_.begin();
- i != providers_.end(); ++i) {
- (*i)->OnPermissionGranted();
- }
+ for (const auto& provider : providers_)
+ provider->OnPermissionGranted();
}
-void LocationArbitratorImpl::StartProviders(bool use_high_accuracy) {
+void LocationArbitratorImpl::StartProviders(bool enable_high_accuracy) {
// GetAccessTokenStore() will return NULL for embedders not implementing
// the AccessTokenStore class, so we report an error to avoid JavaScript
// requests of location to wait eternally for a reply.
@@ -67,7 +65,7 @@ void LocationArbitratorImpl::StartProviders(bool use_high_accuracy) {
// Stash options as OnAccessTokenStoresLoaded has not yet been called.
is_running_ = true;
- use_high_accuracy_ = use_high_accuracy;
+ enable_high_accuracy_ = enable_high_accuracy;
if (providers_.empty()) {
DCHECK(DefaultNetworkProviderURL().is_valid());
access_token_store->LoadAccessTokens(
@@ -79,10 +77,8 @@ void LocationArbitratorImpl::StartProviders(bool use_high_accuracy) {
}
void LocationArbitratorImpl::DoStartProviders() {
- for (ScopedVector<LocationProvider>::iterator i = providers_.begin();
- i != providers_.end(); ++i) {
- (*i)->StartProvider(use_high_accuracy_);
- }
+ for (const auto& provider : providers_)
+ provider->StartProvider(enable_high_accuracy_);
}
void LocationArbitratorImpl::StopProviders() {
@@ -97,7 +93,7 @@ void LocationArbitratorImpl::StopProviders() {
}
void LocationArbitratorImpl::OnAccessTokenStoresLoaded(
- AccessTokenStore::AccessTokenSet access_token_set,
+ AccessTokenStore::AccessTokenMap access_token_map,
net::URLRequestContextGetter* context_getter) {
if (!is_running_ || !providers_.empty()) {
// A second StartProviders() call may have arrived before the first
@@ -105,15 +101,11 @@ void LocationArbitratorImpl::OnAccessTokenStoresLoaded(
return;
}
// If there are no access tokens, boot strap it with the default server URL.
- if (access_token_set.empty())
- access_token_set[DefaultNetworkProviderURL()];
- for (AccessTokenStore::AccessTokenSet::iterator i =
- access_token_set.begin();
- i != access_token_set.end(); ++i) {
- RegisterProvider(
- NewNetworkLocationProvider(
- GetAccessTokenStore(), context_getter,
- i->first, i->second));
+ if (access_token_map.empty())
+ access_token_map[DefaultNetworkProviderURL()];
+ for (const auto& entry : access_token_map) {
+ RegisterProvider(NewNetworkLocationProvider(
+ GetAccessTokenStore(), context_getter, entry.first, entry.second));
}
LocationProvider* provider =
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.h b/chromium/content/browser/geolocation/location_arbitrator_impl.h
index 65a55321022..60c9ac57a90 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl.h
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl.h
@@ -45,7 +45,7 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
static GURL DefaultNetworkProviderURL();
// LocationArbitrator
- void StartProviders(bool use_high_accuracy) override;
+ void StartProviders(bool enable_high_accuracy) override;
void StopProviders() override;
void OnPermissionGranted() override;
bool HasPermissionBeenGranted() const override;
@@ -69,7 +69,7 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
// |providers_| or deleted on error (e.g. it fails to start).
void RegisterProvider(LocationProvider* provider);
void OnAccessTokenStoresLoaded(
- AccessTokenStore::AccessTokenSet access_token_store,
+ AccessTokenStore::AccessTokenMap access_token_map,
net::URLRequestContextGetter* context_getter);
void DoStartProviders();
@@ -88,7 +88,7 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
LocationUpdateCallback arbitrator_update_callback_;
LocationProvider::LocationProviderUpdateCallback provider_update_callback_;
ScopedVector<LocationProvider> providers_;
- bool use_high_accuracy_;
+ bool enable_high_accuracy_;
// The provider which supplied the current |position_|
const LocationProvider* position_provider_;
bool is_permission_granted_;
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc b/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
index bd5eb6e9d07..0ca94b59f48 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
@@ -173,8 +173,8 @@ TEST_F(GeolocationLocationArbitratorTest, NormalUsage) {
EXPECT_FALSE(gps());
arbitrator_->StartProviders(false);
- EXPECT_TRUE(access_token_store_->access_token_set_.empty());
- EXPECT_TRUE(access_token_store_->access_token_set_.empty());
+ EXPECT_TRUE(access_token_store_->access_token_map_.empty());
+ EXPECT_TRUE(access_token_store_->access_token_map_.empty());
access_token_store_->NotifyDelegateTokensLoaded();
ASSERT_TRUE(cell());
diff --git a/chromium/content/browser/geolocation/mock_location_arbitrator.cc b/chromium/content/browser/geolocation/mock_location_arbitrator.cc
index 154fcae4bee..1ebef72974f 100644
--- a/chromium/content/browser/geolocation/mock_location_arbitrator.cc
+++ b/chromium/content/browser/geolocation/mock_location_arbitrator.cc
@@ -14,7 +14,7 @@ MockLocationArbitrator::MockLocationArbitrator()
providers_started_(false) {
}
-void MockLocationArbitrator::StartProviders(bool use_high_accuracy) {
+void MockLocationArbitrator::StartProviders(bool enable_high_accuracy) {
providers_started_ = true;
}
diff --git a/chromium/content/browser/geolocation/mock_location_arbitrator.h b/chromium/content/browser/geolocation/mock_location_arbitrator.h
index 31e66016b19..2ee057db201 100644
--- a/chromium/content/browser/geolocation/mock_location_arbitrator.h
+++ b/chromium/content/browser/geolocation/mock_location_arbitrator.h
@@ -20,7 +20,7 @@ class MockLocationArbitrator : public LocationArbitrator {
bool providers_started() const { return providers_started_; }
// LocationArbitrator:
- void StartProviders(bool use_high_accuracy) override;
+ void StartProviders(bool enable_high_accuracy) override;
void StopProviders() override;
void OnPermissionGranted() override;
bool HasPermissionBeenGranted() const override;
diff --git a/chromium/content/browser/geolocation/network_location_provider.cc b/chromium/content/browser/geolocation/network_location_provider.cc
index 5db43fa6784..01748610e38 100644
--- a/chromium/content/browser/geolocation/network_location_provider.cc
+++ b/chromium/content/browser/geolocation/network_location_provider.cc
@@ -81,12 +81,9 @@ bool NetworkLocationProvider::PositionCache::MakeKey(
const size_t kCharsPerMacAddress = 6 * 3 + 1; // e.g. "11:22:33:44:55:66|"
key->reserve(wifi_data.access_point_data.size() * kCharsPerMacAddress);
const base::string16 separator(base::ASCIIToUTF16("|"));
- for (WifiData::AccessPointDataSet::const_iterator iter =
- wifi_data.access_point_data.begin();
- iter != wifi_data.access_point_data.end();
- iter++) {
+ for (const auto& access_point_data : wifi_data.access_point_data) {
*key += separator;
- *key += iter->mac_address;
+ *key += access_point_data.mac_address;
*key += separator;
}
// If the key is the empty string, return false, as we don't want to cache a
@@ -215,7 +212,7 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
void NetworkLocationProvider::OnWifiDataUpdated() {
DCHECK(CalledOnValidThread());
- wifi_data_updated_timestamp_ = base::Time::Now();
+ wifi_timestamp_ = base::Time::Now();
is_new_data_available_ = is_wifi_data_complete_;
RequestRefresh();
@@ -238,8 +235,8 @@ void NetworkLocationProvider::RequestPosition() {
const Geoposition* cached_position =
position_cache_->FindPosition(wifi_data_);
- DCHECK(!wifi_data_updated_timestamp_.is_null()) <<
- "Timestamp must be set before looking up position";
+ DCHECK(!wifi_timestamp_.is_null())
+ << "Timestamp must be set before looking up position";
if (cached_position) {
DCHECK(cached_position->Validate());
// Record the position and update its timestamp.
@@ -247,7 +244,7 @@ void NetworkLocationProvider::RequestPosition() {
// The timestamp of a position fix is determined by the timestamp
// of the source data update. (The value of position_.timestamp from
// the cache could be from weeks ago!)
- position_.timestamp = wifi_data_updated_timestamp_;
+ position_.timestamp = wifi_timestamp_;
is_new_data_available_ = false;
// Let listeners know that we now have a position available.
NotifyCallback(position_);
@@ -267,8 +264,7 @@ void NetworkLocationProvider::RequestPosition() {
"with new data. Wifi APs: "
<< wifi_data_.access_point_data.size();
}
- request_->MakeRequest(access_token_, wifi_data_,
- wifi_data_updated_timestamp_);
+ request_->MakeRequest(access_token_, wifi_data_, wifi_timestamp_);
}
bool NetworkLocationProvider::IsStarted() const {
diff --git a/chromium/content/browser/geolocation/network_location_provider.h b/chromium/content/browser/geolocation/network_location_provider.h
index 69d891f2494..6c37a8cb16e 100644
--- a/chromium/content/browser/geolocation/network_location_provider.h
+++ b/chromium/content/browser/geolocation/network_location_provider.h
@@ -109,7 +109,7 @@ class NetworkLocationProvider
bool is_wifi_data_complete_;
// The timestamp for the latest wifi data update.
- base::Time wifi_data_updated_timestamp_;
+ base::Time wifi_timestamp_;
// Cached value loaded from the token store or set by a previous server
// response, and sent in each subsequent network request.
diff --git a/chromium/content/browser/geolocation/network_location_provider_unittest.cc b/chromium/content/browser/geolocation/network_location_provider_unittest.cc
index 724eb356427..0b09a39fa8f 100644
--- a/chromium/content/browser/geolocation/network_location_provider_unittest.cc
+++ b/chromium/content/browser/geolocation/network_location_provider_unittest.cc
@@ -126,7 +126,7 @@ class GeolocationNetworkProviderTest : public testing::Test {
access_token_store_.get(),
NULL, // No URLContextGetter needed, as using test urlfecther factory.
test_server_url_,
- access_token_store_->access_token_set_[test_server_url_]);
+ access_token_store_->access_token_map_[test_server_url_]);
if (set_permission_granted)
provider->OnPermissionGranted();
return provider;
@@ -415,7 +415,7 @@ TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) {
// Token should be in the store.
EXPECT_EQ(base::UTF8ToUTF16(REFERENCE_ACCESS_TOKEN),
- access_token_store_->access_token_set_[test_server_url_]);
+ access_token_store_->access_token_map_[test_server_url_]);
// Wifi updated again, with one less AP. This is 'close enough' to the
// previous scan, so no new request made.
@@ -508,7 +508,7 @@ TEST_F(GeolocationNetworkProviderTest, NetworkRequestDeferredForPermission) {
TEST_F(GeolocationNetworkProviderTest,
NetworkRequestWithWifiDataDeferredForPermission) {
- access_token_store_->access_token_set_[test_server_url_] =
+ access_token_store_->access_token_map_[test_server_url_] =
base::UTF8ToUTF16(REFERENCE_ACCESS_TOKEN);
scoped_ptr<LocationProvider> provider(CreateProvider(false));
EXPECT_TRUE(provider->StartProvider(false));
diff --git a/chromium/content/browser/geolocation/network_location_request.cc b/chromium/content/browser/geolocation/network_location_request.cc
index dd23daeeddd..7471c17160e 100644
--- a/chromium/content/browser/geolocation/network_location_request.cc
+++ b/chromium/content/browser/geolocation/network_location_request.cc
@@ -74,7 +74,7 @@ void RecordUmaAccessPoints(int count) {
GURL FormRequestURL(const GURL& url);
void FormUploadData(const WifiData& wifi_data,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
const base::string16& access_token,
std::string* upload_data);
@@ -83,7 +83,7 @@ void FormUploadData(const WifiData& wifi_data,
void GetLocationFromResponse(bool http_post_result,
int status_code,
const std::string& response_body,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
const GURL& server_url,
Geoposition* position,
base::string16* access_token);
@@ -92,7 +92,7 @@ void GetLocationFromResponse(bool http_post_result,
// Sets |*position| to the parsed location if a valid fix was received,
// otherwise leaves it unchanged.
bool ParseServerResponse(const std::string& response_body,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
Geoposition* position,
base::string16* access_token);
void AddWifiData(const WifiData& wifi_data,
@@ -114,7 +114,7 @@ NetworkLocationRequest::~NetworkLocationRequest() {
bool NetworkLocationRequest::MakeRequest(const base::string16& access_token,
const WifiData& wifi_data,
- const base::Time& timestamp) {
+ const base::Time& wifi_timestamp) {
RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_START);
RecordUmaAccessPoints(wifi_data.access_point_data.size());
if (url_fetcher_ != NULL) {
@@ -123,14 +123,14 @@ bool NetworkLocationRequest::MakeRequest(const base::string16& access_token,
url_fetcher_.reset();
}
wifi_data_ = wifi_data;
- wifi_data_timestamp_ = timestamp;
+ wifi_timestamp_ = wifi_timestamp;
GURL request_url = FormRequestURL(url_);
url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, request_url,
net::URLFetcher::POST, this);
url_fetcher_->SetRequestContext(url_context_.get());
std::string upload_data;
- FormUploadData(wifi_data, timestamp, access_token, &upload_data);
+ FormUploadData(wifi_data, wifi_timestamp, access_token, &upload_data);
url_fetcher_->SetUploadData("application/json", upload_data);
url_fetcher_->SetLoadFlags(
net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
@@ -154,12 +154,8 @@ void NetworkLocationRequest::OnURLFetchComplete(
base::string16 access_token;
std::string data;
source->GetResponseAsString(&data);
- GetLocationFromResponse(status.is_success(),
- response_code,
- data,
- wifi_data_timestamp_,
- source->GetURL(),
- &position,
+ GetLocationFromResponse(status.is_success(), response_code, data,
+ wifi_timestamp_, source->GetURL(), &position,
&access_token);
const bool server_error =
!status.is_success() || (response_code >= 500 && response_code < 600);
@@ -209,14 +205,14 @@ GURL FormRequestURL(const GURL& url) {
}
void FormUploadData(const WifiData& wifi_data,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
const base::string16& access_token,
std::string* upload_data) {
int age = std::numeric_limits<int32_t>::min(); // Invalid so AddInteger()
// will ignore.
- if (!timestamp.is_null()) {
+ if (!wifi_timestamp.is_null()) {
// Convert absolute timestamps into a relative age.
- int64_t delta_ms = (base::Time::Now() - timestamp).InMilliseconds();
+ int64_t delta_ms = (base::Time::Now() - wifi_timestamp).InMilliseconds();
if (delta_ms >= 0 && delta_ms < std::numeric_limits<int32_t>::max())
age = static_cast<int>(delta_ms);
}
@@ -253,24 +249,17 @@ void AddWifiData(const WifiData& wifi_data,
typedef std::multiset<const AccessPointData*, AccessPointLess> AccessPointSet;
AccessPointSet access_points_by_signal_strength;
- for (WifiData::AccessPointDataSet::const_iterator iter =
- wifi_data.access_point_data.begin();
- iter != wifi_data.access_point_data.end();
- ++iter) {
- access_points_by_signal_strength.insert(&(*iter));
- }
+ for (const auto& ap_data : wifi_data.access_point_data)
+ access_points_by_signal_strength.insert(&ap_data);
base::ListValue* wifi_access_point_list = new base::ListValue();
- for (AccessPointSet::iterator iter =
- access_points_by_signal_strength.begin();
- iter != access_points_by_signal_strength.end();
- ++iter) {
+ for (const auto& ap_data : access_points_by_signal_strength) {
base::DictionaryValue* wifi_dict = new base::DictionaryValue();
- AddString("macAddress", base::UTF16ToUTF8((*iter)->mac_address), wifi_dict);
- AddInteger("signalStrength", (*iter)->radio_signal_strength, wifi_dict);
+ AddString("macAddress", base::UTF16ToUTF8(ap_data->mac_address), wifi_dict);
+ AddInteger("signalStrength", ap_data->radio_signal_strength, wifi_dict);
AddInteger("age", age_milliseconds, wifi_dict);
- AddInteger("channel", (*iter)->channel, wifi_dict);
- AddInteger("signalToNoiseRatio", (*iter)->signal_to_noise, wifi_dict);
+ AddInteger("channel", ap_data->channel, wifi_dict);
+ AddInteger("signalToNoiseRatio", ap_data->signal_to_noise, wifi_dict);
wifi_access_point_list->Append(wifi_dict);
}
request->Set("wifiAccessPoints", wifi_access_point_list);
@@ -292,7 +281,7 @@ void FormatPositionError(const GURL& server_url,
void GetLocationFromResponse(bool http_post_result,
int status_code,
const std::string& response_body,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
const GURL& server_url,
Geoposition* position,
base::string16* access_token) {
@@ -315,7 +304,8 @@ void GetLocationFromResponse(bool http_post_result,
}
// We use the timestamp from the wifi data that was used to generate
// this position fix.
- if (!ParseServerResponse(response_body, timestamp, position, access_token)) {
+ if (!ParseServerResponse(response_body, wifi_timestamp, position,
+ access_token)) {
// We failed to parse the repsonse.
FormatPositionError(server_url, "Response was malformed", position);
RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED);
@@ -353,14 +343,14 @@ bool GetAsDouble(const base::DictionaryValue& object,
}
bool ParseServerResponse(const std::string& response_body,
- const base::Time& timestamp,
+ const base::Time& wifi_timestamp,
Geoposition* position,
base::string16* access_token) {
DCHECK(position);
DCHECK(!position->Validate());
DCHECK(position->error_code == Geoposition::ERROR_CODE_NONE);
DCHECK(access_token);
- DCHECK(!timestamp.is_null());
+ DCHECK(!wifi_timestamp.is_null());
if (response_body.empty()) {
LOG(WARNING) << "ParseServerResponse() : Response was empty.";
@@ -423,7 +413,7 @@ bool ParseServerResponse(const std::string& response_body,
// All error paths covered: now start actually modifying postion.
position->latitude = latitude;
position->longitude = longitude;
- position->timestamp = timestamp;
+ position->timestamp = wifi_timestamp;
// Other fields are optional.
GetAsDouble(*response_object, kAccuracyString, &position->accuracy);
diff --git a/chromium/content/browser/geolocation/network_location_request.h b/chromium/content/browser/geolocation/network_location_request.h
index fe15b72267d..6f7673af514 100644
--- a/chromium/content/browser/geolocation/network_location_request.h
+++ b/chromium/content/browser/geolocation/network_location_request.h
@@ -5,9 +5,11 @@
#ifndef CONTENT_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_
#define CONTENT_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
#include "content/browser/geolocation/wifi_data_provider.h"
#include "content/common/content_export.h"
#include "net/url_request/url_fetcher_delegate.h"
@@ -47,7 +49,7 @@ class NetworkLocationRequest : private net::URLFetcherDelegate {
// started. In all cases, any currently pending request will be canceled.
bool MakeRequest(const base::string16& access_token,
const WifiData& wifi_data,
- const base::Time& timestamp);
+ const base::Time& wifi_timestamp);
bool is_request_pending() const { return url_fetcher_ != NULL; }
const GURL& url() const { return url_; }
@@ -64,7 +66,7 @@ class NetworkLocationRequest : private net::URLFetcherDelegate {
// Keep a copy of the data sent in the request, so we can refer back to it
// when the response arrives.
WifiData wifi_data_;
- base::Time wifi_data_timestamp_;
+ base::Time wifi_timestamp_;
// The start time for the request.
base::TimeTicks request_start_time_;
diff --git a/chromium/content/browser/geolocation/wifi_data.cc b/chromium/content/browser/geolocation/wifi_data.cc
index 2f41c33ee48..d82e6f442f0 100644
--- a/chromium/content/browser/geolocation/wifi_data.cc
+++ b/chromium/content/browser/geolocation/wifi_data.cc
@@ -23,6 +23,8 @@ AccessPointData::~AccessPointData() {}
WifiData::WifiData() {}
+WifiData::WifiData(const WifiData& other) = default;
+
WifiData::~WifiData() {}
bool WifiData::DiffersSignificantly(const WifiData& other) const {
diff --git a/chromium/content/browser/geolocation/wifi_data.h b/chromium/content/browser/geolocation/wifi_data.h
index d6e0b33ab4e..b3cf569bb71 100644
--- a/chromium/content/browser/geolocation/wifi_data.h
+++ b/chromium/content/browser/geolocation/wifi_data.h
@@ -37,6 +37,7 @@ struct AccessPointDataLess {
// All data for wifi.
struct CONTENT_EXPORT WifiData {
WifiData();
+ WifiData(const WifiData& other);
~WifiData();
// Determines whether a new set of WiFi data differs significantly from this.
diff --git a/chromium/content/browser/geolocation/wifi_data_provider.cc b/chromium/content/browser/geolocation/wifi_data_provider.cc
index 71b78c4765e..433572c99fc 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider.cc
@@ -4,11 +4,16 @@
#include "content/browser/geolocation/wifi_data_provider.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+
namespace content {
WifiDataProvider::WifiDataProvider()
- : client_loop_(base::MessageLoop::current()) {
- DCHECK(client_loop_);
+ : client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ DCHECK(client_task_runner_);
}
WifiDataProvider::~WifiDataProvider() {
@@ -27,16 +32,12 @@ bool WifiDataProvider::has_callbacks() const {
}
void WifiDataProvider::RunCallbacks() {
- client_loop_->task_runner()->PostTask(
+ client_task_runner_->PostTask(
FROM_HERE, base::Bind(&WifiDataProvider::DoRunCallbacks, this));
}
bool WifiDataProvider::CalledOnClientThread() const {
- return base::MessageLoop::current() == this->client_loop_;
-}
-
-base::MessageLoop* WifiDataProvider::client_loop() const {
- return client_loop_;
+ return client_task_runner()->BelongsToCurrentThread();
}
void WifiDataProvider::DoRunCallbacks() {
diff --git a/chromium/content/browser/geolocation/wifi_data_provider.h b/chromium/content/browser/geolocation/wifi_data_provider.h
index 96ab8817b8a..ce514969d55 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider.h
@@ -7,13 +7,10 @@
#include <set>
-#include "base/bind.h"
-#include "base/callback.h"
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
+#include "base/single_thread_task_runner.h"
#include "content/browser/geolocation/wifi_data.h"
#include "content/common/content_export.h"
@@ -57,14 +54,15 @@ class CONTENT_EXPORT WifiDataProvider
bool CalledOnClientThread() const;
- base::MessageLoop* client_loop() const;
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner() const {
+ return client_task_runner_;
+ }
private:
void DoRunCallbacks();
- // Reference to the client's message loop. All callbacks should happen in this
- // context.
- base::MessageLoop* client_loop_;
+ // The task runner for the client thread, all callbacks should run on it.
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
CallbackSet callbacks_;
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
index 6060ec1bdbb..4f148667f63 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
@@ -75,11 +75,11 @@ void WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread() {
WifiData new_data;
if (GetAccessPointData(&new_data.access_point_data)) {
- client_loop()->PostTask(
+ client_task_runner()->PostTask(
FROM_HERE,
base::Bind(&WifiDataProviderChromeOs::DidWifiScanTask, this, new_data));
} else {
- client_loop()->PostTask(
+ client_task_runner()->PostTask(
FROM_HERE,
base::Bind(&WifiDataProviderChromeOs::DidWifiScanTaskNoResults, this));
}
@@ -151,15 +151,13 @@ bool WifiDataProviderChromeOs::GetAccessPointData(
GetWifiAccessPoints(&access_points, &age_ms)) {
return false;
}
- for (chromeos::WifiAccessPointVector::const_iterator i
- = access_points.begin();
- i != access_points.end(); ++i) {
+ for (const auto& access_point : access_points) {
AccessPointData ap_data;
- ap_data.mac_address = base::ASCIIToUTF16(i->mac_address);
- ap_data.radio_signal_strength = i->signal_strength;
- ap_data.channel = i->channel;
- ap_data.signal_to_noise = i->signal_to_noise;
- ap_data.ssid = base::UTF8ToUTF16(i->ssid);
+ ap_data.mac_address = base::ASCIIToUTF16(access_point.mac_address);
+ ap_data.radio_signal_strength = access_point.signal_strength;
+ ap_data.channel = access_point.channel;
+ ap_data.signal_to_noise = access_point.signal_to_noise;
+ ap_data.ssid = base::UTF8ToUTF16(access_point.ssid);
result->insert(ap_data);
}
// If the age is significantly longer than our long polling time, assume the
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
index e901f0131f8..c5055dc6d49 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "content/browser/geolocation/wifi_data_provider.h"
#include "content/browser/geolocation/wifi_polling_policy.h"
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc b/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
index a5d1744ba00..64bce2732f6 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -10,6 +10,7 @@
#include "chromeos/dbus/shill_manager_client.h"
#include "chromeos/network/geolocation_handler.h"
#include "content/browser/geolocation/wifi_data_provider_chromeos.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
@@ -27,7 +28,7 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
chromeos::DBusThreadManager::Get()->GetShillManagerClient();
manager_test_ = manager_client_->GetTestInterface();
provider_ = new WifiDataProviderChromeOs();
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void TearDown() override {
@@ -58,10 +59,10 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
manager_test_->AddGeoNetwork(shill::kTypeWifi, properties);
}
}
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
- base::MessageLoopForUI message_loop_;
+ TestBrowserThreadBundle thread_bundle_;
scoped_refptr<WifiDataProviderChromeOs> provider_;
chromeos::ShillManagerClient* manager_client_;
chromeos::ShillManagerClient::TestInterface* manager_test_;
@@ -69,17 +70,17 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
};
TEST_F(GeolocationChromeOsWifiDataProviderTest, NoAccessPoints) {
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Initial call to GetAccessPointData requests data and will return false.
EXPECT_FALSE(GetAccessPointData());
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Additional call to GetAccessPointData also returns false with no devices.
EXPECT_FALSE(GetAccessPointData());
EXPECT_EQ(0u, ap_data_.size());
}
TEST_F(GeolocationChromeOsWifiDataProviderTest, GetOneAccessPoint) {
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetAccessPointData());
AddAccessPoints(1, 1);
@@ -90,7 +91,7 @@ TEST_F(GeolocationChromeOsWifiDataProviderTest, GetOneAccessPoint) {
}
TEST_F(GeolocationChromeOsWifiDataProviderTest, GetManyAccessPoints) {
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetAccessPointData());
AddAccessPoints(3, 4);
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_common.cc b/chromium/content/browser/geolocation/wifi_data_provider_common.cc
index 4406680c215..572455a6c4f 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_common.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_common.cc
@@ -82,7 +82,7 @@ void WifiDataProviderCommon::DoWifiScanTask() {
}
void WifiDataProviderCommon::ScheduleNextScan(int interval) {
- client_loop()->task_runner()->PostDelayedTask(
+ client_task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&WifiDataProviderCommon::DoWifiScanTask,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(interval));
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc b/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc
index b6521703872..8acf93a9d04 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <vector>
-
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_util.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "build/build_config.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/geolocation/wifi_data_provider_common.h"
#include "content/browser/geolocation/wifi_data_provider_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -60,25 +60,6 @@ class MockPollingPolicy : public WifiPollingPolicy {
virtual void UpdatePollingInterval(bool) {}
};
-// Stops the specified (nested) message loop when the callback is called.
-class MessageLoopQuitter {
- public:
- explicit MessageLoopQuitter(base::MessageLoop* message_loop)
- : message_loop_to_quit_(message_loop),
- callback_(base::Bind(&MessageLoopQuitter::OnWifiDataUpdate,
- base::Unretained(this))) {
- CHECK(message_loop_to_quit_ != NULL);
- }
-
- void OnWifiDataUpdate() {
- // Provider should call back on client's thread.
- EXPECT_EQ(base::MessageLoop::current(), message_loop_to_quit_);
- message_loop_to_quit_->QuitNow();
- }
- base::MessageLoop* message_loop_to_quit_;
- WifiDataProviderManager::WifiDataUpdateCallback callback_;
-};
-
class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
public:
WifiDataProviderCommonWithMock()
@@ -112,24 +93,40 @@ WifiDataProvider* CreateWifiDataProviderCommonWithMock() {
class GeolocationWifiDataProviderCommonTest : public testing::Test {
public:
GeolocationWifiDataProviderCommonTest()
- : loop_quitter_(&main_message_loop_) {
- }
+ : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ wifi_data_callback_(
+ base::Bind(&GeolocationWifiDataProviderCommonTest::OnWifiDataUpdate,
+ base::Unretained(this))) {}
void SetUp() override {
provider_ = new WifiDataProviderCommonWithMock;
wlan_api_ = provider_->new_wlan_api_.get();
polling_policy_ = provider_->new_polling_policy_.get();
- provider_->AddCallback(&loop_quitter_.callback_);
+ provider_->AddCallback(&wifi_data_callback_);
}
+
void TearDown() override {
- provider_->RemoveCallback(&loop_quitter_.callback_);
+ provider_->RemoveCallback(&wifi_data_callback_);
provider_->StopDataProvider();
provider_ = NULL;
}
+ void OnWifiDataUpdate() {
+ // Callbacks must run on the originating thread.
+ EXPECT_TRUE(main_task_runner_->BelongsToCurrentThread());
+ run_loop_->Quit();
+ }
+
+ void RunLoop() {
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
+ }
+
protected:
- base::MessageLoop main_message_loop_;
- MessageLoopQuitter loop_quitter_;
+ TestBrowserThreadBundle thread_bundle_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_ptr<base::RunLoop> run_loop_;
+ WifiDataProviderManager::WifiDataUpdateCallback wifi_data_callback_;
scoped_refptr<WifiDataProviderCommonWithMock> provider_;
MockWlanApi* wlan_api_;
MockPollingPolicy* polling_policy_;
@@ -137,7 +134,7 @@ class GeolocationWifiDataProviderCommonTest : public testing::Test {
TEST_F(GeolocationWifiDataProviderCommonTest, CreateDestroy) {
// Test fixture members were SetUp correctly.
- EXPECT_EQ(&main_message_loop_, base::MessageLoop::current());
+ EXPECT_TRUE(main_task_runner_->BelongsToCurrentThread());
EXPECT_TRUE(NULL != provider_.get());
EXPECT_TRUE(NULL != wlan_api_);
}
@@ -148,20 +145,20 @@ TEST_F(GeolocationWifiDataProviderCommonTest, RunNormal) {
EXPECT_CALL(*polling_policy_, PollingInterval())
.Times(AtLeast(1));
provider_->StartDataProvider();
- main_message_loop_.Run();
+ RunLoop();
SUCCEED();
}
-TEST_F(GeolocationWifiDataProviderCommonTest, NoWifi){
+TEST_F(GeolocationWifiDataProviderCommonTest, NoWifi) {
EXPECT_CALL(*polling_policy_, NoWifiInterval())
.Times(AtLeast(1));
EXPECT_CALL(*wlan_api_, GetAccessPointData(_))
.WillRepeatedly(Return(false));
provider_->StartDataProvider();
- main_message_loop_.Run();
+ RunLoop();
}
-TEST_F(GeolocationWifiDataProviderCommonTest, IntermittentWifi){
+TEST_F(GeolocationWifiDataProviderCommonTest, IntermittentWifi) {
EXPECT_CALL(*polling_policy_, PollingInterval())
.Times(AtLeast(1));
EXPECT_CALL(*polling_policy_, NoWifiInterval())
@@ -180,8 +177,8 @@ TEST_F(GeolocationWifiDataProviderCommonTest, IntermittentWifi){
wlan_api_->data_out_.insert(single_access_point);
provider_->StartDataProvider();
- main_message_loop_.Run();
- main_message_loop_.Run();
+ RunLoop();
+ RunLoop();
}
#if defined(OS_MACOSX)
@@ -195,7 +192,7 @@ TEST_F(GeolocationWifiDataProviderCommonTest, MAYBE_DoAnEmptyScan) {
EXPECT_CALL(*polling_policy_, PollingInterval())
.Times(AtLeast(1));
provider_->StartDataProvider();
- main_message_loop_.Run();
+ RunLoop();
EXPECT_EQ(wlan_api_->calls_, 1);
WifiData data;
EXPECT_TRUE(provider_->GetData(&data));
@@ -221,7 +218,7 @@ TEST_F(GeolocationWifiDataProviderCommonTest, MAYBE_DoScanWithResults) {
wlan_api_->data_out_.insert(single_access_point);
provider_->StartDataProvider();
- main_message_loop_.Run();
+ RunLoop();
EXPECT_EQ(wlan_api_->calls_, 1);
WifiData data;
EXPECT_TRUE(provider_->GetData(&data));
@@ -230,12 +227,11 @@ TEST_F(GeolocationWifiDataProviderCommonTest, MAYBE_DoScanWithResults) {
}
TEST_F(GeolocationWifiDataProviderCommonTest, RegisterUnregister) {
- MessageLoopQuitter loop_quitter(&main_message_loop_);
WifiDataProviderManager::SetFactoryForTesting(
CreateWifiDataProviderCommonWithMock);
- WifiDataProviderManager::Register(&loop_quitter.callback_);
- main_message_loop_.Run();
- WifiDataProviderManager::Unregister(&loop_quitter.callback_);
+ WifiDataProviderManager::Register(&wifi_data_callback_);
+ RunLoop();
+ WifiDataProviderManager::Unregister(&wifi_data_callback_);
WifiDataProviderManager::ResetFactoryForTesting();
}
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm b/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
index 036c7610b43..bbe099f3d2f 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
+++ b/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
@@ -39,6 +39,7 @@
@property (nonatomic, readonly) NSNumber* phyMode;
@property (nonatomic, readonly) NSNumber* channel;
@property (nonatomic, readonly) NSNumber* rssi;
+@property (nonatomic, readonly) NSInteger rssiValue;
@property (nonatomic, readonly) NSNumber* noise;
@property (nonatomic, readonly) NSData* ieData;
@property (nonatomic, readonly) BOOL isIBSS;
@@ -158,7 +159,7 @@ bool CoreWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
continue; // crbug.com/545501
access_point_data.mac_address =
MacAddressAsString16(static_cast<const uint8_t*>([mac bytes]));
- access_point_data.radio_signal_strength = [[network rssi] intValue];
+ access_point_data.radio_signal_strength = [network rssiValue];
access_point_data.channel = [[network channel] intValue];
access_point_data.signal_to_noise =
access_point_data.radio_signal_strength - [[network noise] intValue];
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc b/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc
index 3ca35d114b4..7f36a2c25a4 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_object_proxy.h"
@@ -105,10 +105,9 @@ class GeolocationWifiDataProviderLinuxTest : public testing::Test {
}
protected:
- // DeviceDataProviderImplBase, a super class of WifiDataProviderLinux,
- // requires a message loop to be present. message_loop_ is defined here,
- // as it should outlive wifi_provider_linux_.
- base::MessageLoop message_loop_;
+ // WifiDataProvider requires a task runner to be present. The |thread_bundle_|
+ // is defined here, as it should outlive |wifi_provider_linux_|.
+ TestBrowserThreadBundle thread_bundle_;
scoped_refptr<dbus::MockBus> mock_bus_;
scoped_refptr<dbus::MockObjectProxy> mock_network_manager_proxy_;
scoped_refptr<dbus::MockObjectProxy> mock_access_point_proxy_;
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_manager.h b/chromium/content/browser/geolocation/wifi_data_provider_manager.h
index bb2af81e167..652cf643710 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_manager.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_manager.h
@@ -21,7 +21,6 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "content/browser/geolocation/wifi_data.h"
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win.cc b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
index 4d950ec12fc..7d9db588cd1 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
@@ -27,6 +27,7 @@
#include <winioctl.h>
#include <wlanapi.h>
+#include "base/memory/free_deleter.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc b/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc
index cb3c21ce3ec..d256a4a3fcb 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc
@@ -6,13 +6,14 @@
// WifiDataProviderCommon and covered by it's unit tests.
#include "content/browser/geolocation/wifi_data_provider_win.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
TEST(GeolocationWifiDataProviderWinTest, CreateDestroy) {
- // WifiDataProviderCommon requires the client to have a message loop.
- base::MessageLoop dummy_loop;
+ // WifiDataProvider requires a task runner to be present.
+ TestBrowserThreadBundle thread_bundle;
scoped_refptr<WifiDataProviderWin> instance(new WifiDataProviderWin);
instance = NULL;
SUCCEED();
diff --git a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
index f432608fb27..61082162286 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -18,15 +18,14 @@
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
-#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/gpu/shader_disk_cache.h"
#include "content/common/child_process_host_impl.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_client.h"
#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/message_filter.h"
@@ -34,19 +33,6 @@ namespace content {
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
-struct BrowserGpuChannelHostFactory::CreateRequest {
- CreateRequest(int32_t route_id)
- : event(true, false),
- gpu_host_id(0),
- route_id(route_id),
- result(CREATE_COMMAND_BUFFER_FAILED) {}
- ~CreateRequest() {}
- base::WaitableEvent event;
- int gpu_host_id;
- int32_t route_id;
- CreateCommandBufferResult result;
-};
-
class BrowserGpuChannelHostFactory::EstablishRequest
: public base::RefCountedThreadSafe<EstablishRequest> {
public:
@@ -150,12 +136,11 @@ void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
}
bool preempts = true;
- bool preempted = false;
- bool allow_future_sync_points = true;
+ bool allow_view_command_buffers = true;
bool allow_real_time_streams = true;
host->EstablishGpuChannel(
- gpu_client_id_, gpu_client_tracing_id_, preempts, preempted,
- allow_future_sync_points, allow_real_time_streams,
+ gpu_client_id_, gpu_client_tracing_id_, preempts,
+ allow_view_command_buffers, allow_real_time_streams,
base::Bind(
&BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
this));
@@ -291,65 +276,11 @@ BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
return shm;
}
-void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
- CreateRequest* request,
- int32_t surface_id,
- const GPUCreateCommandBufferConfig& init_params) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- request->event.Signal();
- return;
- }
-
- gfx::GLSurfaceHandle surface =
- GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
-
- host->CreateViewCommandBuffer(
- surface,
- gpu_client_id_,
- init_params,
- request->route_id,
- base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
- request));
-}
-
-// static
-void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
- CreateRequest* request, CreateCommandBufferResult result) {
- request->result = result;
- request->event.Signal();
-}
-
-CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
- int32_t surface_id,
- const GPUCreateCommandBufferConfig& init_params,
- int32_t route_id) {
- CreateRequest request(route_id);
- GetIOThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
- base::Unretained(this), &request, surface_id, init_params));
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
-
- // We're blocking the UI thread, which is generally undesirable.
- // In this case we need to wait for this before we can show any UI /anyway/,
- // so it won't cause additional jank.
- // TODO(piman): Make this asynchronous (http://crbug.com/125248).
- TRACE_EVENT0("browser",
- "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- request.event.Wait();
- return request.result;
-}
-
// Blocking the UI thread to open a GPU channel is not supported on Android.
// (Opening the initial channel to a child process involves handling a reply
// task on the UI thread first, so we cannot block here.)
#if !defined(OS_ANDROID)
-GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
+gpu::GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch) {
EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
@@ -386,7 +317,7 @@ void BrowserGpuChannelHostFactory::EstablishGpuChannel(
}
}
-GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
+gpu::GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
if (gpu_channel_.get() && !gpu_channel_->IsLost())
return gpu_channel_.get();
@@ -405,7 +336,7 @@ void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
- gpu_channel_ = GpuChannelHost::Create(
+ gpu_channel_ = gpu::GpuChannelHost::Create(
this, gpu_client_id_, pending_request_->gpu_info(),
pending_request_->channel_handle(), shutdown_event_.get(),
gpu_memory_buffer_manager_.get());
diff --git a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
index 530768c44b4..618e1c23d47 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -15,36 +15,34 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/content_export.h"
+#include "content/common/gpu_process_launch_causes.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
#include "ipc/message_filter.h"
namespace content {
class BrowserGpuMemoryBufferManager;
class CONTENT_EXPORT BrowserGpuChannelHostFactory
- : public GpuChannelHostFactory {
+ : public gpu::GpuChannelHostFactory {
public:
static void Initialize(bool establish_gpu_channel);
static void Terminate();
static BrowserGpuChannelHostFactory* instance() { return instance_; }
- // Overridden from GpuChannelHostFactory:
+ // Overridden from gpu::GpuChannelHostFactory:
bool IsMainThread() override;
scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
- CreateCommandBufferResult CreateViewCommandBuffer(
- int32_t surface_id,
- const GPUCreateCommandBufferConfig& init_params,
- int32_t route_id) override;
int GpuProcessHostId() { return gpu_host_id_; }
#if !defined(OS_ANDROID)
- GpuChannelHost* EstablishGpuChannelSync(
+ gpu::GpuChannelHost* EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch);
#endif
void EstablishGpuChannel(CauseForGpuLaunch cause_for_gpu_launch,
const base::Closure& callback);
- GpuChannelHost* GetGpuChannel();
+ gpu::GpuChannelHost* GetGpuChannel();
int GetGpuChannelId() { return gpu_client_id_; }
// Used to skip GpuChannelHost tests when there can be no GPU process.
@@ -58,12 +56,7 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
~BrowserGpuChannelHostFactory() override;
void GpuChannelEstablished();
- void CreateViewCommandBufferOnIO(
- CreateRequest* request,
- int32_t surface_id,
- const GPUCreateCommandBufferConfig& init_params);
- static void CommandBufferCreatedOnIO(CreateRequest* request,
- CreateCommandBufferResult result);
+
static void AddFilterOnIO(int gpu_host_id,
scoped_refptr<IPC::MessageFilter> filter);
static void InitializeShaderDiskCacheOnIO(int gpu_client_id,
@@ -72,7 +65,7 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
const int gpu_client_id_;
const uint64_t gpu_client_tracing_id_;
scoped_ptr<base::WaitableEvent> shutdown_event_;
- scoped_refptr<GpuChannelHost> gpu_channel_;
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
int gpu_host_id_;
scoped_refptr<EstablishRequest> pending_request_;
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index d9c25c9344b..7eba55f7457 100644
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -17,27 +17,15 @@
#include "content/browser/gpu/gpu_process_host.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/generic_shared_memory_id_generator.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
-#include "content/common/gpu/gpu_memory_buffer_factory.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/ipc/client/gpu_memory_buffer_impl.h"
+#include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h"
+#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gl/gl_switches.h"
-#if defined(OS_MACOSX)
-#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
-#endif
-
-#if defined(OS_ANDROID)
-#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
-#endif
-
-#if defined(USE_OZONE)
-#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h"
-#endif
-
namespace content {
namespace {
@@ -69,7 +57,7 @@ void HostCreateGpuMemoryBufferFromHandle(
void GpuMemoryBufferDeleted(
scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner,
- const GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
+ const gpu::GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
const gpu::SyncToken& sync_token) {
destruction_task_runner->PostTask(
FROM_HERE, base::Bind(destruction_callback, sync_token));
@@ -78,24 +66,13 @@ void GpuMemoryBufferDeleted(
bool IsNativeGpuMemoryBufferFactoryConfigurationSupported(
gfx::BufferFormat format,
gfx::BufferUsage usage) {
- switch (GpuMemoryBufferFactory::GetNativeType()) {
+ switch (gpu::GetNativeGpuMemoryBufferType()) {
case gfx::SHARED_MEMORY_BUFFER:
return false;
-#if defined(OS_MACOSX)
case gfx::IO_SURFACE_BUFFER:
- return GpuMemoryBufferFactoryIOSurface::
- IsGpuMemoryBufferConfigurationSupported(format, usage);
-#endif
-#if defined(OS_ANDROID)
case gfx::SURFACE_TEXTURE_BUFFER:
- return GpuMemoryBufferFactorySurfaceTexture::
- IsGpuMemoryBufferConfigurationSupported(format, usage);
-#endif
-#if defined(USE_OZONE)
case gfx::OZONE_NATIVE_PIXMAP:
- return GpuMemoryBufferFactoryOzoneNativePixmap::
- IsGpuMemoryBufferConfigurationSupported(format, usage);
-#endif
+ return gpu::IsNativeGpuMemoryBufferConfigurationSupported(format, usage);
default:
NOTREACHED();
return false;
@@ -239,7 +216,7 @@ uint32_t BrowserGpuMemoryBufferManager::GetImageTextureTarget(
return GL_TEXTURE_2D;
}
- switch (GpuMemoryBufferFactory::GetNativeType()) {
+ switch (gpu::GetNativeGpuMemoryBufferType()) {
case gfx::SURFACE_TEXTURE_BUFFER:
case gfx::OZONE_NATIVE_PIXMAP:
// GPU memory buffers that are shared with the GL using EGLImages
@@ -262,8 +239,9 @@ uint32_t BrowserGpuMemoryBufferManager::GetImageTextureTarget(
scoped_ptr<gfx::GpuMemoryBuffer>
BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(const gfx::Size& size,
gfx::BufferFormat format,
- gfx::BufferUsage usage) {
- return AllocateGpuMemoryBufferForSurface(size, format, usage, 0);
+ gfx::BufferUsage usage,
+ int32_t surface_id) {
+ return AllocateGpuMemoryBufferForSurface(size, format, usage, surface_id);
}
scoped_ptr<gfx::GpuMemoryBuffer>
@@ -291,16 +269,6 @@ BrowserGpuMemoryBufferManager::CreateGpuMemoryBufferFromHandle(
return std::move(request.result);
}
-scoped_ptr<gfx::GpuMemoryBuffer>
-BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
- const gfx::Size& size,
- gfx::BufferFormat format,
- int32_t surface_id) {
- DCHECK_GT(surface_id, 0);
- return AllocateGpuMemoryBufferForSurface(
- size, format, gfx::BufferUsage::SCANOUT, surface_id);
-}
-
void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
@@ -320,8 +288,9 @@ void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
}
// Early out if we cannot fallback to shared memory buffer.
- if (!GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
- !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) {
+ if (!gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
+ !gpu::GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size,
+ format)) {
callback.Run(gfx::GpuMemoryBufferHandle());
return;
}
@@ -338,21 +307,21 @@ void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
return;
}
- callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
+ callback.Run(gpu::GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
id, size, format, child_process_handle));
}
gfx::GpuMemoryBuffer*
BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
ClientBuffer buffer) {
- return GpuMemoryBufferImpl::FromClientBuffer(buffer);
+ return gpu::GpuMemoryBufferImpl::FromClientBuffer(buffer);
}
void BrowserGpuMemoryBufferManager::SetDestructionSyncToken(
gfx::GpuMemoryBuffer* buffer,
const gpu::SyncToken& sync_token) {
- static_cast<GpuMemoryBufferImpl*>(buffer)
- ->set_destruction_sync_token(sync_token);
+ static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token(
+ sync_token);
}
bool BrowserGpuMemoryBufferManager::OnMemoryDump(
@@ -485,7 +454,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferOnIO(
return;
}
- DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
+ DCHECK(gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
<< static_cast<int>(request->usage);
BufferMap& buffers = clients_[request->client_id];
@@ -498,7 +467,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferOnIO(
// Note: Unretained is safe as IO thread is stopped before manager is
// destroyed.
- request->result = GpuMemoryBufferImplSharedMemory::Create(
+ request->result = gpu::GpuMemoryBufferImplSharedMemory::Create(
new_id, request->size, request->format,
base::Bind(
&GpuMemoryBufferDeleted,
@@ -517,7 +486,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferFromHandleOnIO(
// Use service side allocation for native types.
if (request->handle.type != gfx::SHARED_MEMORY_BUFFER) {
// Early out if service side allocation is not supported.
- if (request->handle.type != GpuMemoryBufferFactory::GetNativeType() ||
+ if (request->handle.type != gpu::GetNativeGpuMemoryBufferType() ||
!IsNativeGpuMemoryBufferConfiguration(request->format,
request->usage)) {
request->event.Signal();
@@ -535,7 +504,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferFromHandleOnIO(
return;
}
- DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
+ DCHECK(gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
<< static_cast<int>(request->usage);
BufferMap& buffers = clients_[request->client_id];
@@ -554,7 +523,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferFromHandleOnIO(
// Note: Unretained is safe as IO thread is stopped before manager is
// destroyed.
- request->result = GpuMemoryBufferImplSharedMemory::CreateFromHandle(
+ request->result = gpu::GpuMemoryBufferImplSharedMemory::CreateFromHandle(
handle, request->size, request->format, request->usage,
base::Bind(
&GpuMemoryBufferDeleted,
@@ -577,7 +546,7 @@ void BrowserGpuMemoryBufferManager::HandleGpuMemoryBufferCreatedOnIO(
// Note: Unretained is safe as IO thread is stopped before manager is
// destroyed.
- request->result = GpuMemoryBufferImpl::CreateFromHandle(
+ request->result = gpu::GpuMemoryBufferImpl::CreateFromHandle(
handle, request->size, request->format, request->usage,
base::Bind(
&GpuMemoryBufferDeleted,
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
index 0057192b65b..946ccf0e505 100644
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/containers/hash_tables.h"
+#include "base/hash.h"
#include "base/macros.h"
#include "base/trace_event/memory_dump_provider.h"
#include "content/common/content_export.h"
@@ -31,7 +32,7 @@ namespace BASE_HASH_NAMESPACE {
template <>
struct hash<content::GpuMemoryBufferConfigurationKey> {
size_t operator()(const content::GpuMemoryBufferConfigurationKey& key) const {
- return base::HashPair(static_cast<int>(key.first),
+ return base::HashInts(static_cast<int>(key.first),
static_cast<int>(key.second));
}
};
@@ -64,7 +65,8 @@ class CONTENT_EXPORT BrowserGpuMemoryBufferManager
scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
- gfx::BufferUsage usage) override;
+ gfx::BufferUsage usage,
+ int32_t surface_id) override;
scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBufferFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
@@ -78,12 +80,6 @@ class CONTENT_EXPORT BrowserGpuMemoryBufferManager
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
- // Virtual for testing.
- virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
- const gfx::Size& size,
- gfx::BufferFormat format,
- int32_t surface_id);
-
void AllocateGpuMemoryBufferForChildProcess(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
diff --git a/chromium/content/browser/gpu/compositor_util.cc b/chromium/content/browser/gpu/compositor_util.cc
index d7b3e40928e..a7960b35b74 100644
--- a/chromium/content/browser/gpu/compositor_util.cc
+++ b/chromium/content/browser/gpu/compositor_util.cc
@@ -34,6 +34,7 @@ const char* kGpuCompositingFeatureName = "gpu_compositing";
const char* kWebGLFeatureName = "webgl";
const char* kRasterizationFeatureName = "rasterization";
const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";
+const char* kNativeGpuMemoryBuffersFeatureName = "native_gpu_memory_buffers";
const int kMinRasterThreads = 1;
const int kMaxRasterThreads = 4;
@@ -154,6 +155,14 @@ const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
"Raster is using a single thread.",
false
},
+ {
+ kNativeGpuMemoryBuffersFeatureName,
+ false,
+ !BrowserGpuMemoryBufferManager::IsNativeGpuMemoryBuffersEnabled(),
+ "Native GpuMemoryBuffers have been disabled, either via about:flags"
+ " or command line.",
+ true
+ },
};
DCHECK(index < arraysize(kGpuFeatureInfo));
*eof = (index == arraysize(kGpuFeatureInfo) - 1);
@@ -162,12 +171,6 @@ const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
} // namespace
-bool IsPropertyTreeVerificationEnabled() {
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- return command_line.HasSwitch(cc::switches::kEnablePropertyTreeVerification);
-}
-
int NumberOfRendererRasterThreads() {
int num_processors = base::SysInfo::NumberOfProcessors();
@@ -216,8 +219,9 @@ bool IsPartialRasterEnabled() {
// Zero copy currently doesn't take advantage of partial raster.
if (IsZeroCopyUploadEnabled())
return false;
+
const auto& command_line = *base::CommandLine::ForCurrentProcess();
- return command_line.HasSwitch(switches::kEnablePartialRaster);
+ return !command_line.HasSwitch(switches::kDisablePartialRaster);
}
bool IsGpuMemoryBufferCompositorResourcesEnabled() {
@@ -236,12 +240,6 @@ bool IsGpuMemoryBufferCompositorResourcesEnabled() {
if (!BrowserGpuMemoryBufferManager::IsNativeGpuMemoryBuffersEnabled())
return false;
- // GPU rasterization does not support GL_TEXTURE_RECTANGLE_ARB, which is
- // required by GpuMemoryBuffers on Mac.
- // http://crbug.com/551072
- if (IsForceGpuRasterizationEnabled() || IsGpuRasterizationEnabled())
- return false;
-
#if defined(OS_MACOSX)
return true;
#else
@@ -277,24 +275,6 @@ bool IsForceGpuRasterizationEnabled() {
return command_line.HasSwitch(switches::kForceGpuRasterization);
}
-bool UseSurfacesEnabled() {
-#if defined(OS_ANDROID)
- return true;
-#endif
- bool enabled = false;
-#if defined(USE_AURA) || defined(OS_MACOSX)
- enabled = true;
-#endif
-
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
-
- // Flags override.
- enabled |= command_line.HasSwitch(switches::kUseSurfaces);
- enabled &= !command_line.HasSwitch(switches::kDisableSurfaces);
- return enabled;
-}
-
int GpuRasterizationMSAASampleCount() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
diff --git a/chromium/content/browser/gpu/compositor_util.h b/chromium/content/browser/gpu/compositor_util.h
index 1dc495a7758..d66071511a1 100644
--- a/chromium/content/browser/gpu/compositor_util.h
+++ b/chromium/content/browser/gpu/compositor_util.h
@@ -13,10 +13,6 @@ namespace content {
// Note: When adding a function here, please make sure the logic is not
// duplicated in the renderer.
-// Returns true if property tree verification is enabled (via flags or platform
-// default).
-CONTENT_EXPORT bool IsPropertyTreeVerificationEnabled();
-
// Returns true if zero-copy uploads is on (via flags, or platform default).
// Only one of one-copy and zero-copy can be enabled at a time.
CONTENT_EXPORT bool IsZeroCopyUploadEnabled();
@@ -40,9 +36,6 @@ CONTENT_EXPORT bool IsForceGpuRasterizationEnabled();
// Returns the number of raster threads to use for compositing.
CONTENT_EXPORT int NumberOfRendererRasterThreads();
-// Returns true if using cc Surfaces is allowed.
-CONTENT_EXPORT bool UseSurfacesEnabled();
-
CONTENT_EXPORT base::DictionaryValue* GetFeatureStatus();
CONTENT_EXPORT base::Value* GetProblems();
CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkarounds();
diff --git a/chromium/content/browser/gpu/gpu_arc_video_service_host.cc b/chromium/content/browser/gpu/gpu_arc_video_service_host.cc
deleted file mode 100644
index 7ba572d64f1..00000000000
--- a/chromium/content/browser/gpu/gpu_arc_video_service_host.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/gpu/gpu_arc_video_service_host.h"
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/gpu/gpu_messages.h"
-#include "content/public/browser/arc_video_host_delegate.h"
-#include "content/public/browser/browser_thread.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_utils.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
-
-namespace content {
-
-namespace {
-
-void CreateChannelOnIOThread(
- const GpuProcessHost::CreateArcVideoAcceleratorChannelCallback& callback) {
- GpuProcessHost* gpu_process_host =
- GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_ARCVIDEOACCELERATOR);
- gpu_process_host->CreateArcVideoAcceleratorChannel(callback);
-}
-
-void HandleChannelCreatedReply(
- const arc::VideoHost::OnRequestArcVideoAcceleratorChannelCallback& callback,
- const IPC::ChannelHandle& handle) {
- MojoHandle wrapped_handle;
- MojoResult wrap_result = mojo::embedder::CreatePlatformHandleWrapper(
- mojo::embedder::ScopedPlatformHandle(
- mojo::embedder::PlatformHandle(handle.socket.fd)),
- &wrapped_handle);
- if (wrap_result != MOJO_RESULT_OK) {
- LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result;
- callback.Run(mojo::ScopedHandle());
- return;
- }
- callback.Run(mojo::ScopedHandle(mojo::Handle(wrapped_handle)));
-}
-
-} // namespace
-
-scoped_ptr<arc::VideoHostDelegate> CreateArcVideoHostDelegate() {
- return make_scoped_ptr(new GpuArcVideoServiceHost());
-}
-
-GpuArcVideoServiceHost::GpuArcVideoServiceHost()
- : io_task_runner_(content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::IO)) {}
-
-GpuArcVideoServiceHost::~GpuArcVideoServiceHost() {
- DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void GpuArcVideoServiceHost::OnRequestArcVideoAcceleratorChannel(
- const OnRequestArcVideoAcceleratorChannelCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&CreateChannelOnIOThread,
- base::Bind(&HandleChannelCreatedReply, callback)));
-}
-
-void GpuArcVideoServiceHost::OnStopping() {
- GpuProcessHost::SendOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_ShutdownArcVideoService());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_arc_video_service_host.h b/chromium/content/browser/gpu/gpu_arc_video_service_host.h
deleted file mode 100644
index 3a5ca2a1dd3..00000000000
--- a/chromium/content/browser/gpu/gpu_arc_video_service_host.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_GPU_GPU_ARC_VIDEO_SERVICE_HOST_H_
-#define CONTENT_BROWSER_GPU_GPU_ARC_VIDEO_SERVICE_HOST_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "components/arc/video/video_host_delegate.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace IPC {
-struct ChannelHandle;
-}
-
-namespace content {
-
-// This class passes requests from arc::VideoInstance to GpuArcVideoService to
-// create a video accelerator channel in GPU process and reply the created
-// channel.
-//
-// Don't be confused two senses of "host" of this class. This class, which
-// implements arc::VideoHost, handles requests from arc::VideoInstance. At the
-// same time, as its name says, this class is the host of corresponding class,
-// GpuArcVideoService, in the GPU process.
-class GpuArcVideoServiceHost : public arc::VideoHostDelegate {
- public:
- GpuArcVideoServiceHost();
- ~GpuArcVideoServiceHost() override;
-
- // arc::VideoHostDelegate implementation.
- void OnStopping() override;
-
- // arc::VideoHost implementation.
- void OnRequestArcVideoAcceleratorChannel(
- const OnRequestArcVideoAcceleratorChannelCallback& callback) override;
-
- private:
- base::ThreadChecker thread_checker_;
-
- // IO task runner, where GpuProcessHost tasks run.
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuArcVideoServiceHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_GPU_GPU_ARC_VIDEO_SERVICE_HOST_H_
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl.cc b/chromium/content/browser/gpu/gpu_data_manager_impl.cc
index 2fe3cae3a06..0a820a42142 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.cc
@@ -5,6 +5,7 @@
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_data_manager_impl_private.h"
+#include "gpu/ipc/common/memory_stats.h"
namespace content {
@@ -81,11 +82,6 @@ void GpuDataManagerImpl::RegisterSwiftShaderPath(
private_->RegisterSwiftShaderPath(path);
}
-bool GpuDataManagerImpl::ShouldUseWarp() const {
- base::AutoLock auto_lock(lock_);
- return private_->ShouldUseWarp();
-}
-
void GpuDataManagerImpl::AddObserver(
GpuDataManagerObserver* observer) {
base::AutoLock auto_lock(lock_);
@@ -149,7 +145,7 @@ void GpuDataManagerImpl::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
}
void GpuDataManagerImpl::UpdateVideoMemoryUsageStats(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats) {
base::AutoLock auto_lock(lock_);
private_->UpdateVideoMemoryUsageStats(video_memory_usage_stats);
}
@@ -161,15 +157,10 @@ void GpuDataManagerImpl::AppendRendererCommandLine(
}
void GpuDataManagerImpl::AppendGpuCommandLine(
- base::CommandLine* command_line) const {
- base::AutoLock auto_lock(lock_);
- private_->AppendGpuCommandLine(command_line);
-}
-
-void GpuDataManagerImpl::AppendPluginCommandLine(
- base::CommandLine* command_line) const {
+ base::CommandLine* command_line,
+ gpu::GpuPreferences* gpu_preferences) const {
base::AutoLock auto_lock(lock_);
- private_->AppendPluginCommandLine(command_line);
+ private_->AppendGpuCommandLine(command_line, gpu_preferences);
}
void GpuDataManagerImpl::UpdateRendererWebPrefs(
@@ -246,16 +237,6 @@ size_t GpuDataManagerImpl::GetBlacklistedFeatureCount() const {
return private_->GetBlacklistedFeatureCount();
}
-void GpuDataManagerImpl::SetDisplayCount(unsigned int display_count) {
- base::AutoLock auto_lock(lock_);
- private_->SetDisplayCount(display_count);
-}
-
-unsigned int GpuDataManagerImpl::GetDisplayCount() const {
- base::AutoLock auto_lock(lock_);
- return private_->GetDisplayCount();
-}
-
bool GpuDataManagerImpl::UpdateActiveGpu(uint32_t vendor_id,
uint32_t device_id) {
base::AutoLock auto_lock(lock_);
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl.h b/chromium/content/browser/gpu/gpu_data_manager_impl.h
index c509e3a2e88..7b436f30662 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.h
@@ -21,7 +21,6 @@
#include "base/time/time.h"
#include "base/values.h"
#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/common/gpu_memory_stats.h"
#include "content/public/common/three_d_api_types.h"
#include "gpu/config/gpu_info.h"
@@ -31,6 +30,11 @@ namespace base {
class CommandLine;
}
+namespace gpu {
+struct GpuPreferences;
+struct VideoMemoryUsageStats;
+}
+
namespace content {
class GpuDataManagerImplPrivate;
@@ -74,7 +78,6 @@ class CONTENT_EXPORT GpuDataManagerImpl
void RequestVideoMemoryUsageStatsUpdate() const override;
bool ShouldUseSwiftShader() const override;
void RegisterSwiftShaderPath(const base::FilePath& path) override;
- bool ShouldUseWarp() const override;
// TODO(kbr): the threading model for the GpuDataManagerObservers is
// not well defined, and it's impossible for callers to correctly
// delete observers from anywhere except in one of the observer's
@@ -104,18 +107,18 @@ class CONTENT_EXPORT GpuDataManagerImpl
void UpdateGpuInfo(const gpu::GPUInfo& gpu_info);
void UpdateVideoMemoryUsageStats(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats);
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats);
// Insert disable-feature switches corresponding to preliminary gpu feature
// flags into the renderer process command line.
void AppendRendererCommandLine(base::CommandLine* command_line) const;
// Insert switches into gpu process command line: kUseGL, etc.
- void AppendGpuCommandLine(base::CommandLine* command_line) const;
-
- // Insert switches into plugin process command line:
- // kDisableCoreAnimationPlugins.
- void AppendPluginCommandLine(base::CommandLine* command_line) const;
+ // If the gpu_preferences isn't a nullptr, the gpu_preferences will be set
+ // for some GPU switches which have been replaced by GpuPreferences, and those
+ // switches will not be append to the command_line anymore.
+ void AppendGpuCommandLine(base::CommandLine* command_line,
+ gpu::GpuPreferences* gpu_preferences) const;
// Update WebPreferences for renderer based on blacklisting decisions.
void UpdateRendererWebPrefs(WebPreferences* prefs) const;
@@ -173,9 +176,6 @@ class CONTENT_EXPORT GpuDataManagerImpl
// Get number of features being blacklisted.
size_t GetBlacklistedFeatureCount() const;
- void SetDisplayCount(unsigned int display_count);
- unsigned int GetDisplayCount() const;
-
// Set the active gpu.
// Return true if it's a different GPU from the previous active one.
bool UpdateActiveGpu(uint32_t vendor_id, uint32_t device_id);
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
index 9e272012977..496c2ed6f6a 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -11,6 +11,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
#include "base/trace_event/trace_event.h"
@@ -18,13 +19,14 @@
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu_host_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/web_preferences.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_control_list_jsons.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
@@ -32,6 +34,7 @@
#include "gpu/config/gpu_info_collector.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/config/gpu_util.h"
+#include "gpu/ipc/common/memory_stats.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
@@ -223,16 +226,6 @@ void DisplayReconfigCallback(CGDirectDisplayID display,
reinterpret_cast<GpuDataManagerImpl*>(gpu_data_manager);
DCHECK(manager);
- // Display change.
- bool display_changed = false;
- uint32_t displayCount;
- CGGetActiveDisplayList(0, NULL, &displayCount);
- if (displayCount != manager->GetDisplayCount()) {
- manager->SetDisplayCount(displayCount);
- display_changed = true;
- }
-
- // Gpu change.
bool gpu_changed = false;
if (flags & kCGDisplayAddFlag) {
uint32_t vendor_id, device_id;
@@ -241,7 +234,7 @@ void DisplayReconfigCallback(CGDirectDisplayID display,
}
}
- if (display_changed || gpu_changed)
+ if (gpu_changed)
manager->HandleGpuSwitch();
}
#endif // OS_MACOSX
@@ -281,7 +274,7 @@ bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
return true;
}
#endif // OS_CHROMEOS
- if (use_swiftshader_ || ShouldUseWarp()) {
+ if (use_swiftshader_) {
// Skia's software rendering is probably more efficient than going through
// software emulation of the GPU, so use that.
if (feature == gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
@@ -297,19 +290,11 @@ bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
}
size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
- if (use_swiftshader_ || ShouldUseWarp())
+ if (use_swiftshader_)
return 1;
return blacklisted_features_.size();
}
-void GpuDataManagerImplPrivate::SetDisplayCount(unsigned int display_count) {
- display_count_ = display_count;
-}
-
-unsigned int GpuDataManagerImplPrivate::GetDisplayCount() const {
- return display_count_;
-}
-
gpu::GPUInfo GpuDataManagerImplPrivate::GetGPUInfo() const {
return gpu_info_;
}
@@ -321,7 +306,7 @@ void GpuDataManagerImplPrivate::GetGpuProcessHandles(
bool GpuDataManagerImplPrivate::GpuAccessAllowed(
std::string* reason) const {
- if (use_swiftshader_ || ShouldUseWarp())
+ if (use_swiftshader_)
return true;
if (!gpu_process_accessible_) {
@@ -373,8 +358,12 @@ bool GpuDataManagerImplPrivate::GpuAccessAllowed(
}
void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
- if (complete_gpu_info_already_requested_ || IsCompleteGpuInfoAvailable())
+ if (complete_gpu_info_already_requested_ || IsCompleteGpuInfoAvailable() ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kGpuTestingNoCompleteInfoCollection)) {
return;
+ }
+
complete_gpu_info_already_requested_ = true;
GpuProcessHost::SendOnIO(
@@ -404,10 +393,9 @@ bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
}
void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
- GpuProcessHost::SendOnIO(
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_GetVideoMemoryUsageStats());
+ GpuProcessHost::SendOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_GetVideoMemoryUsageStats());
}
bool GpuDataManagerImplPrivate::ShouldUseSwiftShader() const {
@@ -420,13 +408,6 @@ void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
EnableSwiftShaderIfNecessary();
}
-bool GpuDataManagerImplPrivate::ShouldUseWarp() const {
- std::string angle_impl_flag =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kUseANGLE);
- return use_warp_ || angle_impl_flag == gfx::kANGLEImplementationWARPName;
-}
-
void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->AddObserver(observer);
@@ -458,10 +439,9 @@ void GpuDataManagerImplPrivate::UnblockDomainFrom3DAPIs(const GURL& url) {
}
void GpuDataManagerImplPrivate::DisableGpuWatchdog() {
- GpuProcessHost::SendOnIO(
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_DisableWatchdog);
+ GpuProcessHost::SendOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_DisableWatchdog);
}
void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
@@ -470,6 +450,13 @@ void GpuDataManagerImplPrivate::SetGLStrings(const std::string& gl_vendor,
if (gl_vendor.empty() && gl_renderer.empty() && gl_version.empty())
return;
+ if (!is_initialized_) {
+ post_init_tasks_.push_back(
+ base::Bind(&GpuDataManagerImplPrivate::SetGLStrings,
+ base::Unretained(this), gl_vendor, gl_renderer, gl_version));
+ return;
+ }
+
// If GPUInfo already got GL strings, do nothing. This is for the rare
// situation where GPU process collected GL strings before this call.
if (!gpu_info_.gl_vendor.empty() ||
@@ -509,8 +496,10 @@ void GpuDataManagerImplPrivate::Initialize() {
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
+ if (command_line->HasSwitch(switches::kSkipGpuDataLoading)) {
+ RunPostInitTasks();
return;
+ }
gpu::GPUInfo gpu_info;
if (command_line->GetSwitchValueASCII(
@@ -530,6 +519,18 @@ void GpuDataManagerImplPrivate::Initialize() {
TRACE_EVENT0("startup",
"GpuDataManagerImpl::Initialize:CollectBasicGraphicsInfo");
gpu::CollectBasicGraphicsInfo(&gpu_info);
+
+ if (command_line->HasSwitch(switches::kGpuTestingVendorId) &&
+ command_line->HasSwitch(switches::kGpuTestingDeviceId)) {
+ base::HexStringToUInt(
+ command_line->GetSwitchValueASCII(switches::kGpuTestingVendorId),
+ &gpu_info.gpu.vendor_id);
+ base::HexStringToUInt(
+ command_line->GetSwitchValueASCII(switches::kGpuTestingDeviceId),
+ &gpu_info.gpu.device_id);
+ gpu_info.gpu.active = true;
+ gpu_info.secondary_gpus.clear();
+ }
}
#if defined(ARCH_CPU_X86_FAMILY)
if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id) {
@@ -556,16 +557,24 @@ void GpuDataManagerImplPrivate::Initialize() {
if (command_line->HasSwitch(switches::kSingleProcess) ||
command_line->HasSwitch(switches::kInProcessGPU)) {
command_line->AppendSwitch(switches::kDisableGpuWatchdog);
- AppendGpuCommandLine(command_line);
+ AppendGpuCommandLine(command_line, nullptr);
}
}
void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
GetContentClient()->SetGpuInfo(gpu_info_);
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ std::string os_version;
+ if (command_line->HasSwitch(switches::kGpuTestingOsVersion))
+ os_version =
+ command_line->GetSwitchValueASCII(switches::kGpuTestingOsVersion);
+
if (gpu_blacklist_) {
std::set<int> features = gpu_blacklist_->MakeDecision(
- gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
+ gpu::GpuControlList::kOsAny, os_version, gpu_info_);
if (update_histograms_)
UpdateStats(gpu_info_, gpu_blacklist_.get(), features);
@@ -573,13 +582,11 @@ void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
}
if (gpu_driver_bug_list_) {
gpu_driver_bugs_ = gpu_driver_bug_list_->MakeDecision(
- gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
+ gpu::GpuControlList::kOsAny, os_version, gpu_info_);
std::set<std::string> disabled_ext_set;
// Merge disabled extensions from the command line with gpu driver bug list.
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
if (command_line) {
const std::vector<std::string>& disabled_command_line_exts =
base::SplitString(
@@ -606,7 +613,7 @@ void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
// No further update of gpu_info if falling back to SwiftShader.
- if (use_swiftshader_ || ShouldUseWarp())
+ if (use_swiftshader_)
return;
bool was_info_available = IsCompleteGpuInfoAvailable();
@@ -622,7 +629,7 @@ void GpuDataManagerImplPrivate::UpdateGpuInfo(const gpu::GPUInfo& gpu_info) {
}
void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats) {
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->Notify(FROM_HERE,
&GpuDataManagerObserver::OnVideoMemoryUsageStatsUpdate,
@@ -648,7 +655,8 @@ void GpuDataManagerImplPrivate::AppendRendererCommandLine(
}
void GpuDataManagerImplPrivate::AppendGpuCommandLine(
- base::CommandLine* command_line) const {
+ base::CommandLine* command_line,
+ gpu::GpuPreferences* gpu_preferences) const {
DCHECK(command_line);
std::string use_gl =
@@ -656,6 +664,9 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
switches::kUseGL);
if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
command_line->AppendSwitch(switches::kDisableD3D11);
+ if (gpu_driver_bugs_.find(gpu::DISABLE_DIRECT_COMPOSITION) !=
+ gpu_driver_bugs_.end())
+ command_line->AppendSwitch(switches::kDisableDirectComposition);
if (use_swiftshader_) {
command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
} else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
@@ -689,12 +700,20 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
}
if (ShouldDisableAcceleratedVideoDecode(command_line)) {
- command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+ if (gpu_preferences) {
+ gpu_preferences->disable_accelerated_video_decode = true;
+ } else {
+ command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+ }
}
#if defined(ENABLE_WEBRTC)
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE) &&
!command_line->HasSwitch(switches::kDisableWebRtcHWEncoding)) {
- command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
+ if (gpu_preferences) {
+ gpu_preferences->disable_web_rtc_hw_encoding = true;
+ } else {
+ command_line->AppendSwitch(switches::kDisableWebRtcHWEncoding);
+ }
}
#endif
@@ -710,28 +729,6 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
gpu_info_.driver_vendor);
command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
gpu_info_.driver_version);
-
- if (ShouldUseWarp() && !command_line->HasSwitch(switches::kUseANGLE)) {
- command_line->AppendSwitchASCII(switches::kUseANGLE,
- gfx::kANGLEImplementationWARPName);
- }
-}
-
-void GpuDataManagerImplPrivate::AppendPluginCommandLine(
- base::CommandLine* command_line) const {
- DCHECK(command_line);
-
-#if defined(OS_MACOSX)
- // TODO(jbauman): Add proper blacklist support for core animation plugins so
- // special-casing this video card won't be necessary. See
- // http://crbug.com/134015
- if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING)) {
- if (!command_line->HasSwitch(
- switches::kDisableCoreAnimationPlugins))
- command_line->AppendSwitch(
- switches::kDisableCoreAnimationPlugins);
- }
-#endif
}
void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
@@ -752,16 +749,6 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
prefs->flash_stage3d_baseline_enabled = false;
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS))
prefs->accelerated_2d_canvas_enabled = false;
- // TODO(senorblanco): The renderer shouldn't have an extra setting
- // for this, but should rely on extension availability.
- // Note that |gl_multisampling_enabled| only affects the decoder's
- // default framebuffer allocation, which does not support
- // multisampled_render_to_texture, only msaa with explicit resolve.
- if (IsDriverBugWorkaroundActive(
- gpu::DISABLE_CHROMIUM_FRAMEBUFFER_MULTISAMPLE) ||
- (IsDriverBugWorkaroundActive(gpu::DISABLE_MULTIMONITOR_MULTISAMPLING) &&
- display_count_ > 1))
- prefs->gl_multisampling_enabled = false;
#if defined(USE_AURA)
if (!CanUseGpuBrowserCompositor()) {
@@ -782,12 +769,18 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
}
void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
+ if (!is_initialized_) {
+ post_init_tasks_.push_back(
+ base::Bind(&GpuDataManagerImplPrivate::DisableHardwareAcceleration,
+ base::Unretained(this)));
+ return;
+ }
+
card_blacklisted_ = true;
for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
blacklisted_features_.insert(i);
- EnableWarpIfNecessary();
EnableSwiftShaderIfNecessary();
NotifyGpuInfoUpdate();
}
@@ -867,10 +860,9 @@ void GpuDataManagerImplPrivate::HandleGpuSwitch() {
// Notify observers in the browser process.
ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
// Pass the notification to the GPU process to notify observers there.
- GpuProcessHost::SendOnIO(
- GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
- new GpuMsg_GpuSwitched);
+ GpuProcessHost::SendOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH,
+ new GpuMsg_GpuSwitched);
}
bool GpuDataManagerImplPrivate::UpdateActiveGpu(uint32_t vendor_id,
@@ -905,8 +897,6 @@ bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuCompositing))
return false;
- if (ShouldUseWarp())
- return true;
if (ShouldUseSwiftShader())
return false;
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
@@ -932,22 +922,8 @@ bool GpuDataManagerImplPrivate::ShouldDisableAcceleratedVideoDecode(
if (group_name == "Disabled")
return true;
- // Accelerated decode is never available with --disable-gpu. It is also
- // currently non-functional with --single-process and --in-process-gpu, but
- // these should be fixable. We set the --disable-accelerated-video-decode flag
- // in these cases so that the renderer can be aware. (Which is important on
- // Android where there is no fallback once WMPI is selected.)
- //
- // TODO(sandersd): Enable support for accelerated decode with
- // --in-process-gpu, at least on Android (necessary to support WebView).
- // http://crbug.com/574935.
- if (command_line->HasSwitch(switches::kDisableGpu) ||
- command_line->HasSwitch(switches::kSingleProcess) ||
- command_line->HasSwitch(switches::kInProcessGPU)) {
- return true;
- }
-
- return false;
+ // Accelerated decode is never available with --disable-gpu.
+ return command_line->HasSwitch(switches::kDisableGpu);
}
void GpuDataManagerImplPrivate::GetDisabledExtensions(
@@ -990,19 +966,17 @@ GpuDataManagerImplPrivate* GpuDataManagerImplPrivate::Create(
return new GpuDataManagerImplPrivate(owner);
}
-GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
- GpuDataManagerImpl* owner)
+GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(GpuDataManagerImpl* owner)
: complete_gpu_info_already_requested_(false),
observer_list_(new GpuDataManagerObserverList),
use_swiftshader_(false),
- use_warp_(false),
card_blacklisted_(false),
update_histograms_(true),
window_count_(0),
domain_blocking_enabled_(true),
owner_(owner),
- display_count_(0),
gpu_process_accessible_(true),
+ is_initialized_(false),
finalized_(false) {
DCHECK(owner_);
const base::CommandLine* command_line =
@@ -1014,7 +988,6 @@ GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
DisableHardwareAcceleration();
#if defined(OS_MACOSX)
- CGGetActiveDisplayList (0, NULL, &display_count_);
CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_);
#endif // OS_MACOSX
@@ -1059,6 +1032,17 @@ void GpuDataManagerImplPrivate::InitializeImpl(
UpdateGpuInfo(gpu_info);
UpdateGpuSwitchingManager(gpu_info);
UpdatePreliminaryBlacklistedFeatures();
+
+ RunPostInitTasks();
+}
+
+void GpuDataManagerImplPrivate::RunPostInitTasks() {
+ // Set initialized before running callbacks.
+ is_initialized_ = true;
+
+ for (const auto& callback : post_init_tasks_)
+ callback.Run();
+ post_init_tasks_.clear();
}
void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
@@ -1072,7 +1056,6 @@ void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
}
- EnableWarpIfNecessary();
EnableSwiftShaderIfNecessary();
}
@@ -1104,9 +1087,6 @@ void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
}
void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
- if (ShouldUseWarp())
- return;
-
if (!GpuAccessAllowed(NULL) ||
blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
if (!swiftshader_path_.empty() &&
@@ -1116,22 +1096,6 @@ void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
}
}
-void GpuDataManagerImplPrivate::EnableWarpIfNecessary() {
-#if defined(OS_WIN)
- if (use_warp_)
- return;
- // We should only use WARP if we are unable to use the regular GPU for
- // compositing, and if we in Metro mode.
- use_warp_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kViewerConnect) &&
- !CanUseGpuBrowserCompositor();
-#endif
-}
-
-void GpuDataManagerImplPrivate::ForceWarpModeForTesting() {
- use_warp_ = true;
-}
-
std::string GpuDataManagerImplPrivate::GetDomainFromURL(
const GURL& url) const {
// For the moment, we just use the host, or its IP address, as the
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl_private.h b/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
index b083b601775..229d510dae8 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -28,6 +28,11 @@ namespace base {
class CommandLine;
}
+namespace gpu {
+struct GpuPreferences;
+struct VideoMemoryUsageStats;
+}
+
namespace content {
class CONTENT_EXPORT GpuDataManagerImplPrivate {
@@ -49,7 +54,6 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
void RequestVideoMemoryUsageStatsUpdate() const;
bool ShouldUseSwiftShader() const;
void RegisterSwiftShaderPath(const base::FilePath& path);
- bool ShouldUseWarp() const;
void AddObserver(GpuDataManagerObserver* observer);
void RemoveObserver(GpuDataManagerObserver* observer);
void UnblockDomainFrom3DAPIs(const GURL& url);
@@ -67,13 +71,12 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
void UpdateGpuInfo(const gpu::GPUInfo& gpu_info);
void UpdateVideoMemoryUsageStats(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats);
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats);
void AppendRendererCommandLine(base::CommandLine* command_line) const;
- void AppendGpuCommandLine(base::CommandLine* command_line) const;
-
- void AppendPluginCommandLine(base::CommandLine* command_line) const;
+ void AppendGpuCommandLine(base::CommandLine* command_line,
+ gpu::GpuPreferences* gpu_preferences) const;
void UpdateRendererWebPrefs(WebPreferences* prefs) const;
@@ -116,9 +119,6 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
size_t GetBlacklistedFeatureCount() const;
- void SetDisplayCount(unsigned int display_count);
- unsigned int GetDisplayCount() const;
-
bool UpdateActiveGpu(uint32_t vendor_id, uint32_t device_id);
void OnGpuProcessInitFailure();
@@ -139,8 +139,6 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
SwiftShaderRendering2);
FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
- WarpEnabledOverridesSwiftShader);
- FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
GpuInfoUpdate);
FRIEND_TEST_ALL_PREFIXES(GpuDataManagerImplPrivateTest,
NoGpuInfoUpdateWithSwiftShader);
@@ -197,6 +195,8 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
const std::string& gpu_driver_bug_list_json,
const gpu::GPUInfo& gpu_info);
+ void RunPostInitTasks();
+
void UpdateGpuInfoHelper();
void UpdateBlacklistedFeatures(const std::set<int>& features);
@@ -215,13 +215,6 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
// Try to switch to SwiftShader rendering, if possible and necessary.
void EnableSwiftShaderIfNecessary();
- // Try to switch to WARP rendering if the GPU hardware is not supported or
- // absent, and if we are trying to run in Windows Metro mode.
- void EnableWarpIfNecessary();
-
- // Use only for testing, forces |use_warp_| to true.
- void ForceWarpModeForTesting();
-
// Helper to extract the domain from a given URL.
std::string GetDomainFromURL(const GURL& url) const;
@@ -252,8 +245,6 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
bool use_swiftshader_;
- bool use_warp_;
-
base::FilePath swiftshader_path_;
// Current card force-blacklisted due to GPU crashes, or disabled through
@@ -273,15 +264,20 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
GpuDataManagerImpl* owner_;
- unsigned int display_count_;
-
bool gpu_process_accessible_;
+ // True if Initialize() has been completed.
+ bool is_initialized_;
+
// True if all future Initialize calls should be ignored.
bool finalized_;
std::string disabled_extensions_;
+ // If one tries to call a member before initialization then it is defered
+ // until Initialize() is completed.
+ std::vector<base::Closure> post_init_tasks_;
+
DISALLOW_COPY_AND_ASSIGN(GpuDataManagerImplPrivate);
};
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index f1865594646..c92f37cbf43 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -15,6 +15,7 @@
#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/gpu_switches.h"
+#include "gpu/ipc/common/memory_stats.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -43,7 +44,7 @@ class TestObserver : public GpuDataManagerObserver {
void OnGpuInfoUpdate() override { gpu_info_updated_ = true; }
void OnVideoMemoryUsageStatsUpdate(
- const GPUVideoMemoryUsageStats& stats) override {
+ const gpu::VideoMemoryUsageStats& stats) override {
video_memory_usage_stats_updated_ = true;
}
@@ -233,6 +234,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuSideExceptions) {
TEST_F(GpuDataManagerImplPrivateTest, DisableHardwareAcceleration) {
ScopedGpuDataManagerImplPrivate manager;
+ manager->InitializeForTesting("", gpu::GPUInfo());
EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
std::string reason;
EXPECT_TRUE(manager->GpuAccessAllowed(&reason));
@@ -248,6 +250,7 @@ TEST_F(GpuDataManagerImplPrivateTest, DisableHardwareAcceleration) {
TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering) {
// Blacklist, then register SwiftShader.
ScopedGpuDataManagerImplPrivate manager;
+ manager->InitializeForTesting("", gpu::GPUInfo());
EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
EXPECT_FALSE(manager->ShouldUseSwiftShader());
@@ -270,6 +273,7 @@ TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering) {
TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering2) {
// Register SwiftShader, then blacklist.
ScopedGpuDataManagerImplPrivate manager;
+ manager->InitializeForTesting("", gpu::GPUInfo());
EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
EXPECT_FALSE(manager->ShouldUseSwiftShader());
@@ -288,22 +292,6 @@ TEST_F(GpuDataManagerImplPrivateTest, SwiftShaderRendering2) {
gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS));
}
-TEST_F(GpuDataManagerImplPrivateTest, WarpEnabledOverridesSwiftShader) {
- // If WARP fallback is enabled on Windows 8 it should not allow SwiftShader
- // to be enabled.
-#if defined(OS_WIN)
- if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
- ScopedGpuDataManagerImplPrivate manager;
- manager->ForceWarpModeForTesting();
- const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
- manager->RegisterSwiftShaderPath(test_path);
- manager->DisableHardwareAcceleration();
- EXPECT_TRUE(manager->ShouldUseWarp());
- EXPECT_FALSE(manager->ShouldUseSwiftShader());
- }
-#endif
-}
-
TEST_F(GpuDataManagerImplPrivateTest, GpuInfoUpdate) {
ScopedGpuDataManagerImpl manager;
@@ -327,6 +315,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuInfoUpdate) {
TEST_F(GpuDataManagerImplPrivateTest, NoGpuInfoUpdateWithSwiftShader) {
ScopedGpuDataManagerImpl manager;
+ manager->InitializeForTesting("", gpu::GPUInfo());
manager->DisableHardwareAcceleration();
const base::FilePath test_path(FILE_PATH_LITERAL("AnyPath"));
@@ -368,7 +357,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GPUVideoMemoryUsageStatsUpdate) {
}
EXPECT_FALSE(observer.video_memory_usage_stats_updated());
- GPUVideoMemoryUsageStats vram_stats;
+ gpu::VideoMemoryUsageStats vram_stats;
manager->UpdateVideoMemoryUsageStats(vram_stats);
{
base::RunLoop run_loop;
@@ -609,6 +598,43 @@ TEST_F(GpuDataManagerImplPrivateTest, SetGLStringsNoEffects) {
EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
EXPECT_TRUE(manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL));
}
+
+TEST_F(GpuDataManagerImplPrivateTest, SetGLStringsDefered) {
+ const char* kGLVendorMesa = "Tungsten Graphics, Inc";
+ const char* kGLRendererMesa = "Mesa DRI Intel(R) G41";
+ const char* kGLVersionMesa801 = "2.1 Mesa 8.0.1-DEVEL";
+
+ ScopedGpuDataManagerImplPrivate manager;
+ EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
+
+ const std::string blacklist_json = LONG_STRING_CONST({
+ "name" : "gpu blacklist",
+ "version" : "0.1",
+ "entries" : [ {
+ "id" : 1,
+ "vendor_id" : "0x8086",
+ "device_id" : ["0x0042"],
+ "driver_vendor" : "Mesa",
+ "driver_version" : {"op" : ">=", "value" : "8.0.0"},
+ "features" : ["webgl"]
+ } ]
+ });
+
+ // Check that it is allowed to call SetGLStrings before Initialize.
+
+ // Assume browser gets GL strings from local state.
+ manager->SetGLStrings(kGLVendorMesa, kGLRendererMesa, kGLVersionMesa801);
+
+ gpu::GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x8086;
+ gpu_info.gpu.device_id = 0x0042;
+ manager->InitializeForTesting(blacklist_json, gpu_info);
+
+ EXPECT_TRUE(manager->GpuAccessAllowed(NULL));
+ EXPECT_EQ(1u, manager->GetBlacklistedFeatureCount());
+ EXPECT_TRUE(manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL));
+}
#endif // OS_LINUX
TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListSingle) {
@@ -616,7 +642,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListSingle) {
manager->gpu_driver_bugs_.insert(5);
base::CommandLine command_line(0, NULL);
- manager->AppendGpuCommandLine(&command_line);
+ manager->AppendGpuCommandLine(&command_line, nullptr);
EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
std::string args = command_line.GetSwitchValueASCII(
@@ -630,7 +656,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListMultiple) {
manager->gpu_driver_bugs_.insert(7);
base::CommandLine command_line(0, NULL);
- manager->AppendGpuCommandLine(&command_line);
+ manager->AppendGpuCommandLine(&command_line, nullptr);
EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
std::string args = command_line.GetSwitchValueASCII(
diff --git a/chromium/content/browser/gpu/gpu_internals_ui.cc b/chromium/content/browser/gpu/gpu_internals_ui.cc
index e93c9015202..34ba18db3b6 100644
--- a/chromium/content/browser/gpu/gpu_internals_ui.cc
+++ b/chromium/content/browser/gpu/gpu_internals_ui.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -42,6 +43,7 @@
#endif
#if defined(OS_WIN)
#include "ui/base/win/shell.h"
+#include "ui/gfx/win/physical_size.h"
#endif
#if defined(OS_LINUX) && defined(USE_X11)
@@ -144,9 +146,20 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
ui::win::IsAeroGlassEnabled() ? "Aero Glass" : "none";
basic_info->Append(
NewDescriptionValuePair("Desktop compositing", compositor));
- if (GpuDataManagerImpl::GetInstance()->ShouldUseWarp()) {
- basic_info->Append(NewDescriptionValuePair("Using WARP",
- new base::FundamentalValue(true)));
+
+ std::vector<gfx::PhysicalDisplaySize> display_sizes =
+ gfx::GetPhysicalSizeForDisplays();
+ for (const auto& display_size : display_sizes) {
+ const int w = display_size.width_mm;
+ const int h = display_size.height_mm;
+ const double size_mm = sqrt(w * w + h * h);
+ const double size_inches = 0.0393701 * size_mm;
+ const double rounded_size_inches = floor(10.0 * size_inches) / 10.0;
+ std::string size_string = base::StringPrintf("%.1f\"", rounded_size_inches);
+ std::string description_string = base::StringPrintf(
+ "Diagonal Monitor Size of %s", display_size.display_name.c_str());
+ basic_info->Append(
+ NewDescriptionValuePair(description_string, size_string));
}
#endif
@@ -230,7 +243,7 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
scoped_ptr<base::Value> dx_info = base::Value::CreateNullValue();
if (gpu_info.dx_diagnostics.children.size())
dx_info.reset(DxDiagNodeToList(gpu_info.dx_diagnostics));
- info->Set("diagnostics", dx_info.Pass());
+ info->Set("diagnostics", std::move(dx_info));
#endif
return info;
@@ -286,7 +299,19 @@ const char* BufferUsageToString(gfx::BufferUsage usage) {
return nullptr;
}
-base::DictionaryValue* GpuMemoryBufferInfoAsDictionaryValue() {
+base::ListValue* CompositorInfo() {
+ base::ListValue* compositor_info = new base::ListValue();
+
+ compositor_info->Append(NewDescriptionValuePair(
+ "Tile Update Mode",
+ IsZeroCopyUploadEnabled() ? "Zero-copy" : "One-copy"));
+
+ compositor_info->Append(NewDescriptionValuePair(
+ "Partial Raster", IsPartialRasterEnabled() ? "Enabled" : "Disabled"));
+ return compositor_info;
+}
+
+base::ListValue* GpuMemoryBufferInfo() {
base::ListValue* gpu_memory_buffer_info = new base::ListValue();
BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
@@ -312,11 +337,7 @@ base::DictionaryValue* GpuMemoryBufferInfoAsDictionaryValue() {
BufferFormatToString(static_cast<gfx::BufferFormat>(format)),
native_usage_support));
}
-
- base::DictionaryValue* info = new base::DictionaryValue();
- info->Set("gpu_memory_buffer_info", gpu_memory_buffer_info);
-
- return info;
+ return gpu_memory_buffer_info;
}
// This class receives javascript messages from the renderer.
@@ -492,18 +513,12 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
workarounds->AppendString(workaround);
feature_status->Set("workarounds", workarounds);
gpu_info_val->Set("featureStatus", feature_status);
+ gpu_info_val->Set("compositorInfo", CompositorInfo());
+ gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo());
// Send GPU Info to javascript.
web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
*(gpu_info_val.get()));
-
- // Get GpuMemoryBuffer Info.
- scoped_ptr<base::DictionaryValue> gpu_memory_buffer_info_val(
- GpuMemoryBufferInfoAsDictionaryValue());
-
- // Send GpuMemoryBuffer Info to javascript.
- web_ui()->CallJavascriptFunction("browserBridge.onGpuMemoryBufferInfoUpdate",
- *(gpu_memory_buffer_info_val.get()));
}
void GpuMessageHandler::OnGpuSwitched() {
diff --git a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
index 1dcb1549049..fd0ba6909dd 100644
--- a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -9,12 +9,13 @@
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/content_browser_test.h"
#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "ui/gl/gl_switches.h"
@@ -27,9 +28,32 @@ const content::CauseForGpuLaunch kInitCause =
content::
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
+scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext(
+ gpu::GpuChannelHost* gpu_channel_host) {
+ // This is for an offscreen context, so the default framebuffer doesn't need
+ // any alpha, depth, stencil, antialiasing.
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = -1;
+ attributes.depth_size = 0;
+ attributes.stencil_size = 0;
+ attributes.samples = 0;
+ attributes.sample_buffers = 0;
+ attributes.bind_generates_resource = false;
+ bool share_resources = false;
+ bool automatic_flushes = false;
+ return make_scoped_ptr(
+ WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
+ gpu_channel_host, attributes, gfx::PreferIntegratedGpu,
+ share_resources, automatic_flushes, GURL(),
+ WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
+ nullptr));
+}
+
class ContextTestBase : public content::ContentBrowserTest {
public:
void SetUpOnMainThread() override {
+ // This may leave the provider_ null in some cases, so tests need to early
+ // out.
if (!content::BrowserGpuChannelHostFactory::CanUseForTesting())
return;
@@ -39,36 +63,36 @@ class ContextTestBase : public content::ContentBrowserTest {
content::BrowserGpuChannelHostFactory* factory =
content::BrowserGpuChannelHostFactory::instance();
CHECK(factory);
- bool lose_context_when_out_of_memory = false;
base::RunLoop run_loop;
factory->EstablishGpuChannel(kInitCause, run_loop.QuitClosure());
run_loop.Run();
- scoped_refptr<content::GpuChannelHost>
- gpu_channel_host(factory->GetGpuChannel());
- DCHECK(gpu_channel_host.get());
- context_.reset(
- WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
- gpu_channel_host.get(),
- blink::WebGraphicsContext3D::Attributes(),
- lose_context_when_out_of_memory,
- GURL(),
- WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
- NULL));
- CHECK(context_.get());
- context_->InitializeOnCurrentThread();
- context_support_ = context_->GetContextSupport();
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
+ factory->GetGpuChannel());
+ CHECK(gpu_channel_host);
+
+ provider_ = content::ContextProviderCommandBuffer::Create(
+ CreateContext(gpu_channel_host.get()),
+ content::OFFSCREEN_CONTEXT_FOR_TESTING);
+ bool bound = provider_->BindToCurrentThread();
+ CHECK(bound);
+ gl_ = provider_->ContextGL();
+ context_support_ = provider_->ContextSupport();
+
ContentBrowserTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
// Must delete the context first.
- context_.reset(NULL);
+ provider_ = nullptr;
ContentBrowserTest::TearDownOnMainThread();
}
protected:
- scoped_ptr<content::WebGraphicsContext3DCommandBufferImpl> context_;
- gpu::ContextSupport* context_support_;
+ gpu::gles2::GLES2Interface* gl_ = nullptr;
+ gpu::ContextSupport* context_support_ = nullptr;
+
+ private:
+ scoped_refptr<content::ContextProviderCommandBuffer> provider_;
};
} // namespace
@@ -121,26 +145,12 @@ class BrowserGpuChannelHostFactoryTest : public ContentBrowserTest {
run_loop.Run();
}
- GpuChannelHost* GetGpuChannel() {
- return GetFactory()->GetGpuChannel();
- }
+ gpu::GpuChannelHost* GetGpuChannel() { return GetFactory()->GetGpuChannel(); }
static void Signal(bool *event) {
CHECK_EQ(*event, false);
*event = true;
}
-
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext() {
- bool lose_context_when_out_of_memory = false;
- return make_scoped_ptr(
- WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
- GetGpuChannel(),
- blink::WebGraphicsContext3D::Attributes(),
- lose_context_when_out_of_memory,
- GURL(),
- WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
- NULL));
- }
};
// Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
@@ -185,7 +195,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
MAYBE_AlreadyEstablished) {
DCHECK(!IsChannelEstablished());
- scoped_refptr<GpuChannelHost> gpu_channel =
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel =
GetFactory()->EstablishGpuChannelSync(kInitCause);
// Expect established callback immediately.
@@ -199,9 +209,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
#endif
// Test fails on Windows because GPU Channel set-up fails.
-// Mac only fails GPU set-up on MacOS 10.6, but we have no version-specific
-// macros for disabling tests.
-#if !defined(OS_WIN) && !defined(OS_MACOSX)
+#if !defined(OS_WIN)
#define MAYBE_GrContextKeepsGpuChannelAlive GrContextKeepsGpuChannelAlive
#else
#define MAYBE_GrContextKeepsGpuChannelAlive \
@@ -221,22 +229,33 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
// Step 2: verify that holding onto the provider's GrContext will
// retain the host after provider is destroyed.
scoped_refptr<ContextProviderCommandBuffer> provider =
- ContextProviderCommandBuffer::Create(CreateContext(),
+ ContextProviderCommandBuffer::Create(CreateContext(GetGpuChannel()),
OFFSCREEN_CONTEXT_FOR_TESTING);
EXPECT_TRUE(provider->BindToCurrentThread());
- skia::RefPtr<GrContext> gr_context = skia::SharePtr(provider->GrContext());
- provider = nullptr;
+ sk_sp<GrContext> gr_context = sk_ref_sp(provider->GrContext());
SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
- skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRenderTarget(
- gr_context.get(), SkSurface::kNo_Budgeted, info));
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
+ gr_context.get(), SkBudgeted::kNo, info);
+ EXPECT_TRUE(surface);
+
+ // Destroy the GL context after we made a surface.
+ provider = nullptr;
+
+ // New surfaces will fail to create now.
+ sk_sp<SkSurface> surface2 =
+ SkSurface::MakeRenderTarget(gr_context.get(), SkBudgeted::kNo, info);
+ EXPECT_FALSE(surface2);
+
+ // Drop our reference to the gr_context also.
gr_context = nullptr;
- // use the canvas after the provider and grcontext have been locally
- // unref'ed. This should work just fine thanks to SkSurface_Gpu ref'ing
- // the GrContext, which is ref'ing the GrGLInterfaceForWebGraphicsContext3D,
- // which owns the commandbuffer instance.
+ // After the context provider is destroyed, the surface no longer has access
+ // to the GrContext, even though it's alive. Use the canvas after the provider
+ // and GrContext have been locally unref'ed. This should work fine as the
+ // GrContext has been abandoned when the GL context provider was destroyed
+ // above.
SkPaint greenFillPaint;
greenFillPaint.setColor(SK_ColorGREEN);
greenFillPaint.setStyle(SkPaint::kFill_Style);
@@ -255,10 +274,10 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
MAYBE_CrashAndRecover) {
DCHECK(!IsChannelEstablished());
EstablishAndWait();
- scoped_refptr<GpuChannelHost> host = GetGpuChannel();
+ scoped_refptr<gpu::GpuChannelHost> host = GetGpuChannel();
scoped_refptr<ContextProviderCommandBuffer> provider =
- ContextProviderCommandBuffer::Create(CreateContext(),
+ ContextProviderCommandBuffer::Create(CreateContext(GetGpuChannel()),
OFFSCREEN_CONTEXT_FOR_TESTING);
base::RunLoop run_loop;
int counter = 0;
diff --git a/chromium/content/browser/gpu/gpu_process_host.cc b/chromium/content/browser/gpu/gpu_process_host.cc
index b3bd310650a..1f03d6361d5 100644
--- a/chromium/content/browser/gpu/gpu_process_host.cc
+++ b/chromium/content/browser/gpu/gpu_process_host.cc
@@ -31,11 +31,13 @@
#include "content/browser/mojo/mojo_application_host.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/child_process_host_impl.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/establish_channel_params.h"
+#include "content/common/gpu_host_messages.h"
#include "content/common/in_process_child_thread_params.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/gpu_utils.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
@@ -44,6 +46,7 @@
#include "content/public/common/result_codes.h"
#include "content/public/common/sandbox_type.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_switches.h"
@@ -62,6 +65,7 @@
#include "content/common/sandbox_win.h"
#include "sandbox/win/src/sandbox_policy.h"
#include "ui/gfx/switches.h"
+#include "ui/gfx/win/rendering_window_manager.h"
#endif
#if defined(USE_OZONE)
@@ -104,13 +108,10 @@ static const char* const kSwitchNames[] = {
#endif
switches::kEnableHeapProfiling,
switches::kEnableLogging,
- switches::kEnableShareGroupAsyncTextureUpload,
-#if defined(OS_ANDROID)
- switches::kEnableUnifiedMediaPipeline,
-#endif
#if defined(OS_CHROMEOS)
switches::kDisableVaapiAcceleratedVideoEncode,
#endif
+ switches::kGpuDriverBugWorkarounds,
switches::kGpuStartupDialog,
switches::kGpuSandboxAllowSysVShm,
switches::kGpuSandboxFailuresFatal,
@@ -129,13 +130,9 @@ static const char* const kSwitchNames[] = {
switches::kVModule,
#if defined(OS_MACOSX)
switches::kDisableRemoteCoreAnimation,
- switches::kDisableMacOverlays,
switches::kEnableSandboxLogging,
switches::kShowMacOverlayBorders,
#endif
-#if defined(USE_AURA)
- switches::kUIPrioritizeInGpuProcess,
-#endif
#if defined(USE_OZONE)
switches::kOzonePlatform,
#endif
@@ -382,6 +379,14 @@ void GpuProcessHost::SendOnIO(GpuProcessKind kind,
GpuMainThreadFactoryFunction g_gpu_main_thread_factory = NULL;
+GpuProcessHost::EstablishChannelRequest::EstablishChannelRequest()
+ : client_id(0) {}
+
+GpuProcessHost::EstablishChannelRequest::EstablishChannelRequest(
+ const EstablishChannelRequest& other) = default;
+
+GpuProcessHost::EstablishChannelRequest::~EstablishChannelRequest() {}
+
void GpuProcessHost::RegisterGpuMainThreadFactory(
GpuMainThreadFactoryFunction create) {
g_gpu_main_thread_factory = create;
@@ -451,11 +456,6 @@ GpuProcessHost::~GpuProcessHost() {
if (g_gpu_process_hosts[kind_] == this)
g_gpu_process_hosts[kind_] = NULL;
- // If there are any remaining offscreen contexts at the point the
- // GPU process exits, assume something went wrong, and block their
- // URLs from accessing client 3D APIs without prompting.
- BlockLiveOffscreenContexts();
-
UMA_HISTOGRAM_COUNTS_100("GPU.AtExitSurfaceCount",
GpuSurfaceTracker::Get()->GetSurfaceCount());
UMA_HISTOGRAM_BOOLEAN("GPU.AtExitReceivedMemoryStats",
@@ -473,6 +473,7 @@ GpuProcessHost::~GpuProcessHost() {
}
std::string message;
+ bool block_offscreen_contexts = true;
if (!in_process_) {
int exit_code;
base::TerminationStatus status = process_->GetTerminationStatus(
@@ -490,6 +491,14 @@ GpuProcessHost::~GpuProcessHost() {
switch (status) {
case base::TERMINATION_STATUS_NORMAL_TERMINATION:
+ // Don't block offscreen contexts (and force page reload for webgl)
+ // if this was an intentional shutdown or the OOM killer on Android
+ // killed us while Chrome was in the background.
+// TODO(crbug.com/598400): Restrict this to Android for now, since other
+// platforms might fall through here for the 'exit_on_context_lost' workaround.
+#if defined(OS_ANDROID)
+ block_offscreen_contexts = false;
+#endif
message = "The GPU process exited normally. Everything is okay.";
break;
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
@@ -516,6 +525,12 @@ GpuProcessHost::~GpuProcessHost() {
}
}
+ // If there are any remaining offscreen contexts at the point the
+ // GPU process exits, assume something went wrong, and block their
+ // URLs from accessing client 3D APIs without prompting.
+ if (block_offscreen_contexts)
+ BlockLiveOffscreenContexts();
+
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&GpuProcessHostUIShim::Destroy,
@@ -535,25 +550,30 @@ bool GpuProcessHost::Init() {
if (!SetupMojo())
return false;
+ gpu::GpuPreferences gpu_preferences = GetGpuPreferencesFromCommandLine();
if (in_process_) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(g_gpu_main_thread_factory);
in_process_gpu_thread_.reset(
g_gpu_main_thread_factory(InProcessChildThreadParams(
- channel_id, base::MessageLoop::current()->task_runner())));
+ channel_id, base::MessageLoop::current()->task_runner()),
+ gpu_preferences));
base::Thread::Options options;
#if defined(OS_WIN)
// WGL needs to create its own window and pump messages on it.
options.message_loop_type = base::MessageLoop::TYPE_UI;
#endif
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+ options.priority = base::ThreadPriority::DISPLAY;
+#endif
in_process_gpu_thread_->StartWithOptions(options);
OnProcessLaunched(); // Fake a callback that the process is ready.
- } else if (!LaunchGpuProcess(channel_id)) {
+ } else if (!LaunchGpuProcess(channel_id, &gpu_preferences)) {
return false;
}
- if (!Send(new GpuMsg_Initialize()))
+ if (!Send(new GpuMsg_Initialize(gpu_preferences)))
return false;
return true;
@@ -599,15 +619,10 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized)
IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
- IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryBufferCreated,
OnGpuMemoryBufferCreated)
IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext,
OnDidCreateOffscreenContext)
-#if defined(OS_CHROMEOS)
- IPC_MESSAGE_HANDLER(GpuHostMsg_ArcVideoAcceleratorChannelCreated,
- OnArcVideoAcceleratorChannelCreated)
-#endif
IPC_MESSAGE_HANDLER(GpuHostMsg_DidLoseContext, OnDidLoseContext)
IPC_MESSAGE_HANDLER(GpuHostMsg_DidDestroyOffscreenContext,
OnDidDestroyOffscreenContext)
@@ -617,10 +632,8 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_GENERIC(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
OnAcceleratedSurfaceBuffersSwapped(message))
#endif
- IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel,
- OnDestroyChannel)
- IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader,
- OnCacheShader)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel, OnDestroyChannel)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader, OnCacheShader)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceCreatedChildWindow,
OnAcceleratedSurfaceCreatedChildWindow)
@@ -634,31 +647,38 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
#if defined(OS_WIN)
void GpuProcessHost::OnAcceleratedSurfaceCreatedChildWindow(
- const gfx::PluginWindowHandle& parent_handle,
- const gfx::PluginWindowHandle& window_handle) {
- DCHECK(process_);
- {
- DWORD process_id = 0;
- DWORD thread_id = GetWindowThreadProcessId(parent_handle, &process_id);
-
- if (!thread_id || process_id != ::GetCurrentProcessId()) {
- process_->TerminateOnBadMessageReceived(
- GpuHostMsg_AcceleratedSurfaceCreatedChildWindow::ID);
- return;
+ gpu::SurfaceHandle parent_handle,
+ gpu::SurfaceHandle window_handle) {
+ if (!in_process_) {
+ DCHECK(process_);
+ {
+ DWORD process_id = 0;
+ DWORD thread_id = GetWindowThreadProcessId(parent_handle, &process_id);
+
+ if (!thread_id || process_id != ::GetCurrentProcessId()) {
+ process_->TerminateOnBadMessageReceived(
+ GpuHostMsg_AcceleratedSurfaceCreatedChildWindow::ID);
+ return;
+ }
}
- }
- {
- DWORD process_id = 0;
- DWORD thread_id = GetWindowThreadProcessId(window_handle, &process_id);
- if (!thread_id || process_id != process_->GetProcess().Pid()) {
- process_->TerminateOnBadMessageReceived(
- GpuHostMsg_AcceleratedSurfaceCreatedChildWindow::ID);
- return;
+ {
+ DWORD process_id = 0;
+ DWORD thread_id = GetWindowThreadProcessId(window_handle, &process_id);
+
+ if (!thread_id || process_id != process_->GetProcess().Pid()) {
+ process_->TerminateOnBadMessageReceived(
+ GpuHostMsg_AcceleratedSurfaceCreatedChildWindow::ID);
+ return;
+ }
}
}
- ::SetParent(window_handle, parent_handle);
+ if (!gfx::RenderingWindowManager::GetInstance()->RegisterChild(
+ parent_handle, window_handle)) {
+ process_->TerminateOnBadMessageReceived(
+ GpuHostMsg_AcceleratedSurfaceCreatedChildWindow::ID);
+ }
}
#endif
@@ -675,8 +695,7 @@ void GpuProcessHost::EstablishGpuChannel(
int client_id,
uint64_t client_tracing_id,
bool preempts,
- bool preempted,
- bool allow_future_sync_points,
+ bool allow_view_command_buffers,
bool allow_real_time_streams,
const EstablishChannelCallback& callback) {
DCHECK(CalledOnValidThread());
@@ -689,15 +708,17 @@ void GpuProcessHost::EstablishGpuChannel(
return;
}
- GpuMsg_EstablishChannel_Params params;
+ EstablishChannelParams params;
params.client_id = client_id;
params.client_tracing_id = client_tracing_id;
params.preempts = preempts;
- params.preempted = preempted;
- params.allow_future_sync_points = allow_future_sync_points;
+ params.allow_view_command_buffers = allow_view_command_buffers;
params.allow_real_time_streams = allow_real_time_streams;
if (Send(new GpuMsg_EstablishChannel(params))) {
- channel_requests_.push(callback);
+ EstablishChannelRequest request;
+ request.client_id = client_id;
+ request.callback = callback;
+ channel_requests_.push(request);
} else {
DVLOG(1) << "Failed to send GpuMsg_EstablishChannel.";
callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
@@ -709,27 +730,6 @@ void GpuProcessHost::EstablishGpuChannel(
}
}
-void GpuProcessHost::CreateViewCommandBuffer(
- const gfx::GLSurfaceHandle& compositing_surface,
- int client_id,
- const GPUCreateCommandBufferConfig& init_params,
- int route_id,
- const CreateCommandBufferCallback& callback) {
- TRACE_EVENT0("gpu", "GpuProcessHost::CreateViewCommandBuffer");
-
- DCHECK(CalledOnValidThread());
-
- if (!compositing_surface.is_null() &&
- Send(new GpuMsg_CreateViewCommandBuffer(compositing_surface, client_id,
- init_params, route_id))) {
- create_command_buffer_requests_.push(callback);
- } else {
- // Could distinguish here between compositing_surface being NULL
- // and Send failing, if desired.
- callback.Run(CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST);
- }
-}
-
void GpuProcessHost::CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
@@ -749,7 +749,9 @@ void GpuProcessHost::CreateGpuMemoryBuffer(
params.usage = usage;
params.client_id = client_id;
params.surface_handle =
- GpuSurfaceTracker::GetInstance()->GetSurfaceHandle(surface_id).handle;
+ surface_id
+ ? GpuSurfaceTracker::GetInstance()->GetSurfaceHandle(surface_id)
+ : gpu::kNullSurfaceHandle;
if (Send(new GpuMsg_CreateGpuMemoryBuffer(params))) {
create_gpu_memory_buffer_requests_.push(callback);
} else {
@@ -791,19 +793,6 @@ void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
Send(new GpuMsg_DestroyGpuMemoryBuffer(id, client_id, sync_token));
}
-#if defined(OS_CHROMEOS)
-void GpuProcessHost::CreateArcVideoAcceleratorChannel(
- const CreateArcVideoAcceleratorChannelCallback& callback) {
- DCHECK(CalledOnValidThread());
-
- if (Send(new GpuMsg_CreateArcVideoAcceleratorChannel())) {
- create_arc_video_accelerator_channel_requests_.push(callback);
- } else {
- callback.Run(IPC::ChannelHandle());
- }
-}
-#endif
-
void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", result);
initialized_ = result;
@@ -822,40 +811,26 @@ void GpuProcessHost::OnChannelEstablished(
if (channel_requests_.empty()) {
// This happens when GPU process is compromised.
RouteOnUIThread(GpuHostMsg_OnLogMessage(
- logging::LOG_WARNING,
- "WARNING",
+ logging::LOG_WARNING, "WARNING",
"Received a ChannelEstablished message but no requests in queue."));
return;
}
- EstablishChannelCallback callback = channel_requests_.front();
+ EstablishChannelRequest request = channel_requests_.front();
channel_requests_.pop();
// Currently if any of the GPU features are blacklisted, we don't establish a
// GPU channel.
if (!channel_handle.name.empty() &&
!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) {
- Send(new GpuMsg_CloseChannel(channel_handle));
- callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
- RouteOnUIThread(GpuHostMsg_OnLogMessage(
- logging::LOG_WARNING,
- "WARNING",
- "Hardware acceleration is unavailable."));
+ Send(new GpuMsg_CloseChannel(request.client_id));
+ request.callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
+ RouteOnUIThread(
+ GpuHostMsg_OnLogMessage(logging::LOG_WARNING, "WARNING",
+ "Hardware acceleration is unavailable."));
return;
}
- callback.Run(channel_handle, gpu_info_);
-}
-
-void GpuProcessHost::OnCommandBufferCreated(CreateCommandBufferResult result) {
- TRACE_EVENT0("gpu", "GpuProcessHost::OnCommandBufferCreated");
-
- if (create_command_buffer_requests_.empty())
- return;
-
- CreateCommandBufferCallback callback =
- create_command_buffer_requests_.front();
- create_command_buffer_requests_.pop();
- callback.Run(result);
+ request.callback.Run(channel_handle, gpu_info_);
}
void GpuProcessHost::OnGpuMemoryBufferCreated(
@@ -871,24 +846,6 @@ void GpuProcessHost::OnGpuMemoryBufferCreated(
callback.Run(handle);
}
-#if defined(OS_CHROMEOS)
-void GpuProcessHost::OnArcVideoAcceleratorChannelCreated(
- const IPC::ChannelHandle& handle) {
- if (create_arc_video_accelerator_channel_requests_.empty()) {
- RouteOnUIThread(
- GpuHostMsg_OnLogMessage(logging::LOG_WARNING, "WARNING",
- "Received a ArcVideoAcceleratorChannelCreated "
- "message but no requests in queue."));
- return;
- }
-
- CreateArcVideoAcceleratorChannelCallback callback =
- create_arc_video_accelerator_channel_requests_.front();
- create_arc_video_accelerator_channel_requests_.pop();
- callback.Run(handle);
-}
-#endif
-
void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) {
urls_with_live_offscreen_contexts_.insert(url);
}
@@ -935,7 +892,7 @@ void GpuProcessHost::OnDidDestroyOffscreenContext(const GURL& url) {
}
void GpuProcessHost::OnGpuMemoryUmaStatsReceived(
- const GPUMemoryUmaStats& stats) {
+ const gpu::GPUMemoryUmaStats& stats) {
TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryUmaStatsReceived");
uma_memory_stats_received_ = true;
uma_memory_stats_ = stats;
@@ -993,7 +950,8 @@ void GpuProcessHost::StopGpuProcess() {
Send(new GpuMsg_Finalize());
}
-bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
+bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id,
+ gpu::GpuPreferences* gpu_preferences) {
if (!(gpu_enabled_ &&
GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) &&
!hardware_gpu_enabled_) {
@@ -1027,6 +985,7 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
base::CommandLine* cmd_line = new base::CommandLine(exe_path);
#endif
+ BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line);
cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
@@ -1038,21 +997,21 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED)
cmd_line->AppendSwitch(switches::kDisableGpuSandbox);
+ // TODO(penghuang): Replace all GPU related switches with GpuPreferences.
+ // https://crbug.com/590825
// If you want a browser command-line switch passed to the GPU process
// you need to add it to |kSwitchNames| at the beginning of this file.
cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
arraysize(kSwitchNames));
cmd_line->CopySwitchesFrom(
- browser_command_line, switches::kGpuSwitches, switches::kNumGpuSwitches);
- cmd_line->CopySwitchesFrom(
browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost,
switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches);
GetContentClient()->browser()->AppendExtraCommandLineSwitches(
cmd_line, process_->GetData().id);
- GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line);
-
+ GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line,
+ gpu_preferences);
if (cmd_line->HasSwitch(switches::kUseGL)) {
swiftshader_rendering_ =
(cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader");
@@ -1081,16 +1040,9 @@ void GpuProcessHost::SendOutstandingReplies() {
valid_ = false;
// First send empty channel handles for all EstablishChannel requests.
while (!channel_requests_.empty()) {
- EstablishChannelCallback callback = channel_requests_.front();
+ EstablishChannelRequest request = channel_requests_.front();
channel_requests_.pop();
- callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
- }
-
- while (!create_command_buffer_requests_.empty()) {
- CreateCommandBufferCallback callback =
- create_command_buffer_requests_.front();
- create_command_buffer_requests_.pop();
- callback.Run(CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST);
+ request.callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
}
while (!create_gpu_memory_buffer_requests_.empty()) {
@@ -1099,15 +1051,6 @@ void GpuProcessHost::SendOutstandingReplies() {
create_gpu_memory_buffer_requests_.pop();
callback.Run(gfx::GpuMemoryBufferHandle());
}
-
-#if defined(OS_CHROMEOS)
- while (!create_arc_video_accelerator_channel_requests_.empty()) {
- CreateArcVideoAcceleratorChannelCallback callback =
- create_arc_video_accelerator_channel_requests_.front();
- create_arc_video_accelerator_channel_requests_.pop();
- callback.Run(IPC::ChannelHandle());
- }
-#endif
}
void GpuProcessHost::BlockLiveOffscreenContexts() {
diff --git a/chromium/content/browser/gpu/gpu_process_host.h b/chromium/content/browser/gpu/gpu_process_host.h
index 3fb0c006fe2..0b35c56b70e 100644
--- a/chromium/content/browser/gpu/gpu_process_host.h
+++ b/chromium/content/browser/gpu/gpu_process_host.h
@@ -15,23 +15,23 @@
#include "base/callback.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
-#include "content/common/gpu/gpu_memory_uma_stats.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
-#include "content/common/gpu/gpu_result_codes.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/public/browser/browser_child_process_host_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/config/gpu_info.h"
+#include "gpu/ipc/common/gpu_memory_uma_stats.h"
+#include "gpu/ipc/common/surface_handle.h"
#include "ipc/ipc_sender.h"
#include "ipc/message_filter.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
struct GPUCreateCommandBufferConfig;
@@ -41,6 +41,7 @@ struct ChannelHandle;
}
namespace gpu {
+struct GpuPreferences;
struct SyncToken;
}
@@ -53,7 +54,7 @@ class RenderWidgetHostViewFrameSubscriber;
class ShaderDiskCache;
typedef base::Thread* (*GpuMainThreadFactoryFunction)(
- const InProcessChildThreadParams&);
+ const InProcessChildThreadParams&, const gpu::GpuPreferences&);
class GpuProcessHost : public BrowserChildProcessHostDelegate,
public IPC::Sender,
@@ -68,17 +69,17 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
typedef base::Callback<void(const IPC::ChannelHandle&, const gpu::GPUInfo&)>
EstablishChannelCallback;
- typedef base::Callback<void(CreateCommandBufferResult)>
- CreateCommandBufferCallback;
+ struct EstablishChannelRequest {
+ EstablishChannelRequest();
+ EstablishChannelRequest(const EstablishChannelRequest& other);
+ ~EstablishChannelRequest();
+ int32_t client_id;
+ EstablishChannelCallback callback;
+ };
typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
CreateGpuMemoryBufferCallback;
-#if defined(OS_CHROMEOS)
- typedef base::Callback<void(const IPC::ChannelHandle&)>
- CreateArcVideoAcceleratorChannelCallback;
-#endif
-
static bool gpu_enabled() { return gpu_enabled_; }
static int gpu_crash_count() { return gpu_crash_count_; }
@@ -104,6 +105,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
CONTENT_EXPORT static void RegisterGpuMainThreadFactory(
GpuMainThreadFactoryFunction create);
+ // BrowserChildProcessHostDelegate implementation.
+ ServiceRegistry* GetServiceRegistry() override;
+
// Get the GPU process host for the GPU process with the given ID. Returns
// null if the process no longer exists.
static GpuProcessHost* FromID(int host_id);
@@ -121,20 +125,10 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void EstablishGpuChannel(int client_id,
uint64_t client_tracing_id,
bool preempts,
- bool preempted,
- bool allow_future_sync_points,
+ bool allow_view_command_buffers,
bool allow_real_time_streams,
const EstablishChannelCallback& callback);
- // Tells the GPU process to create a new command buffer that draws into the
- // given surface.
- void CreateViewCommandBuffer(
- const gfx::GLSurfaceHandle& compositing_surface,
- int client_id,
- const GPUCreateCommandBufferConfig& init_params,
- int route_id,
- const CreateCommandBufferCallback& callback);
-
// Tells the GPU process to create a new GPU memory buffer.
void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
const gfx::Size& size,
@@ -159,13 +153,6 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
int client_id,
const gpu::SyncToken& sync_token);
-#if defined(OS_CHROMEOS)
- // Tells the GPU process to create a new ipc channel for
- // ArcVideoAccelerator.
- void CreateArcVideoAcceleratorChannel(
- const CreateArcVideoAcceleratorChannelCallback& callback);
-#endif
-
// What kind of GPU process, e.g. sandboxed or unsandboxed.
GpuProcessKind kind();
@@ -175,10 +162,6 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Asks the GPU process to stop by itself.
void StopGpuProcess();
- void BeginFrameSubscription(
- int surface_id,
- base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber);
- void EndFrameSubscription(int surface_id);
void LoadedShader(const std::string& key, const std::string& data);
private:
@@ -201,28 +184,25 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void OnProcessLaunched() override;
void OnProcessLaunchFailed() override;
void OnProcessCrashed(int exit_code) override;
- ServiceRegistry* GetServiceRegistry() override;
// Message handlers.
void OnInitialized(bool result, const gpu::GPUInfo& gpu_info);
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle);
- void OnCommandBufferCreated(CreateCommandBufferResult result);
void OnGpuMemoryBufferCreated(const gfx::GpuMemoryBufferHandle& handle);
- void OnArcVideoAcceleratorChannelCreated(const IPC::ChannelHandle& handle);
void OnDidCreateOffscreenContext(const GURL& url);
void OnDidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason,
const GURL& url);
void OnDidDestroyOffscreenContext(const GURL& url);
- void OnGpuMemoryUmaStatsReceived(const GPUMemoryUmaStats& stats);
+ void OnGpuMemoryUmaStatsReceived(const gpu::GPUMemoryUmaStats& stats);
#if defined(OS_MACOSX)
void OnAcceleratedSurfaceBuffersSwapped(const IPC::Message& message);
#endif
#if defined(OS_WIN)
void OnAcceleratedSurfaceCreatedChildWindow(
- const gfx::PluginWindowHandle& parent_handle,
- const gfx::PluginWindowHandle& window_handle);
+ gpu::SurfaceHandle parent_handle,
+ gpu::SurfaceHandle window_handle);
#endif
void CreateChannelCache(int32_t client_id);
@@ -231,7 +211,8 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
const std::string& key,
const std::string& shader);
- bool LaunchGpuProcess(const std::string& channel_id);
+ bool LaunchGpuProcess(const std::string& channel_id,
+ gpu::GpuPreferences* gpu_preferences);
void SendOutstandingReplies();
@@ -247,21 +228,11 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// These are the channel requests that we have already sent to
// the GPU process, but haven't heard back about yet.
- std::queue<EstablishChannelCallback> channel_requests_;
-
- // The pending create command buffer requests we need to reply to.
- std::queue<CreateCommandBufferCallback> create_command_buffer_requests_;
+ std::queue<EstablishChannelRequest> channel_requests_;
// The pending create gpu memory buffer requests we need to reply to.
std::queue<CreateGpuMemoryBufferCallback> create_gpu_memory_buffer_requests_;
-#if defined(OS_CHROMEOS)
- // The pending create arc video accelerator channel requests we need to reply
- // to.
- std::queue<CreateArcVideoAcceleratorChannelCallback>
- create_arc_video_accelerator_channel_requests_;
-#endif
-
// Qeueud messages to send when the process launches.
std::queue<IPC::Message*> queued_messages_;
@@ -313,7 +284,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Statics kept around to send to UMA histograms on GPU process lost.
bool uma_memory_stats_received_;
- GPUMemoryUmaStats uma_memory_stats_;
+ gpu::GPUMemoryUmaStats uma_memory_stats_;
typedef std::map<int32_t, scoped_refptr<ShaderDiskCache>>
ClientIdToShaderCacheMap;
diff --git a/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc b/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
index f50db216e35..a7c5b20bd8d 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -22,10 +22,13 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu_host_messages.h"
#include "content/public/browser/browser_thread.h"
+#include "gpu/ipc/common/memory_stats.h"
+#include "ui/gfx/swap_result.h"
#if defined(OS_MACOSX)
+#include "content/common/accelerated_surface_buffers_swapped_params_mac.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#endif
@@ -184,8 +187,7 @@ bool GpuProcessHostUIShim::OnControlMessageReceived(
DCHECK(CalledOnValidThread());
IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
- IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
- OnLogMessage)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage, OnLogMessage)
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
OnAcceleratedSurfaceBuffersSwapped)
@@ -222,19 +224,19 @@ void GpuProcessHostUIShim::OnGraphicsInfoCollected(
#if defined(OS_MACOSX)
void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
+ const AcceleratedSurfaceBuffersSwappedParams& params) {
TRACE_EVENT0("browser",
"GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
if (!ui::LatencyInfo::Verify(params.latency_info,
"GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) {
-
TRACE_EVENT0("browser", "ui::LatencyInfo::Verify failed");
return;
}
// On Mac with delegated rendering, accelerated surfaces are not necessarily
// associated with a RenderWidgetHostViewBase.
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
+ BufferPresentedParams ack_params;
+ ack_params.surface_id = params.surface_id;
// If the frame was intended for an NSView that the gfx::AcceleratedWidget is
// no longer attached to, do not pass the frame along to the widget. Just ack
@@ -266,12 +268,12 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
content::ImageTransportFactory::GetInstance()->OnGpuSwapBuffersCompleted(
params.surface_id, params.latency_info, gfx::SwapResult::SWAP_ACK);
- Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
+ Send(new AcceleratedSurfaceMsg_BufferPresented(ack_params));
}
#endif
void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats) {
GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
video_memory_usage_stats);
}
diff --git a/chromium/content/browser/gpu/gpu_process_host_ui_shim.h b/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
index 251ca2e7654..c0661bf835c 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -21,15 +21,11 @@
#include "base/threading/non_thread_safe.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
-#include "content/common/message_router.h"
-#include "content/public/common/gpu_memory_stats.h"
#include "gpu/config/gpu_info.h"
+#include "gpu/ipc/common/memory_stats.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
-
-#if defined(OS_MACOSX)
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
-#endif
+#include "ipc/message_router.h"
namespace ui {
class LatencyInfo;
@@ -43,7 +39,14 @@ namespace IPC {
class Message;
}
+namespace gpu {
+struct VideoMemoryUsageStats;
+}
+
namespace content {
+#if defined(OS_MACOSX)
+struct AcceleratedSurfaceBuffersSwappedParams;
+#endif
void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg);
class GpuProcessHostUIShim : public IPC::Listener,
@@ -98,10 +101,10 @@ class GpuProcessHostUIShim : public IPC::Listener,
#if defined(OS_MACOSX)
void OnAcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
+ const AcceleratedSurfaceBuffersSwappedParams& params);
#endif
void OnVideoMemoryUsageStatsReceived(
- const GPUVideoMemoryUsageStats& video_memory_usage_stats);
+ const gpu::VideoMemoryUsageStats& video_memory_usage_stats);
void OnAddSubscription(int32_t process_id, unsigned int target);
void OnRemoveSubscription(int32_t process_id, unsigned int target);
diff --git a/chromium/content/browser/gpu/gpu_surface_tracker.cc b/chromium/content/browser/gpu/gpu_surface_tracker.cc
index bd4e91dc261..60aed74c507 100644
--- a/chromium/content/browser/gpu/gpu_surface_tracker.cc
+++ b/chromium/content/browser/gpu/gpu_surface_tracker.cc
@@ -9,17 +9,19 @@
#if defined(OS_ANDROID)
#include <android/native_window_jni.h>
+#include "content/browser/android/child_process_launcher_android.h"
+#include "ui/gl/android/scoped_java_surface.h"
#endif // defined(OS_ANDROID)
namespace content {
GpuSurfaceTracker::GpuSurfaceTracker()
: next_surface_id_(1) {
- GpuSurfaceLookup::InitInstance(this);
+ gpu::GpuSurfaceLookup::InitInstance(this);
}
GpuSurfaceTracker::~GpuSurfaceTracker() {
- GpuSurfaceLookup::InitInstance(NULL);
+ gpu::GpuSurfaceLookup::InitInstance(NULL);
}
GpuSurfaceTracker* GpuSurfaceTracker::GetInstance() {
@@ -30,7 +32,7 @@ int GpuSurfaceTracker::AddSurfaceForNativeWidget(
gfx::AcceleratedWidget widget) {
base::AutoLock lock(lock_);
int surface_id = next_surface_id_++;
- surface_map_[surface_id] = SurfaceInfo(widget, gfx::GLSurfaceHandle());
+ surface_map_[surface_id] = widget;
return surface_id;
}
@@ -40,20 +42,24 @@ void GpuSurfaceTracker::RemoveSurface(int surface_id) {
surface_map_.erase(surface_id);
}
-void GpuSurfaceTracker::SetSurfaceHandle(int surface_id,
- const gfx::GLSurfaceHandle& handle) {
+gpu::SurfaceHandle GpuSurfaceTracker::GetSurfaceHandle(int surface_id) {
+ DCHECK(surface_id);
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if DCHECK_IS_ON()
base::AutoLock lock(lock_);
DCHECK(surface_map_.find(surface_id) != surface_map_.end());
- SurfaceInfo& info = surface_map_[surface_id];
- info.handle = handle;
-}
-
-gfx::GLSurfaceHandle GpuSurfaceTracker::GetSurfaceHandle(int surface_id) {
+#endif
+ // On Mac and Android, we can't pass the AcceleratedWidget, which is
+ // process-local, so instead we pass the surface_id, so that we can look up
+ // the AcceleratedWidget on the GPU side or when we receive
+ // GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params.
+ return surface_id;
+#else
base::AutoLock lock(lock_);
SurfaceMap::iterator it = surface_map_.find(surface_id);
- if (it == surface_map_.end())
- return gfx::GLSurfaceHandle();
- return it->second.handle;
+ DCHECK(it != surface_map_.end());
+ return it->second;
+#endif
}
gfx::AcceleratedWidget GpuSurfaceTracker::AcquireNativeWidget(int surface_id) {
@@ -63,27 +69,22 @@ gfx::AcceleratedWidget GpuSurfaceTracker::AcquireNativeWidget(int surface_id) {
return gfx::kNullAcceleratedWidget;
#if defined(OS_ANDROID)
- if (it->second.native_widget != gfx::kNullAcceleratedWidget)
- ANativeWindow_acquire(it->second.native_widget);
+ if (it->second != gfx::kNullAcceleratedWidget)
+ ANativeWindow_acquire(it->second);
#endif // defined(OS_ANDROID)
- return it->second.native_widget;
+ return it->second;
}
+#if defined(OS_ANDROID)
+gfx::ScopedJavaSurface GpuSurfaceTracker::AcquireJavaSurface(int surface_id) {
+ return GetViewSurface(surface_id);
+}
+#endif
+
std::size_t GpuSurfaceTracker::GetSurfaceCount() {
base::AutoLock lock(lock_);
return surface_map_.size();
}
-GpuSurfaceTracker::SurfaceInfo::SurfaceInfo()
- : native_widget(gfx::kNullAcceleratedWidget) {}
-
-GpuSurfaceTracker::SurfaceInfo::SurfaceInfo(
- const gfx::AcceleratedWidget& native_widget,
- const gfx::GLSurfaceHandle& handle)
- : native_widget(native_widget), handle(handle) {}
-
-GpuSurfaceTracker::SurfaceInfo::~SurfaceInfo() { }
-
-
} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_surface_tracker.h b/chromium/content/browser/gpu/gpu_surface_tracker.h
index 386eeeae7c4..dbaec68be5f 100644
--- a/chromium/content/browser/gpu/gpu_surface_tracker.h
+++ b/chromium/content/browser/gpu/gpu_surface_tracker.h
@@ -14,7 +14,8 @@
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
-#include "content/common/gpu/gpu_surface_lookup.h"
+#include "gpu/ipc/common/gpu_surface_lookup.h"
+#include "gpu/ipc/common/surface_handle.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
@@ -29,12 +30,16 @@ namespace content {
// Note: The ID can exist before the actual native handle for the surface is
// created, for example to allow giving a reference to it to a renderer, so that
// it is unamibiguously identified.
-class CONTENT_EXPORT GpuSurfaceTracker : public GpuSurfaceLookup {
+class CONTENT_EXPORT GpuSurfaceTracker : public gpu::GpuSurfaceLookup {
public:
// GpuSurfaceLookup implementation:
// Returns the native widget associated with a given surface_id.
gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override;
+#if defined(OS_ANDROID)
+ gfx::ScopedJavaSurface AcquireJavaSurface(int surface_id) override;
+#endif
+
// Gets the global instance of the surface tracker.
static GpuSurfaceTracker* Get() { return GetInstance(); }
@@ -44,13 +49,9 @@ class CONTENT_EXPORT GpuSurfaceTracker : public GpuSurfaceLookup {
// Removes a given existing surface.
void RemoveSurface(int surface_id);
- // Sets the native handle for the given surface.
- // Note: This is an O(log N) lookup.
- void SetSurfaceHandle(int surface_id, const gfx::GLSurfaceHandle& handle);
-
// Gets the native handle for the given surface.
// Note: This is an O(log N) lookup.
- gfx::GLSurfaceHandle GetSurfaceHandle(int surface_id);
+ gpu::SurfaceHandle GetSurfaceHandle(int surface_id);
// Returns the number of surfaces currently registered with the tracker.
std::size_t GetSurfaceCount();
@@ -60,15 +61,7 @@ class CONTENT_EXPORT GpuSurfaceTracker : public GpuSurfaceLookup {
static GpuSurfaceTracker* GetInstance();
private:
- struct SurfaceInfo {
- SurfaceInfo();
- SurfaceInfo(const gfx::AcceleratedWidget& native_widget,
- const gfx::GLSurfaceHandle& handle);
- ~SurfaceInfo();
- gfx::AcceleratedWidget native_widget;
- gfx::GLSurfaceHandle handle;
- };
- typedef std::map<int, SurfaceInfo> SurfaceMap;
+ typedef std::map<int, gfx::AcceleratedWidget> SurfaceMap;
friend struct base::DefaultSingletonTraits<GpuSurfaceTracker>;
diff --git a/chromium/content/browser/histogram_controller.cc b/chromium/content/browser/histogram_controller.cc
index efefa964575..052bd7a5bd7 100644
--- a/chromium/content/browser/histogram_controller.cc
+++ b/chromium/content/browser/histogram_controller.cc
@@ -75,8 +75,7 @@ void HistogramController::GetHistogramDataFromChildProcesses(
for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
const ChildProcessData& data = iter.GetData();
int type = data.process_type;
- if (type != PROCESS_TYPE_PLUGIN &&
- type != PROCESS_TYPE_GPU &&
+ if (type != PROCESS_TYPE_GPU &&
type != PROCESS_TYPE_PPAPI_PLUGIN &&
type != PROCESS_TYPE_PPAPI_BROKER) {
continue;
@@ -90,8 +89,10 @@ void HistogramController::GetHistogramDataFromChildProcesses(
continue;
++pending_processes;
- if (!iter.Send(new ChildProcessMsg_GetChildHistogramData(sequence_number)))
+ if (!iter.Send(new ChildProcessMsg_GetChildNonPersistentHistogramData(
+ sequence_number))) {
--pending_processes;
+ }
}
BrowserThread::PostTask(
@@ -113,7 +114,8 @@ void HistogramController::GetHistogramData(int sequence_number) {
!it.IsAtEnd(); it.Advance()) {
++pending_processes;
if (!it.GetCurrentValue()->Send(
- new ChildProcessMsg_GetChildHistogramData(sequence_number))) {
+ new ChildProcessMsg_GetChildNonPersistentHistogramData(
+ sequence_number))) {
--pending_processes;
}
}
diff --git a/chromium/content/browser/host_zoom_map_impl.cc b/chromium/content/browser/host_zoom_map_impl.cc
index cb394f81cbe..298a66a8fc4 100644
--- a/chromium/content/browser/host_zoom_map_impl.cc
+++ b/chromium/content/browser/host_zoom_map_impl.cc
@@ -24,7 +24,7 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/url_constants.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
index e3816d4d37a..71ad4e1c102 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -18,10 +18,12 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/indexed_db/indexed_db_blob_info.h"
#include "content/browser/indexed_db/indexed_db_class_factory.h"
+#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/indexed_db_metadata.h"
@@ -88,20 +90,8 @@ static std::string ComputeOriginIdentifier(const GURL& origin_url) {
return storage::GetIdentifierFromOrigin(origin_url) + "@1";
}
-static base::FilePath ComputeFileName(const GURL& origin_url) {
- return base::FilePath()
- .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
- .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
-}
-
-static base::FilePath ComputeBlobPath(const GURL& origin_url) {
- return base::FilePath()
- .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
- .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
-}
-
-static base::FilePath ComputeCorruptionFileName(const GURL& origin_url) {
- return ComputeFileName(origin_url)
+static FilePath ComputeCorruptionFileName(const GURL& origin_url) {
+ return IndexedDBContextImpl::GetLevelDBFileName(origin_url)
.Append(FILE_PATH_LITERAL("corruption_info.json"));
}
@@ -413,11 +403,10 @@ WARN_UNUSED_RESULT leveldb::Status IndexedDBBackingStore::SetUpMetadata() {
INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
return InternalInconsistencyStatus();
}
- std::string int_version_key = DatabaseMetaDataKey::Encode(
- database_id, DatabaseMetaDataKey::USER_INT_VERSION);
- PutVarInt(transaction.get(),
- int_version_key,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ std::string version_key = DatabaseMetaDataKey::Encode(
+ database_id, DatabaseMetaDataKey::USER_VERSION);
+ PutVarInt(transaction.get(), version_key,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
}
}
if (s.ok() && db_schema_version < 2) {
@@ -798,6 +787,8 @@ IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
+IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions(
+ const CursorOptions& other) = default;
IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
// Values match entries in tools/metrics/histograms/histograms.xml
@@ -908,7 +899,7 @@ leveldb::Status IndexedDBBackingStore::DestroyBackingStore(
const base::FilePath& path_base,
const GURL& origin_url) {
const base::FilePath file_path =
- path_base.Append(ComputeFileName(origin_url));
+ path_base.Append(IndexedDBContextImpl::GetLevelDBFileName(origin_url));
DefaultLevelDBFactory leveldb_factory;
return leveldb_factory.DestroyLevelDB(file_path);
}
@@ -1012,10 +1003,10 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
return scoped_refptr<IndexedDBBackingStore>();
}
- const base::FilePath file_path =
- path_base.Append(ComputeFileName(origin_url));
- const base::FilePath blob_path =
- path_base.Append(ComputeBlobPath(origin_url));
+ const FilePath file_path =
+ path_base.Append(IndexedDBContextImpl::GetLevelDBFileName(origin_url));
+ const FilePath blob_path =
+ path_base.Append(IndexedDBContextImpl::GetBlobStoreFileName(origin_url));
if (IsPathTooLong(file_path)) {
*status = leveldb::Status::IOError("File path too long");
@@ -1105,6 +1096,11 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
origin_url);
}
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->RegisterDumpProviderWithSequencedTaskRunner(
+ db.get(), "IndexedDBBackingStore", task_runner,
+ base::trace_event::MemoryDumpProvider::Options());
+
scoped_refptr<IndexedDBBackingStore> backing_store =
Create(indexed_db_factory, origin_url, blob_path, request_context,
std::move(db), std::move(comparator), task_runner, status);
@@ -1149,6 +1145,10 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
return scoped_refptr<IndexedDBBackingStore>();
}
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url);
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->RegisterDumpProviderWithSequencedTaskRunner(
+ db.get(), "IndexedDBBackingStore", task_runner,
+ base::trace_event::MemoryDumpProvider::Options());
return Create(NULL /* indexed_db_factory */, origin_url, base::FilePath(),
NULL /* request_context */, std::move(db),
@@ -1218,19 +1218,18 @@ std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
// Look up version by id.
bool found = false;
- int64_t database_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+ int64_t database_version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
*s = GetVarInt(db_.get(),
DatabaseMetaDataKey::Encode(
- database_id, DatabaseMetaDataKey::USER_INT_VERSION),
- &database_version,
- &found);
+ database_id, DatabaseMetaDataKey::USER_VERSION),
+ &database_version, &found);
if (!s->ok() || !found) {
INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES);
continue;
}
// Ignore stale metadata from failed initial opens.
- if (database_version != IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
+ if (database_version != IndexedDBDatabaseMetadata::DEFAULT_VERSION)
found_names.push_back(database_name_key.database_name());
}
@@ -1255,11 +1254,9 @@ leveldb::Status IndexedDBBackingStore::GetIDBDatabaseMetaData(
if (!*found)
return leveldb::Status::OK();
- s = GetString(db_.get(),
- DatabaseMetaDataKey::Encode(metadata->id,
- DatabaseMetaDataKey::USER_VERSION),
- &metadata->version,
- found);
+ s = GetVarInt(db_.get(), DatabaseMetaDataKey::Encode(
+ metadata->id, DatabaseMetaDataKey::USER_VERSION),
+ &metadata->version, found);
if (!s.ok()) {
INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
return s;
@@ -1269,22 +1266,8 @@ leveldb::Status IndexedDBBackingStore::GetIDBDatabaseMetaData(
return InternalInconsistencyStatus();
}
- s = GetVarInt(db_.get(),
- DatabaseMetaDataKey::Encode(
- metadata->id, DatabaseMetaDataKey::USER_INT_VERSION),
- &metadata->int_version,
- found);
- if (!s.ok()) {
- INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
- return s;
- }
- if (!*found) {
- INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
- return InternalInconsistencyStatus();
- }
-
- if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
- metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
+ if (metadata->version == IndexedDBDatabaseMetadata::DEFAULT_VERSION)
+ metadata->version = IndexedDBDatabaseMetadata::NO_VERSION;
s = GetMaxObjectStoreId(
db_.get(), metadata->id, &metadata->max_object_store_id);
@@ -1343,8 +1326,7 @@ WARN_UNUSED_RESULT static leveldb::Status GetNewDatabaseId(
leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
const base::string16& name,
- const base::string16& version,
- int64_t int_version,
+ int64_t version,
int64_t* row_id) {
// TODO(jsbell): Don't persist metadata if open fails. http://crbug.com/395472
scoped_refptr<LevelDBTransaction> transaction =
@@ -1355,20 +1337,15 @@ leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
return s;
DCHECK_GE(*row_id, 0);
- if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
- int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+ if (version == IndexedDBDatabaseMetadata::NO_VERSION)
+ version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
PutInt(transaction.get(),
DatabaseNameKey::Encode(origin_identifier_, name),
*row_id);
- PutString(
- transaction.get(),
- DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION),
- version);
- PutVarInt(transaction.get(),
- DatabaseMetaDataKey::Encode(*row_id,
- DatabaseMetaDataKey::USER_INT_VERSION),
- int_version);
+ PutVarInt(transaction.get(), DatabaseMetaDataKey::Encode(
+ *row_id, DatabaseMetaDataKey::USER_VERSION),
+ version);
PutVarInt(
transaction.get(),
DatabaseMetaDataKey::Encode(
@@ -1384,14 +1361,14 @@ leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
IndexedDBBackingStore::Transaction* transaction,
int64_t row_id,
- int64_t int_version) {
- if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
- int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
- DCHECK_GE(int_version, 0) << "int_version was " << int_version;
- PutVarInt(transaction->transaction(),
- DatabaseMetaDataKey::Encode(row_id,
- DatabaseMetaDataKey::USER_INT_VERSION),
- int_version);
+ int64_t version) {
+ if (version == IndexedDBDatabaseMetadata::NO_VERSION)
+ version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
+ DCHECK_GE(version, 0) << "version was " << version;
+ PutVarInt(
+ transaction->transaction(),
+ DatabaseMetaDataKey::Encode(row_id, DatabaseMetaDataKey::USER_VERSION),
+ version);
return true;
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store.h b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
index 1ba22603a36..f1fecbdf193 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
@@ -287,6 +287,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
struct CursorOptions {
CursorOptions();
+ CursorOptions(const CursorOptions& other);
~CursorOptions();
int64_t database_id;
int64_t object_store_id;
@@ -408,15 +409,13 @@ class CONTENT_EXPORT IndexedDBBackingStore
const base::string16& name,
IndexedDBDatabaseMetadata* metadata,
bool* success) WARN_UNUSED_RESULT;
- virtual leveldb::Status CreateIDBDatabaseMetaData(
- const base::string16& name,
- const base::string16& version,
- int64_t int_version,
- int64_t* row_id);
+ virtual leveldb::Status CreateIDBDatabaseMetaData(const base::string16& name,
+ int64_t version,
+ int64_t* row_id);
virtual bool UpdateIDBDatabaseIntVersion(
IndexedDBBackingStore::Transaction* transaction,
int64_t row_id,
- int64_t int_version);
+ int64_t version);
virtual leveldb::Status DeleteDatabase(const base::string16& name);
// Assumes caller has already closed the backing store.
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 93d281e036a..55acfa0151c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -22,6 +22,7 @@
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/browser/indexed_db/leveldb/leveldb_factory.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/url_request_test_util.h"
@@ -235,12 +236,12 @@ class IndexedDBBackingStoreTest : public testing::Test {
const GURL origin("http://localhost:81");
task_runner_ = new base::TestSimpleTaskRunner();
special_storage_policy_ = new MockSpecialStoragePolicy();
+ quota_manager_proxy_ = new MockQuotaManagerProxy(nullptr, nullptr);
special_storage_policy_->SetAllUnlimited(true);
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- idb_context_ = new IndexedDBContextImpl(temp_dir_.path(),
- special_storage_policy_.get(),
- NULL,
- task_runner_.get());
+ idb_context_ = new IndexedDBContextImpl(
+ temp_dir_.path(), special_storage_policy_.get(),
+ quota_manager_proxy_.get(), task_runner_.get());
idb_factory_ = new TestIDBFactory(idb_context_.get());
backing_store_ =
idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_);
@@ -268,6 +269,10 @@ class IndexedDBBackingStoreTest : public testing::Test {
m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
}
+ void TearDown() override {
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ }
+
// This just checks the data that survive getting stored and recalled, e.g.
// the file path and UUID will change and thus aren't verified.
bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
@@ -345,6 +350,7 @@ class IndexedDBBackingStoreTest : public testing::Test {
base::ScopedTempDir temp_dir_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
scoped_refptr<IndexedDBContextImpl> idb_context_;
scoped_refptr<TestIDBFactory> idb_factory_;
net::TestURLRequestContext url_request_context_;
@@ -935,8 +941,7 @@ TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
const base::string16 database_name(ASCIIToUTF16("db1"));
int64_t database_id;
- const base::string16 version(ASCIIToUTF16("old_string_version"));
- const int64_t int_version = 9;
+ const int64_t version = 9;
const int64_t object_store_id = 99;
const base::string16 object_store_name(ASCIIToUTF16("object_store1"));
@@ -952,7 +957,7 @@ TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
{
leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
- database_name, version, int_version, &database_id);
+ database_name, version, &database_id);
EXPECT_TRUE(s.ok());
EXPECT_GT(database_id, 0);
@@ -996,7 +1001,6 @@ TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
// database.name is not filled in by the implementation.
EXPECT_EQ(version, database.version);
- EXPECT_EQ(int_version, database.int_version);
EXPECT_EQ(database_id, database.id);
s = backing_store_->GetObjectStores(database.id, &database.object_stores);
@@ -1019,25 +1023,22 @@ TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
}
TEST_F(IndexedDBBackingStoreTest, GetDatabaseNames) {
- const base::string16 string_version(ASCIIToUTF16("string_version"));
-
const base::string16 db1_name(ASCIIToUTF16("db1"));
const int64_t db1_version = 1LL;
int64_t db1_id;
- // Database records with DEFAULT_INT_VERSION represent stale data,
+ // Database records with DEFAULT_VERSION represent stale data,
// and should not be enumerated.
const base::string16 db2_name(ASCIIToUTF16("db2"));
- const int64_t db2_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+ const int64_t db2_version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
int64_t db2_id;
- leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
- db1_name, string_version, db1_version, &db1_id);
+ leveldb::Status s =
+ backing_store_->CreateIDBDatabaseMetaData(db1_name, db1_version, &db1_id);
EXPECT_TRUE(s.ok());
EXPECT_GT(db1_id, 0LL);
- s = backing_store_->CreateIDBDatabaseMetaData(
- db2_name, string_version, db2_version, &db2_id);
+ s = backing_store_->CreateIDBDatabaseMetaData(db2_name, db2_version, &db2_id);
EXPECT_TRUE(s.ok());
EXPECT_GT(db2_id, db1_id);
diff --git a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
index e659d96a0db..9a53bc6da05 100644
--- a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -201,7 +201,13 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
true /* incognito */);
}
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
+// crbug.com/513787
+#if defined(ANDROID)
+#define MAYBE_CursorPrefetch DISABLED_CursorPrefetch
+#else
+#define MAYBE_CursorPrefetch CursorPrefetch
+#endif
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, MAYBE_CursorPrefetch) {
SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
}
@@ -461,14 +467,9 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed, DISABLED_BlobDidAck) {
EXPECT_EQ(0UL, blob_context->context()->blob_count());
}
-// Very flaky on Linux. See crbug.com/459835.
-#if defined(OS_LINUX)
-#define MAYBE_BlobDidAckPrefetch DISABLED_BlobDidAckPrefetch
-#else
-#define MAYBE_BlobDidAckPrefetch BlobDidAckPrefetch
-#endif
+// Flaky. See crbug.com/459835.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
- MAYBE_BlobDidAckPrefetch) {
+ DISABLED_BlobDidAckPrefetch) {
SimpleTest(GetTestUrl("indexeddb", "blob_did_ack_prefetch.html"));
// Wait for idle so that the blob ack has time to be received/processed by
// the browser process.
@@ -632,12 +633,14 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
std::string key = net::UnescapeURLComponent(
escaped_key,
net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
- net::UnescapeRule::URL_SPECIAL_CHARS);
+ net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
std::string value = net::UnescapeURLComponent(
escaped_value,
net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
- net::UnescapeRule::URL_SPECIAL_CHARS);
+ net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
if (key == "method")
fail_method = value;
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
index 6a5ca73916e..a695c4b89c5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -251,9 +251,8 @@ static bool CreateAllBlobs(
return false;
for (i = 0; i < blob_info.size(); ++i) {
(*blob_or_file_info)[i].uuid =
- CreateBlobData(blob_info[i],
- dispatcher_host,
- dispatcher_host->Context()->TaskRunner());
+ CreateBlobData(blob_info[i], dispatcher_host,
+ dispatcher_host->context()->TaskRunner());
}
return true;
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
index 582f16fc6d7..cbe6016c049 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -116,9 +116,7 @@ IndexedDBContextImpl::IndexedDBContextImpl(
IDB_TRACE("init");
if (!data_path.empty())
data_path_ = data_path.Append(kIndexedDBDirectory);
- if (quota_manager_proxy) {
- quota_manager_proxy->RegisterClient(new IndexedDBQuotaClient(this));
- }
+ quota_manager_proxy->RegisterClient(new IndexedDBQuotaClient(this));
}
IndexedDBFactory* IndexedDBContextImpl::GetIDBFactory() {
@@ -138,6 +136,12 @@ std::vector<GURL> IndexedDBContextImpl::GetAllOrigins() {
return std::vector<GURL>(origins_set->begin(), origins_set->end());
}
+bool IndexedDBContextImpl::HasOrigin(const GURL& origin) {
+ DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
+ std::set<GURL>* set = GetOriginSet();
+ return set->find(origin) != set->end();
+}
+
std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
std::vector<GURL> origins = GetAllOrigins();
@@ -277,9 +281,8 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
int IndexedDBContextImpl::GetOriginBlobFileCount(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
int count = 0;
- base::FileEnumerator file_enumerator(
- GetBlobPath(storage::GetIdentifierFromOrigin(origin_url)), true,
- base::FileEnumerator::FILES);
+ base::FileEnumerator file_enumerator(GetBlobStorePath(origin_url), true,
+ base::FileEnumerator::FILES);
for (base::FilePath file_path = file_enumerator.Next(); !file_path.empty();
file_path = file_enumerator.Next()) {
count++;
@@ -289,7 +292,7 @@ int IndexedDBContextImpl::GetOriginBlobFileCount(const GURL& origin_url) {
int64_t IndexedDBContextImpl::GetOriginDiskUsage(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return 0;
EnsureDiskUsageCacheInitialized(origin_url);
return origin_size_map_[origin_url];
@@ -297,7 +300,7 @@ int64_t IndexedDBContextImpl::GetOriginDiskUsage(const GURL& origin_url) {
base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return base::Time();
base::FilePath idb_directory = GetLevelDBPath(origin_url);
base::File::Info file_info;
@@ -309,7 +312,7 @@ base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) {
void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
ForceClose(origin_url, FORCE_CLOSE_DELETE_ORIGIN);
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return;
base::FilePath idb_directory = GetLevelDBPath(origin_url);
@@ -325,13 +328,11 @@ void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
const bool kNonRecursive = false;
base::DeleteFile(idb_directory, kNonRecursive);
}
- base::DeleteFile(GetBlobPath(storage::GetIdentifierFromOrigin(origin_url)),
- true /* recursive */);
+ base::DeleteFile(GetBlobStorePath(origin_url), true /* recursive */);
QueryDiskAndUpdateQuotaUsage(origin_url);
if (s.ok()) {
RemoveFromOriginSet(origin_url);
origin_size_map_.erase(origin_url);
- space_available_map_.erase(origin_url);
}
}
@@ -339,14 +340,13 @@ void IndexedDBContextImpl::CopyOriginData(const GURL& origin_url,
IndexedDBContext* dest_context) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return;
IndexedDBContextImpl* dest_context_impl =
static_cast<IndexedDBContextImpl*>(dest_context);
ForceClose(origin_url, FORCE_CLOSE_COPY_ORIGIN);
- std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
// Make sure we're not about to delete our own database.
CHECK_NE(dest_context_impl->data_path().value(), data_path().value());
@@ -375,7 +375,7 @@ void IndexedDBContextImpl::ForceClose(const GURL origin_url,
reason,
FORCE_CLOSE_REASON_MAX);
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return;
if (factory_.get())
@@ -385,7 +385,7 @@ void IndexedDBContextImpl::ForceClose(const GURL origin_url,
size_t IndexedDBContextImpl::GetConnectionCount(const GURL& origin_url) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (data_path_.empty() || !IsInOriginSet(origin_url))
+ if (data_path_.empty() || !HasOrigin(origin_url))
return 0;
if (!factory_.get())
@@ -394,24 +394,17 @@ size_t IndexedDBContextImpl::GetConnectionCount(const GURL& origin_url) {
return factory_->GetConnectionCount(origin_url);
}
-base::FilePath IndexedDBContextImpl::GetLevelDBPath(
- const GURL& origin_url) const {
- std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
- return GetLevelDBPath(origin_id);
-}
-
std::vector<base::FilePath> IndexedDBContextImpl::GetStoragePaths(
const GURL& origin_url) const {
- std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
std::vector<base::FilePath> paths;
- paths.push_back(GetLevelDBPath(origin_id));
- paths.push_back(GetBlobPath(origin_id));
+ paths.push_back(GetLevelDBPath(origin_url));
+ paths.push_back(GetBlobStorePath(origin_url));
return paths;
}
base::FilePath IndexedDBContextImpl::GetFilePathForTesting(
- const std::string& origin_id) const {
- return GetLevelDBPath(origin_id);
+ const GURL& origin_url) const {
+ return GetLevelDBPath(origin_url);
}
void IndexedDBContextImpl::SetTaskRunnerForTesting(
@@ -423,30 +416,23 @@ void IndexedDBContextImpl::SetTaskRunnerForTesting(
void IndexedDBContextImpl::ConnectionOpened(const GURL& origin_url,
IndexedDBConnection* connection) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (quota_manager_proxy()) {
- quota_manager_proxy()->NotifyStorageAccessed(
- storage::QuotaClient::kIndexedDatabase,
- origin_url,
- storage::kStorageTypeTemporary);
- }
+ quota_manager_proxy()->NotifyStorageAccessed(
+ storage::QuotaClient::kIndexedDatabase, origin_url,
+ storage::kStorageTypeTemporary);
if (AddToOriginSet(origin_url)) {
// A newly created db, notify the quota system.
QueryDiskAndUpdateQuotaUsage(origin_url);
} else {
EnsureDiskUsageCacheInitialized(origin_url);
}
- QueryAvailableQuota(origin_url);
}
void IndexedDBContextImpl::ConnectionClosed(const GURL& origin_url,
IndexedDBConnection* connection) {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (quota_manager_proxy()) {
- quota_manager_proxy()->NotifyStorageAccessed(
- storage::QuotaClient::kIndexedDatabase,
- origin_url,
- storage::kStorageTypeTemporary);
- }
+ quota_manager_proxy()->NotifyStorageAccessed(
+ storage::QuotaClient::kIndexedDatabase, origin_url,
+ storage::kStorageTypeTemporary);
if (factory_.get() && factory_->GetConnectionCount(origin_url) == 0)
QueryDiskAndUpdateQuotaUsage(origin_url);
}
@@ -454,32 +440,11 @@ void IndexedDBContextImpl::ConnectionClosed(const GURL& origin_url,
void IndexedDBContextImpl::TransactionComplete(const GURL& origin_url) {
DCHECK(!factory_.get() || factory_->GetConnectionCount(origin_url) > 0);
QueryDiskAndUpdateQuotaUsage(origin_url);
- QueryAvailableQuota(origin_url);
}
void IndexedDBContextImpl::DatabaseDeleted(const GURL& origin_url) {
AddToOriginSet(origin_url);
QueryDiskAndUpdateQuotaUsage(origin_url);
- QueryAvailableQuota(origin_url);
-}
-
-bool IndexedDBContextImpl::WouldBeOverQuota(const GURL& origin_url,
- int64_t additional_bytes) {
- if (space_available_map_.find(origin_url) == space_available_map_.end()) {
- // We haven't heard back from the QuotaManager yet, just let it through.
- return false;
- }
- bool over_quota = additional_bytes > space_available_map_[origin_url];
- return over_quota;
-}
-
-bool IndexedDBContextImpl::IsOverQuota(const GURL& origin_url) {
- const int kOneAdditionalByte = 1;
- return WouldBeOverQuota(origin_url, kOneAdditionalByte);
-}
-
-storage::QuotaManagerProxy* IndexedDBContextImpl::quota_manager_proxy() {
- return quota_manager_proxy_.get();
}
IndexedDBContextImpl::~IndexedDBContextImpl() {
@@ -509,18 +474,36 @@ IndexedDBContextImpl::~IndexedDBContextImpl() {
&ClearSessionOnlyOrigins, data_path_, special_storage_policy_));
}
-base::FilePath IndexedDBContextImpl::GetBlobPath(
- const std::string& origin_id) const {
- DCHECK(!data_path_.empty());
- return data_path_.AppendASCII(origin_id).AddExtension(kIndexedDBExtension)
+// static
+base::FilePath IndexedDBContextImpl::GetBlobStoreFileName(
+ const GURL& origin_url) {
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
+ return base::FilePath()
+ .AppendASCII(origin_id)
+ .AddExtension(kIndexedDBExtension)
.AddExtension(kBlobExtension);
}
+// static
+base::FilePath IndexedDBContextImpl::GetLevelDBFileName(
+ const GURL& origin_url) {
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
+ return base::FilePath()
+ .AppendASCII(origin_id)
+ .AddExtension(kIndexedDBExtension)
+ .AddExtension(kLevelDBExtension);
+}
+
+base::FilePath IndexedDBContextImpl::GetBlobStorePath(
+ const GURL& origin_url) const {
+ DCHECK(!data_path_.empty());
+ return data_path_.Append(GetBlobStoreFileName(origin_url));
+}
+
base::FilePath IndexedDBContextImpl::GetLevelDBPath(
- const std::string& origin_id) const {
+ const GURL& origin_url) const {
DCHECK(!data_path_.empty());
- return data_path_.AppendASCII(origin_id).AddExtension(kIndexedDBExtension)
- .AddExtension(kLevelDBExtension);
+ return data_path_.Append(GetLevelDBFileName(origin_url));
}
int64_t IndexedDBContextImpl::ReadUsageFromDisk(const GURL& origin_url) const {
@@ -545,69 +528,12 @@ void IndexedDBContextImpl::QueryDiskAndUpdateQuotaUsage(
int64_t difference = current_disk_usage - former_disk_usage;
if (difference) {
origin_size_map_[origin_url] = current_disk_usage;
- // quota_manager_proxy() is NULL in unit tests.
- if (quota_manager_proxy()) {
- quota_manager_proxy()->NotifyStorageModified(
- storage::QuotaClient::kIndexedDatabase,
- origin_url,
- storage::kStorageTypeTemporary,
- difference);
- }
+ quota_manager_proxy()->NotifyStorageModified(
+ storage::QuotaClient::kIndexedDatabase, origin_url,
+ storage::kStorageTypeTemporary, difference);
}
}
-void IndexedDBContextImpl::GotUsageAndQuota(const GURL& origin_url,
- storage::QuotaStatusCode status,
- int64_t usage,
- int64_t quota) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(status == storage::kQuotaStatusOk ||
- status == storage::kQuotaErrorAbort)
- << "status was " << status;
- if (status == storage::kQuotaErrorAbort) {
- // We seem to no longer care to wait around for the answer.
- return;
- }
- TaskRunner()->PostTask(FROM_HERE,
- base::Bind(&IndexedDBContextImpl::GotUpdatedQuota,
- this,
- origin_url,
- usage,
- quota));
-}
-
-void IndexedDBContextImpl::GotUpdatedQuota(const GURL& origin_url,
- int64_t usage,
- int64_t quota) {
- DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- space_available_map_[origin_url] = quota - usage;
-}
-
-void IndexedDBContextImpl::QueryAvailableQuota(const GURL& origin_url) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (quota_manager_proxy()) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &IndexedDBContextImpl::QueryAvailableQuota, this, origin_url));
- }
- return;
- }
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!quota_manager_proxy() || !quota_manager_proxy()->quota_manager())
- return;
-
- // crbug.com/349708
- TRACE_EVENT0("io", "IndexedDBContextImpl::QueryAvailableQuota");
-
- quota_manager_proxy()->quota_manager()->GetUsageAndQuota(
- origin_url,
- storage::kStorageTypeTemporary,
- base::Bind(&IndexedDBContextImpl::GotUsageAndQuota, this, origin_url));
-}
-
std::set<GURL>* IndexedDBContextImpl::GetOriginSet() {
if (!origin_set_) {
std::vector<GURL> origins;
@@ -620,7 +546,6 @@ std::set<GURL>* IndexedDBContextImpl::GetOriginSet() {
void IndexedDBContextImpl::ResetCaches() {
origin_set_.reset();
origin_size_map_.clear();
- space_available_map_.clear();
}
base::SequencedTaskRunner* IndexedDBContextImpl::TaskRunner() const {
diff --git a/chromium/content/browser/indexed_db/indexed_db_context_impl.h b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
index d175ce46a65..608e0f23394 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
@@ -74,8 +74,7 @@ class CONTENT_EXPORT IndexedDBContextImpl
void DeleteForOrigin(const GURL& origin_url) override;
void CopyOriginData(const GURL& origin_url,
IndexedDBContext* dest_context) override;
- base::FilePath GetFilePathForTesting(
- const std::string& origin_id) const override;
+ base::FilePath GetFilePathForTesting(const GURL& origin_url) const override;
void SetTaskRunnerForTesting(base::SequencedTaskRunner* task_runner) override;
// Methods called by IndexedDBDispatcherHost for quota support.
@@ -83,13 +82,20 @@ class CONTENT_EXPORT IndexedDBContextImpl
void ConnectionClosed(const GURL& origin_url, IndexedDBConnection* db);
void TransactionComplete(const GURL& origin_url);
void DatabaseDeleted(const GURL& origin_url);
- bool WouldBeOverQuota(const GURL& origin_url, int64_t additional_bytes);
- bool IsOverQuota(const GURL& origin_url);
- storage::QuotaManagerProxy* quota_manager_proxy();
+ static base::FilePath GetBlobStoreFileName(const GURL& origin_url);
+ static base::FilePath GetLevelDBFileName(const GURL& origin_url);
+ // Will be null in unit tests.
+ storage::QuotaManagerProxy* quota_manager_proxy() const {
+ return quota_manager_proxy_.get();
+ }
+
+ // Returns a list of all origins with backing stores.
std::vector<GURL> GetAllOrigins();
- base::Time GetOriginLastModified(const GURL& origin_url);
+ bool HasOrigin(const GURL& origin);
+
+ // Used by IndexedDBInternalsUI to populate internals page.
base::ListValue* GetAllOriginsDetails();
// ForceClose takes a value rather than a reference since it may release the
@@ -100,10 +106,6 @@ class CONTENT_EXPORT IndexedDBContextImpl
std::vector<base::FilePath> GetStoragePaths(const GURL& origin_url) const;
base::FilePath data_path() const { return data_path_; }
- bool IsInOriginSet(const GURL& origin_url) {
- std::set<GURL>* set = GetOriginSet();
- return set->find(origin_url) != set->end();
- }
size_t GetConnectionCount(const GURL& origin_url);
int GetOriginBlobFileCount(const GURL& origin_url);
@@ -127,18 +129,13 @@ class CONTENT_EXPORT IndexedDBContextImpl
typedef std::map<GURL, int64_t> OriginToSizeMap;
class IndexedDBGetUsageAndQuotaCallback;
- base::FilePath GetBlobPath(const std::string& origin_id) const;
+ base::FilePath GetBlobStorePath(const GURL& origin_url) const;
base::FilePath GetLevelDBPath(const GURL& origin_url) const;
- base::FilePath GetLevelDBPath(const std::string& origin_id) const;
+
int64_t ReadUsageFromDisk(const GURL& origin_url) const;
void EnsureDiskUsageCacheInitialized(const GURL& origin_url);
void QueryDiskAndUpdateQuotaUsage(const GURL& origin_url);
- void GotUsageAndQuota(const GURL& origin_url,
- storage::QuotaStatusCode,
- int64_t usage,
- int64_t quota);
- void GotUpdatedQuota(const GURL& origin_url, int64_t usage, int64_t quota);
- void QueryAvailableQuota(const GURL& origin_url);
+ base::Time GetOriginLastModified(const GURL& origin_url);
std::set<GURL>* GetOriginSet();
bool AddToOriginSet(const GURL& origin_url) {
@@ -160,7 +157,6 @@ class CONTENT_EXPORT IndexedDBContextImpl
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_ptr<std::set<GURL> > origin_set_;
OriginToSizeMap origin_size_map_;
- OriginToSizeMap space_available_map_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBContextImpl);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.cc b/chromium/content/browser/indexed_db/indexed_db_database.cc
index d90af34cae2..a877a7bac28 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database.cc
@@ -143,10 +143,6 @@ scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create(
return NULL;
}
-namespace {
-const base::string16::value_type kNoStringVersion[] = {0};
-}
-
IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
IndexedDBBackingStore* backing_store,
IndexedDBFactory* factory,
@@ -154,8 +150,7 @@ IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
: backing_store_(backing_store),
metadata_(name,
kInvalidId,
- kNoStringVersion,
- IndexedDBDatabaseMetadata::NO_INT_VERSION,
+ IndexedDBDatabaseMetadata::NO_VERSION,
kInvalidId),
identifier_(unique_identifier),
factory_(factory) {
@@ -221,7 +216,7 @@ leveldb::Status IndexedDBDatabase::OpenInternal() {
&metadata_.object_stores);
return backing_store_->CreateIDBDatabaseMetaData(
- metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id);
+ metadata_.name, metadata_.version, &metadata_.id);
}
IndexedDBDatabase::~IndexedDBDatabase() {
@@ -1521,7 +1516,7 @@ void IndexedDBDatabase::VersionChangeOperation(
IndexedDBTransaction* transaction) {
IDB_TRACE1(
"IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id());
- int64_t old_version = metadata_.int_version;
+ int64_t old_version = metadata_.version;
DCHECK_GT(version, old_version);
if (!backing_store_->UpdateIDBDatabaseIntVersion(
@@ -1537,12 +1532,9 @@ void IndexedDBDatabase::VersionChangeOperation(
}
transaction->ScheduleAbortTask(
- base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation,
- this,
- metadata_.version,
- metadata_.int_version));
- metadata_.int_version = version;
- metadata_.version = kNoStringVersion;
+ base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this,
+ metadata_.version));
+ metadata_.version = version;
DCHECK(!pending_second_half_open_);
pending_second_half_open_.reset(
@@ -1560,7 +1552,7 @@ void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction,
if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) {
if (pending_second_half_open_) {
if (committed) {
- DCHECK_EQ(pending_second_half_open_->version(), metadata_.int_version);
+ DCHECK_EQ(pending_second_half_open_->version(), metadata_.version);
DCHECK(metadata_.id != kInvalidId);
// Connection was already minted for OnUpgradeNeeded callback.
@@ -1616,7 +1608,7 @@ size_t IndexedDBDatabase::PendingDeleteCount() const {
void IndexedDBDatabase::ProcessPendingCalls() {
if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
DCHECK(pending_run_version_change_transaction_call_->version() >
- metadata_.int_version);
+ metadata_.version);
scoped_ptr<PendingUpgradeCall> pending_call =
std::move(pending_run_version_change_transaction_call_);
RunVersionChangeTransactionFinal(pending_call->callbacks(),
@@ -1709,11 +1701,10 @@ void IndexedDBDatabase::OpenConnection(
// The database was deleted then immediately re-opened; OpenInternal()
// recreates it in the backing store.
if (OpenInternal().ok()) {
- DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
- metadata_.int_version);
+ DCHECK_EQ(IndexedDBDatabaseMetadata::NO_VERSION, metadata_.version);
} else {
base::string16 message;
- if (connection.version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
+ if (connection.version == IndexedDBDatabaseMetadata::NO_VERSION) {
message = ASCIIToUTF16(
"Internal error opening database with no version specified.");
} else {
@@ -1730,12 +1721,11 @@ void IndexedDBDatabase::OpenConnection(
// We infer that the database didn't exist from its lack of either type of
// version.
bool is_new_database =
- metadata_.version == kNoStringVersion &&
- metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION;
+ metadata_.version == IndexedDBDatabaseMetadata::NO_VERSION;
- if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) {
+ if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_VERSION) {
// For unit tests only - skip upgrade steps. Calling from script with
- // DEFAULT_INT_VERSION throws exception.
+ // DEFAULT_VERSION throws exception.
// TODO(jsbell): DCHECK that not in unit tests.
DCHECK(is_new_database);
connection.callbacks->OnSuccess(
@@ -1747,7 +1737,7 @@ void IndexedDBDatabase::OpenConnection(
// We may need to change the version.
int64_t local_version = connection.version;
- if (local_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
+ if (local_version == IndexedDBDatabaseMetadata::NO_VERSION) {
if (!is_new_database) {
connection.callbacks->OnSuccess(
CreateConnection(connection.database_callbacks,
@@ -1760,7 +1750,7 @@ void IndexedDBDatabase::OpenConnection(
local_version = 1;
}
- if (local_version > metadata_.int_version) {
+ if (local_version > metadata_.version) {
RunVersionChangeTransaction(connection.callbacks,
CreateConnection(connection.database_callbacks,
connection.child_process_id),
@@ -1768,16 +1758,16 @@ void IndexedDBDatabase::OpenConnection(
local_version);
return;
}
- if (local_version < metadata_.int_version) {
+ if (local_version < metadata_.version) {
connection.callbacks->OnError(IndexedDBDatabaseError(
blink::WebIDBDatabaseExceptionVersionError,
ASCIIToUTF16("The requested version (") +
Int64ToString16(local_version) +
ASCIIToUTF16(") is less than the existing version (") +
- Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
+ Int64ToString16(metadata_.version) + ASCIIToUTF16(").")));
return;
}
- DCHECK_EQ(local_version, metadata_.int_version);
+ DCHECK_EQ(local_version, metadata_.version);
connection.callbacks->OnSuccess(
CreateConnection(connection.database_callbacks,
connection.child_process_id),
@@ -1797,7 +1787,7 @@ void IndexedDBDatabase::RunVersionChangeTransaction(
// close_pending set.
for (const auto* iter : connections_) {
if (iter != connection.get()) {
- iter->callbacks()->OnVersionChange(metadata_.int_version,
+ iter->callbacks()->OnVersionChange(metadata_.version,
requested_version);
}
}
@@ -1841,7 +1831,7 @@ void IndexedDBDatabase::DeleteDatabase(
// Front end ensures the event is not fired at connections that have
// close_pending set.
connection->callbacks()->OnVersionChange(
- metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION);
+ metadata_.version, IndexedDBDatabaseMetadata::NO_VERSION);
}
// OnBlocked will be fired at the request when one of the other
// connections acks that the OnVersionChange was ignored.
@@ -1872,10 +1862,9 @@ void IndexedDBDatabase::DeleteDatabaseFinal(
}
return;
}
- int64_t old_version = metadata_.int_version;
- metadata_.version = kNoStringVersion;
+ int64_t old_version = metadata_.version;
metadata_.id = kInvalidId;
- metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
+ metadata_.version = IndexedDBDatabaseMetadata::NO_VERSION;
metadata_.object_stores.clear();
callbacks->OnSuccess(old_version);
factory_->DatabaseDeleted(identifier_);
@@ -1895,10 +1884,10 @@ void IndexedDBDatabase::ForceClose() {
void IndexedDBDatabase::VersionChangeIgnored() {
if (pending_run_version_change_transaction_call_)
pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
- metadata_.int_version);
+ metadata_.version);
for (const auto& pending_delete_call : pending_delete_calls_)
- pending_delete_call->callbacks()->OnBlocked(metadata_.int_version);
+ pending_delete_call->callbacks()->OnBlocked(metadata_.version);
}
@@ -1965,13 +1954,11 @@ void IndexedDBDatabase::DeleteObjectStoreAbortOperation(
}
void IndexedDBDatabase::VersionChangeAbortOperation(
- const base::string16& previous_version,
- int64_t previous_int_version,
+ int64_t previous_version,
IndexedDBTransaction* transaction) {
DCHECK(!transaction);
IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation");
metadata_.version = previous_version;
- metadata_.int_version = previous_int_version;
}
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.h b/chromium/content/browser/indexed_db/indexed_db_database.h
index 0049e6c20ee..207c1f9c41a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database.h
@@ -193,8 +193,7 @@ class CONTENT_EXPORT IndexedDBDatabase
scoped_refptr<IndexedDBCallbacks> callbacks,
scoped_ptr<IndexedDBConnection> connection,
IndexedDBTransaction* transaction);
- void VersionChangeAbortOperation(const base::string16& previous_version,
- int64_t previous_int_version,
+ void VersionChangeAbortOperation(int64_t previous_version,
IndexedDBTransaction* transaction);
void DeleteIndexOperation(int64_t object_store_id,
int64_t index_id,
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
index 35b15c3bce8..69f9b162213 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
@@ -35,7 +35,7 @@ void IndexedDBDatabaseCallbacks::OnVersionChange(int64_t old_version,
if (!dispatcher_host_.get())
return;
- dispatcher_host_->Send(new IndexedDBMsg_DatabaseCallbacksIntVersionChange(
+ dispatcher_host_->Send(new IndexedDBMsg_DatabaseCallbacksVersionChange(
ipc_thread_id_, ipc_database_callbacks_id_, old_version, new_version));
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
index a837945e4a2..efc1bddf050 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -76,11 +76,8 @@ TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id1 = 1;
IndexedDBPendingConnection connection1(
- request1,
- callbacks1,
- kFakeChildProcessId,
- transaction_id1,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ request1, callbacks1, kFakeChildProcessId, transaction_id1,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
db->OpenConnection(connection1);
EXPECT_FALSE(backing_store->HasOneRef()); // db, connection count > 0
@@ -90,11 +87,8 @@ TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id2 = 2;
IndexedDBPendingConnection connection2(
- request2,
- callbacks2,
- kFakeChildProcessId,
- transaction_id2,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ request2, callbacks2, kFakeChildProcessId, transaction_id2,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
db->OpenConnection(connection2);
EXPECT_FALSE(backing_store->HasOneRef()); // local and connection
@@ -134,11 +128,8 @@ TEST(IndexedDBDatabaseTest, ForcedClose) {
scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks());
const int64_t upgrade_transaction_id = 3;
IndexedDBPendingConnection connection(
- request,
- callbacks,
- kFakeChildProcessId,
- upgrade_transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ request, callbacks, kFakeChildProcessId, upgrade_transaction_id,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
database->OpenConnection(connection);
EXPECT_EQ(database.get(), request->connection()->database());
@@ -198,11 +189,8 @@ TEST(IndexedDBDatabaseTest, PendingDelete) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id1 = 1;
IndexedDBPendingConnection connection(
- request1,
- callbacks1,
- kFakeChildProcessId,
- transaction_id1,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ request1, callbacks1, kFakeChildProcessId, transaction_id1,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
db->OpenConnection(connection);
EXPECT_FALSE(backing_store->HasOneRef()); // local and db
@@ -246,13 +234,9 @@ class IndexedDBDatabaseOperationTest : public testing::Test {
callbacks_ = new MockIndexedDBDatabaseCallbacks();
const int64_t transaction_id = 1;
db_->OpenConnection(IndexedDBPendingConnection(
- request_,
- callbacks_,
- kFakeChildProcessId,
- transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION));
- EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
- db_->metadata().int_version);
+ request_, callbacks_, kFakeChildProcessId, transaction_id,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+ EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version);
transaction_ = IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
transaction_id, callbacks_, std::set<int64_t>() /*scope*/,
diff --git a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index f0890137038..969ce78e978 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -33,6 +33,7 @@
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/database/database_util.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/common/database/database_identifier.h"
#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "url/gurl.h"
@@ -178,7 +179,7 @@ int32_t IndexedDBDispatcherHost::Add(IndexedDBConnection* connection,
return -1;
}
int32_t ipc_database_id = database_dispatcher_host_->map_.Add(connection);
- Context()->ConnectionOpened(origin_url, connection);
+ context()->ConnectionOpened(origin_url, connection);
database_dispatcher_host_->database_url_map_[ipc_database_id] = origin_url;
return ipc_database_id;
}
@@ -187,6 +188,7 @@ void IndexedDBDispatcherHost::RegisterTransactionId(int64_t host_transaction_id,
const GURL& url) {
if (!database_dispatcher_host_)
return;
+ database_dispatcher_host_->transaction_size_map_[host_transaction_id] = 0;
database_dispatcher_host_->transaction_url_map_[host_transaction_id] = url;
}
@@ -277,7 +279,6 @@ IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(
metadata.id = web_metadata.id;
metadata.name = web_metadata.name;
metadata.version = web_metadata.version;
- metadata.int_version = web_metadata.int_version;
metadata.max_object_store_id = web_metadata.max_object_store_id;
for (const auto& iter : web_metadata.object_stores) {
@@ -311,15 +312,10 @@ void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
base::FilePath indexed_db_path = indexed_db_context_->data_path();
- GURL origin_url =
- storage::GetOriginFromIdentifier(params.database_identifier);
-
- Context()->GetIDBFactory()->GetDatabaseNames(
- new IndexedDBCallbacks(
- this, params.ipc_thread_id, params.ipc_callbacks_id),
- origin_url,
- indexed_db_path,
- request_context_);
+ context()->GetIDBFactory()->GetDatabaseNames(
+ new IndexedDBCallbacks(this, params.ipc_thread_id,
+ params.ipc_callbacks_id),
+ params.origin, indexed_db_path, request_context_);
}
void IndexedDBDispatcherHost::OnIDBFactoryOpen(
@@ -328,20 +324,13 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
base::TimeTicks begin_time = base::TimeTicks::Now();
base::FilePath indexed_db_path = indexed_db_context_->data_path();
- GURL origin_url =
- storage::GetOriginFromIdentifier(params.database_identifier);
-
int64_t host_transaction_id = HostTransactionId(params.transaction_id);
// TODO(dgrogan): Don't let a non-existing database be opened (and therefore
// created) if this origin is already over quota.
- scoped_refptr<IndexedDBCallbacks> callbacks =
- new IndexedDBCallbacks(this,
- params.ipc_thread_id,
- params.ipc_callbacks_id,
- params.ipc_database_callbacks_id,
- host_transaction_id,
- origin_url);
+ scoped_refptr<IndexedDBCallbacks> callbacks = new IndexedDBCallbacks(
+ this, params.ipc_thread_id, params.ipc_callbacks_id,
+ params.ipc_database_callbacks_id, host_transaction_id, params.origin);
callbacks->SetConnectionOpenStartTime(begin_time);
scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
new IndexedDBDatabaseCallbacks(
@@ -352,24 +341,20 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
host_transaction_id,
params.version);
DCHECK(request_context_);
- Context()->GetIDBFactory()->Open(
- params.name, connection, request_context_, origin_url, indexed_db_path);
+ context()->GetIDBFactory()->Open(params.name, connection, request_context_,
+ params.origin, indexed_db_path);
}
void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
- GURL origin_url =
- storage::GetOriginFromIdentifier(params.database_identifier);
base::FilePath indexed_db_path = indexed_db_context_->data_path();
DCHECK(request_context_);
- Context()->GetIDBFactory()->DeleteDatabase(
- params.name,
- request_context_,
- new IndexedDBCallbacks(
- this, params.ipc_thread_id, params.ipc_callbacks_id),
- origin_url,
- indexed_db_path);
+ context()->GetIDBFactory()->DeleteDatabase(
+ params.name, request_context_,
+ new IndexedDBCallbacks(this, params.ipc_thread_id,
+ params.ipc_callbacks_id),
+ params.origin, indexed_db_path);
}
// OnPutHelper exists only to allow us to hop threads while holding a reference
@@ -399,7 +384,7 @@ void IndexedDBDispatcherHost::FinishTransaction(int64_t host_transaction_id,
TransactionIDToDatabaseIDMap& transaction_database_map =
database_dispatcher_host_->transaction_database_map_;
if (committed)
- Context()->TransactionComplete(transaction_url_map[host_transaction_id]);
+ context()->TransactionComplete(transaction_url_map[host_transaction_id]);
transaction_url_map.erase(host_transaction_id);
transaction_size_map.erase(host_transaction_id);
transaction_database_map.erase(host_transaction_id);
@@ -450,7 +435,7 @@ void IndexedDBDispatcherHost::DestroyObject(MapType* map,
IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
IndexedDBDispatcherHost* parent)
- : parent_(parent) {
+ : parent_(parent), weak_factory_(this) {
map_.set_check_on_null_data(true);
}
@@ -461,8 +446,7 @@ IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
// Abort outstanding transactions started by connections in the associated
// front-end to unblock later transactions. This should only occur on unclean
// (crash) or abrupt (process-kill) shutdowns.
@@ -485,17 +469,16 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
IndexedDBConnection* connection = map_.Lookup(iter.first);
if (connection && connection->IsConnected()) {
connection->Close();
- parent_->Context()->ConnectionClosed(iter.second, connection);
+ parent_->context()->ConnectionClosed(iter.second, connection);
}
}
}
bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
const IPC::Message& message) {
- DCHECK(
- (message.type() == IndexedDBHostMsg_DatabasePut::ID ||
- message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK((message.type() == IndexedDBHostMsg_DatabasePut::ID ||
+ message.type() == IndexedDBHostMsg_AckReceivedBlobs::ID) ||
+ parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(
@@ -532,8 +515,7 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -546,20 +528,13 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
params.name,
params.key_path,
params.auto_increment);
- if (parent_->Context()->IsOverQuota(
- database_url_map_[params.ipc_database_id])) {
- connection->database()->Abort(
- host_transaction_id,
- IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
- }
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
int32_t ipc_database_id,
int64_t transaction_id,
int64_t object_store_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -571,8 +546,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
const IndexedDBHostMsg_DatabaseCreateTransaction_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -581,8 +555,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
int64_t host_transaction_id =
parent_->HostTransactionId(params.transaction_id);
- if (transaction_database_map_.find(host_transaction_id) !=
- transaction_database_map_.end()) {
+ if (ContainsKey(transaction_database_map_, host_transaction_id)) {
DLOG(ERROR) << "Duplicate host_transaction_id.";
return;
}
@@ -596,8 +569,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateTransaction(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
int32_t ipc_database_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -607,8 +579,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
int32_t ipc_database_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -618,24 +589,22 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
int32_t ipc_object_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_object_id);
if (!connection)
return;
if (connection->IsConnected())
connection->Close();
- parent_->Context()
- ->ConnectionClosed(database_url_map_[ipc_object_id], connection);
+ parent_->context()->ConnectionClosed(database_url_map_[ipc_object_id],
+ connection);
database_url_map_.erase(ipc_object_id);
parent_->DestroyObject(&map_, ipc_object_id);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
const IndexedDBHostMsg_DatabaseGet_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -654,8 +623,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGetAll(
const IndexedDBHostMsg_DatabaseGetAll_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -678,17 +646,15 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
->GetBlobDataFromUUID(info.uuid)
.release());
}
- parent_->indexed_db_context_->TaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(
- &IndexedDBDispatcherHost::OnPutHelper, parent_, params, handles));
+ parent_->context()->TaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&IndexedDBDispatcherHost::OnPutHelper, parent_,
+ params, handles));
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
const IndexedDBHostMsg_DatabasePut_Params& params,
std::vector<storage::BlobDataHandle*> handles) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
ScopedVector<storage::BlobDataHandle> scoped_handles;
scoped_handles.swap(handles);
@@ -745,17 +711,14 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
params.put_mode,
callbacks,
params.index_keys);
- TransactionIDToSizeMap* map =
- &parent_->database_dispatcher_host_->transaction_size_map_;
// Size can't be big enough to overflow because it represents the
// actual bytes passed through IPC.
- (*map)[host_transaction_id] += params.value.bits.size();
+ transaction_size_map_[host_transaction_id] += params.value.bits.size();
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexKeys(
const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -775,8 +738,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
int64_t transaction_id,
int64_t object_store_id,
const std::vector<int64_t>& index_ids) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -788,8 +750,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetIndexesReady(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
const IndexedDBHostMsg_DatabaseOpenCursor_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -810,8 +771,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
const IndexedDBHostMsg_DatabaseCount_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -829,8 +789,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCount(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteRange(
const IndexedDBHostMsg_DatabaseDeleteRange_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -851,8 +810,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
int32_t ipc_database_id,
int64_t transaction_id,
int64_t object_store_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -868,8 +826,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClear(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
int32_t ipc_database_id,
int64_t transaction_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -881,31 +838,62 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnAbort(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCommit(
int32_t ipc_database_id,
int64_t transaction_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
return;
int64_t host_transaction_id = parent_->HostTransactionId(transaction_id);
+ // May have been aborted by back end before front-end could request commit.
+ if (!ContainsKey(transaction_size_map_, host_transaction_id))
+ return;
+ int64_t transaction_size = transaction_size_map_[host_transaction_id];
+
+ // Always allow empty or delete-only transactions.
+ if (!transaction_size) {
+ connection->database()->Commit(host_transaction_id);
+ return;
+ }
+
+ parent_->context()->quota_manager_proxy()->GetUsageAndQuota(
+ parent_->context()->TaskRunner(),
+ transaction_url_map_[host_transaction_id], storage::kStorageTypeTemporary,
+ base::Bind(&IndexedDBDispatcherHost::DatabaseDispatcherHost::
+ OnGotUsageAndQuotaForCommit,
+ weak_factory_.GetWeakPtr(), ipc_database_id, transaction_id));
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::
+ OnGotUsageAndQuotaForCommit(int32_t ipc_database_id,
+ int64_t transaction_id,
+ storage::QuotaStatusCode status,
+ int64_t usage,
+ int64_t quota) {
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
+ IndexedDBConnection* connection = map_.Lookup(ipc_database_id);
+ // May have disconnected while quota check was pending.
+ if (!connection || !connection->IsConnected())
+ return;
+ int64_t host_transaction_id = parent_->HostTransactionId(transaction_id);
+ // May have aborted while quota check was pending.
+ if (!ContainsKey(transaction_size_map_, host_transaction_id))
+ return;
int64_t transaction_size = transaction_size_map_[host_transaction_id];
- if (transaction_size &&
- parent_->Context()->WouldBeOverQuota(
- transaction_url_map_[host_transaction_id], transaction_size)) {
+
+ if (status == storage::kQuotaStatusOk &&
+ usage + transaction_size <= quota) {
+ connection->database()->Commit(host_transaction_id);
+ } else {
connection->database()->Abort(
host_transaction_id,
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
- return;
}
-
- connection->database()->Commit(host_transaction_id);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
const IndexedDBHostMsg_DatabaseCreateIndex_Params& params) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -920,12 +908,6 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateIndex(
params.key_path,
params.unique,
params.multi_entry);
- if (parent_->Context()->IsOverQuota(
- database_url_map_[params.ipc_database_id])) {
- connection->database()->Abort(
- host_transaction_id,
- IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError));
- }
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
@@ -933,8 +915,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteIndex(
int64_t transaction_id,
int64_t object_store_id,
int64_t index_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, ipc_database_id);
if (!connection || !connection->IsConnected())
@@ -969,9 +950,8 @@ bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- DCHECK(
- !handled ||
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(!handled ||
+ parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
return handled;
}
@@ -981,8 +961,7 @@ void IndexedDBDispatcherHost::CursorDispatcherHost::OnAdvance(
int32_t ipc_thread_id,
int32_t ipc_callbacks_id,
uint32_t count) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBCursor* idb_cursor =
parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
if (!idb_cursor)
@@ -1000,8 +979,7 @@ void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
int32_t ipc_callbacks_id,
const IndexedDBKey& key,
const IndexedDBKey& primary_key) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBCursor* idb_cursor =
parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
if (!idb_cursor)
@@ -1021,8 +999,7 @@ void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetch(
int32_t ipc_thread_id,
int32_t ipc_callbacks_id,
int n) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBCursor* idb_cursor =
parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
if (!idb_cursor)
@@ -1038,8 +1015,7 @@ void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
int32_t ipc_cursor_id,
int used_prefetches,
int unused_prefetches) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBCursor* idb_cursor =
parent_->GetOrTerminateProcess(&map_, ipc_cursor_id);
if (!idb_cursor)
@@ -1054,8 +1030,7 @@ void IndexedDBDispatcherHost::CursorDispatcherHost::OnPrefetchReset(
void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
int32_t ipc_object_id) {
- DCHECK(
- parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
parent_->DestroyObject(&map_, ipc_object_id);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
index 29edb8a9728..bba6b814fbf 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -15,10 +15,13 @@
#include "base/id_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/public/browser/browser_message_filter.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/common/quota/quota_status_code.h"
#include "url/gurl.h"
struct IndexedDBDatabaseMetadata;
@@ -73,7 +76,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
void FinishTransaction(int64_t host_transaction_id, bool committed);
// A shortcut for accessing our context.
- IndexedDBContextImpl* Context() { return indexed_db_context_.get(); }
+ IndexedDBContextImpl* context() const { return indexed_db_context_.get(); }
storage::BlobStorageContext* blob_storage_context() const {
return blob_storage_context_->context();
}
@@ -198,6 +201,12 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
void OnAbort(int32_t ipc_database_id, int64_t transaction_id);
void OnCommit(int32_t ipc_database_id, int64_t transaction_id);
+ void OnGotUsageAndQuotaForCommit(int32_t ipc_database_id,
+ int64_t transaction_id,
+ storage::QuotaStatusCode status,
+ int64_t usage,
+ int64_t quota);
+
IndexedDBDispatcherHost* parent_;
IDMap<IndexedDBConnection, IDMapOwnPointer> map_;
WebIDBObjectIDToURLMap database_url_map_;
@@ -205,6 +214,10 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
TransactionIDToURLMap transaction_url_map_;
TransactionIDToDatabaseIDMap transaction_database_map_;
+ // Weak pointers are used when an asynchronous quota request is made, in
+ // case the dispatcher is torn down before the response returns.
+ base::WeakPtrFactory<DatabaseDispatcherHost> weak_factory_;
+
private:
DISALLOW_COPY_AND_ASSIGN(DatabaseDispatcherHost);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
index 2261dcc30f0..33db01f70fe 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -17,7 +17,6 @@
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
-#include "storage/common/database/database_identifier.h"
#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "third_party/leveldatabase/env_chromium.h"
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 1dcaecc3378..b61e66c5631 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -17,7 +17,7 @@
#include "content/browser/indexed_db/indexed_db_factory_impl.h"
#include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
-#include "storage/common/database/database_identifier.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
@@ -74,12 +74,15 @@ class IndexedDBFactoryTest : public testing::Test {
public:
IndexedDBFactoryTest() {
task_runner_ = new base::TestSimpleTaskRunner();
- context_ = new IndexedDBContextImpl(base::FilePath(),
- NULL /* special_storage_policy */,
- NULL /* quota_manager_proxy */,
- task_runner_.get());
+ quota_manager_proxy_ = new MockQuotaManagerProxy(nullptr, nullptr);
+ context_ = new IndexedDBContextImpl(
+ base::FilePath(), NULL /* special_storage_policy */,
+ quota_manager_proxy_.get(), task_runner_.get());
idb_factory_ = new MockIDBFactory(context_.get());
}
+ ~IndexedDBFactoryTest() override {
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ }
protected:
// For timers to post events.
@@ -93,7 +96,7 @@ class IndexedDBFactoryTest : public testing::Test {
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
scoped_refptr<IndexedDBContextImpl> context_;
scoped_refptr<MockIDBFactory> idb_factory_;
-
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryTest);
};
@@ -279,11 +282,8 @@ TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id = 1;
IndexedDBPendingConnection connection(
- callbacks,
- db_callbacks,
- 0, /* child_process_id */
- transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ callbacks, db_callbacks, 0, /* child_process_id */
+ transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
factory()->Open(ASCIIToUTF16("db"),
connection,
NULL /* request_context */,
@@ -312,11 +312,8 @@ TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id = 1;
IndexedDBPendingConnection connection(
- callbacks,
- db_callbacks,
- 0, /* child_process_id */
- transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ callbacks, db_callbacks, 0, /* child_process_id */
+ transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
factory()->Open(ASCIIToUTF16("db"),
connection,
NULL /* request_context */,
@@ -407,11 +404,8 @@ TEST_F(IndexedDBFactoryTest, ForceCloseReleasesBackingStore) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id = 1;
IndexedDBPendingConnection connection(
- callbacks,
- db_callbacks,
- 0, /* child_process_id */
- transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ callbacks, db_callbacks, 0, /* child_process_id */
+ transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
factory()->Open(ASCIIToUTF16("db"),
connection,
NULL /* request_context */,
diff --git a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
index 01f83cbe2cb..b2aeb4c9573 100644
--- a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -45,8 +45,7 @@ leveldb::Status IndexedDBFakeBackingStore::GetIDBDatabaseMetaData(
leveldb::Status IndexedDBFakeBackingStore::CreateIDBDatabaseMetaData(
const base::string16& name,
- const base::string16& version,
- int64_t int_version,
+ int64_t version,
int64_t* row_id) {
return leveldb::Status::OK();
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
index 8f033005570..3e168695e6b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
@@ -30,8 +30,7 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
IndexedDBDatabaseMetadata*,
bool* found) override;
leveldb::Status CreateIDBDatabaseMetaData(const base::string16& name,
- const base::string16& version,
- int64_t int_version,
+ int64_t version,
int64_t* row_id) override;
bool UpdateIDBDatabaseIntVersion(Transaction*,
int64_t row_id,
diff --git a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
index 1e8926009dc..bec8dd85fdf 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -214,9 +214,11 @@ void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
const scoped_refptr<IndexedDBContextImpl> context,
const GURL& origin_url) {
DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
+ // This runs on the IndexedDB task runner to prevent script from reopening
+ // the origin while we are zipping.
// Make sure the database hasn't been deleted since the page was loaded.
- if (!context->IsInOriginSet(origin_url))
+ if (!context->HasOrigin(origin_url))
return;
context->ForceClose(origin_url,
@@ -235,9 +237,6 @@ void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
base::FilePath zip_path =
temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip"));
- // This happens on the "webkit" thread (which is really just the IndexedDB
- // thread) as a simple way to avoid another script reopening the origin
- // while we are zipping.
std::vector<base::FilePath> paths = context->GetStoragePaths(origin_url);
zip::ZipWithFilterCallback(context->data_path(), zip_path,
base::Bind(AllowWhitelistedPaths, paths));
@@ -260,7 +259,7 @@ void IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread(
DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
// Make sure the database hasn't been deleted since the page was loaded.
- if (!context->IsInOriginSet(origin_url))
+ if (!context->HasOrigin(origin_url))
return;
context->ForceClose(origin_url,
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
index eb705378123..8d5185b84b2 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -14,155 +14,8 @@
#include "content/common/indexed_db/indexed_db_key.h"
#include "content/common/indexed_db/indexed_db_key_path.h"
-// LevelDB Coding Scheme
-// =====================
-//
-// LevelDB stores key/value pairs. Keys and values are strings of bytes,
-// normally of type std::string.
-//
-// The keys in the backing store are variable-length tuples with different
-// types of fields. Each key in the backing store starts with a ternary
-// prefix: (database id, object store id, index id). For each, 0 is reserved
-// for metadata. See KeyPrefix::Decode() for details of the prefix coding.
-//
-// The prefix makes sure that data for a specific database, object store, and
-// index are grouped together. The locality is important for performance:
-// common operations should only need a minimal number of seek operations. For
-// example, all the metadata for a database is grouped together so that
-// reading that metadata only requires one seek.
-//
-// Each key type has a class (in square brackets below) which knows how to
-// encode, decode, and compare that key type.
-//
-// Strings (origins, names, etc) are encoded as UTF-16BE.
-//
-//
-// Global metadata
-// ---------------
-// The prefix is <0, 0, 0>, followed by a metadata type byte:
-//
-// <0, 0, 0, 0> => backing store schema version [SchemaVersionKey]
-// <0, 0, 0, 1> => maximum allocated database [MaxDatabaseIdKey]
-// <0, 0, 0, 2> => SerializedScriptValue version [DataVersionKey]
-// <0, 0, 0, 3>
-// => Blob journal
-// The format of the journal is:
-// {database_id (var int), blobKey (var int)}*.
-// If the blobKey is kAllBlobsKey, the whole database should be deleted.
-// [BlobJournalKey]
-// <0, 0, 0, 4> => Live blob journal; same format. [LiveBlobJournalKey]
-// <0, 0, 0, 100, database id>
-// => Existence implies the database id is in the free list
-// [DatabaseFreeListKey]
-// <0, 0, 0, 201, origin, database name> => Database id (int) [DatabaseNameKey]
-//
-//
-// Database metadata: [DatabaseMetaDataKey]
-// ----------------------------------------
-// The prefix is <database id, 0, 0> followed by a metadata type byte:
-//
-// <database id, 0, 0, 0> => origin name
-// <database id, 0, 0, 1> => database name
-// <database id, 0, 0, 2> => IDB string version data (obsolete)
-// <database id, 0, 0, 3> => maximum allocated object store id
-// <database id, 0, 0, 4> => IDB integer version (var int)
-// <database id, 0, 0, 5> => blob key generator current number
-//
-//
-// Object store metadata: [ObjectStoreMetaDataKey]
-// -----------------------------------------------
-// The prefix is <database id, 0, 0>, followed by a type byte (50), then the
-// object store id (var int), then a metadata type byte.
-//
-// <database id, 0, 0, 50, object store id, 0> => object store name
-// <database id, 0, 0, 50, object store id, 1> => key path
-// <database id, 0, 0, 50, object store id, 2> => auto increment flag
-// <database id, 0, 0, 50, object store id, 3> => is evictable
-// <database id, 0, 0, 50, object store id, 4> => last "version" number
-// <database id, 0, 0, 50, object store id, 5> => maximum allocated index id
-// <database id, 0, 0, 50, object store id, 6> => has key path flag (obsolete)
-// <database id, 0, 0, 50, object store id, 7> => key generator current number
-//
-// The key path was originally just a string (#1) or null (identified by flag,
-// #6). To support null, string, or array the coding is now identified by the
-// leading bytes in #1 - see EncodeIDBKeyPath.
-//
-// The "version" field is used to weed out stale index data. Whenever new
-// object store data is inserted, it gets a new "version" number, and new
-// index data is written with this number. When the index is used for
-// look-ups, entries are validated against the "exists" entries, and records
-// with old "version" numbers are deleted when they are encountered in
-// GetPrimaryKeyViaIndex, IndexCursorImpl::LoadCurrentRow and
-// IndexKeyCursorImpl::LoadCurrentRow.
-//
-//
-// Index metadata: [IndexMetaDataKey]
-// ----------------------------------
-// The prefix is <database id, 0, 0>, followed by a type byte (100), then the
-// object store id (var int), then the index id (var int), then a metadata
-// type byte.
-//
-// <database id, 0, 0, 100, object store id, index id, 0> => index name
-// <database id, 0, 0, 100, object store id, index id, 1> => unique flag
-// <database id, 0, 0, 100, object store id, index id, 2> => key path
-// <database id, 0, 0, 100, object store id, index id, 3> => multi-entry flag
-//
-//
-// Other object store and index metadata
-// -------------------------------------
-// The prefix is <database id, 0, 0> followed by a type byte. The object
-// store and index id are variable length integers, the names are variable
-// length strings.
-//
-// <database id, 0, 0, 150, object store id>
-// => existence implies the object store id is in the free list
-// [ObjectStoreFreeListKey]
-// <database id, 0, 0, 151, object store id, index id>
-// => existence implies the index id is in the free list [IndexFreeListKey]
-// <database id, 0, 0, 200, object store name>
-// => object store id [ObjectStoreNamesKey]
-// <database id, 0, 0, 201, object store id, index name>
-// => index id [IndexNamesKey]
-//
-//
-// Object store data: [ObjectStoreDataKey]
-// ---------------------------------------
-// The prefix is followed by a type byte and the encoded IDB primary key. The
-// data has a "version" prefix followed by the serialized script value.
-//
-// <database id, object store id, 1, user key>
-// => "version", serialized script value
-//
-//
-// "Exists" entry: [ExistsEntryKey]
-// --------------------------------
-// The prefix is followed by a type byte and the encoded IDB primary key.
-//
-// <database id, object store id, 2, user key> => "version"
-//
-//
-// Blob entry table: [BlobEntryKey]
-// --------------------------------
-//
-// The prefix is followed by a type byte and the encoded IDB primary key.
-//
-// <database id, object store id, 3, user key> => array of IndexedDBBlobInfo
-//
-//
-// Index data
-// ----------
-// The prefix is followed by a type byte, the encoded IDB index key, a
-// "sequence" number (obsolete; var int), and the encoded IDB primary key.
-//
-// <database id, object store id, index id, index key, sequence number,
-// primary key> => "version", primary key [IndexDataKey]
-//
-// The sequence number is obsolete; it was used to allow two entries with the
-// same user (index) key in non-unique indexes prior to the inclusion of the
-// primary key in the data.
-//
-// Note: In order to be compatible with LevelDB's Bloom filter each bit of the
-// encoded key needs to used and "not ignored" by the comparator.
+// See leveldb_coding_scheme.md for detailed documentation of the coding
+// scheme implemented here.
using base::StringPiece;
using blink::WebIDBKeyType;
@@ -197,6 +50,10 @@ static const unsigned char kIndexedDBKeyBinaryTypeByte = 6;
static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0;
static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0;
+static const unsigned char kIndexedDBKeyPathNullTypeByte = 0;
+static const unsigned char kIndexedDBKeyPathStringTypeByte = 1;
+static const unsigned char kIndexedDBKeyPathArrayTypeByte = 2;
+
static const unsigned char kObjectStoreDataIndexId = 1;
static const unsigned char kExistsEntryIndexId = 2;
static const unsigned char kBlobEntryIndexId = 3;
@@ -353,6 +210,18 @@ void EncodeIDBKey(const IndexedDBKey& value, std::string* into) {
}
}
+#define COMPILE_ASSERT_MATCHING_VALUES(a, b) \
+ static_assert( \
+ static_cast<unsigned char>(a) == static_cast<unsigned char>(b), \
+ "Blink enum and coding byte must match.")
+
+COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeNull,
+ kIndexedDBKeyPathNullTypeByte);
+COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeString,
+ kIndexedDBKeyPathStringTypeByte);
+COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeArray,
+ kIndexedDBKeyPathArrayTypeByte);
+
void EncodeIDBKeyPath(const IndexedDBKeyPath& value, std::string* into) {
// May be typed, or may be a raw string. An invalid leading
// byte is used to identify typed coding. New records are
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
index bd3724c798a..5be0eecfc8b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -237,9 +237,9 @@ class DatabaseMetaDataKey {
enum MetaDataType {
ORIGIN_NAME = 0,
DATABASE_NAME = 1,
- USER_VERSION = 2,
+ USER_STRING_VERSION = 2, // Obsolete
MAX_OBJECT_STORE_ID = 3,
- USER_INT_VERSION = 4,
+ USER_VERSION = 4,
BLOB_KEY_GENERATOR_CURRENT_NUMBER = 5,
MAX_SIMPLE_METADATA_TYPE = 6
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
index 2f9e141d0ea..0c300848237 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
@@ -888,11 +888,11 @@ TEST(IndexedDBLevelDBCodingTest, ComparisonTest) {
keys.push_back(
DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::DATABASE_NAME));
keys.push_back(
- DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_VERSION));
+ DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_STRING_VERSION));
keys.push_back(
DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID));
keys.push_back(
- DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_INT_VERSION));
+ DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_VERSION));
keys.push_back(
ObjectStoreMetaDataKey::Encode(1, 1, ObjectStoreMetaDataKey::NAME));
keys.push_back(
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata.cc b/chromium/content/browser/indexed_db/indexed_db_metadata.cc
index 74bdfbf9d01..899c881ad13 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata.cc
@@ -49,19 +49,16 @@ IndexedDBObjectStoreMetadata::~IndexedDBObjectStoreMetadata() = default;
IndexedDBObjectStoreMetadata& IndexedDBObjectStoreMetadata::operator=(
const IndexedDBObjectStoreMetadata& other) = default;
-IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata()
- : int_version(NO_INT_VERSION) {}
+IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata() : version(NO_VERSION) {}
IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
const base::string16& name,
int64_t id,
- const base::string16& version,
- int64_t int_version,
+ int64_t version,
int64_t max_object_store_id)
: name(name),
id(id),
version(version),
- int_version(int_version),
max_object_store_id(max_object_store_id) {}
IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata.h b/chromium/content/browser/indexed_db/indexed_db_metadata.h
index 288801722f4..ec9d9acbcb8 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata.h
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata.h
@@ -61,18 +61,14 @@ struct CONTENT_EXPORT IndexedDBObjectStoreMetadata {
struct CONTENT_EXPORT IndexedDBDatabaseMetadata {
// TODO(jsbell): These can probably be collapsed into 0.
- enum {
- NO_INT_VERSION = -1,
- DEFAULT_INT_VERSION = 0
- };
+ enum { NO_VERSION = -1, DEFAULT_VERSION = 0 };
typedef std::map<int64_t, IndexedDBObjectStoreMetadata> ObjectStoreMap;
IndexedDBDatabaseMetadata();
IndexedDBDatabaseMetadata(const base::string16& name,
int64_t id,
- const base::string16& version,
- int64_t int_version,
+ int64_t version,
int64_t max_object_store_id);
IndexedDBDatabaseMetadata(const IndexedDBDatabaseMetadata& other);
~IndexedDBDatabaseMetadata();
@@ -80,8 +76,7 @@ struct CONTENT_EXPORT IndexedDBDatabaseMetadata {
base::string16 name;
int64_t id;
- base::string16 version;
- int64_t int_version;
+ int64_t version;
int64_t max_object_store_id;
ObjectStoreMap object_stores;
diff --git a/chromium/content/browser/indexed_db/indexed_db_pending_connection.cc b/chromium/content/browser/indexed_db/indexed_db_pending_connection.cc
index ee16aba741e..34f4924285c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_pending_connection.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_pending_connection.cc
@@ -18,6 +18,9 @@ IndexedDBPendingConnection::IndexedDBPendingConnection(
transaction_id(transaction_id_in),
version(version_in) {}
+IndexedDBPendingConnection::IndexedDBPendingConnection(
+ const IndexedDBPendingConnection& other) = default;
+
IndexedDBPendingConnection::~IndexedDBPendingConnection() {}
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_pending_connection.h b/chromium/content/browser/indexed_db/indexed_db_pending_connection.h
index b66d9cd4955..10e1b05df55 100644
--- a/chromium/content/browser/indexed_db/indexed_db_pending_connection.h
+++ b/chromium/content/browser/indexed_db/indexed_db_pending_connection.h
@@ -24,6 +24,7 @@ struct CONTENT_EXPORT IndexedDBPendingConnection {
int child_process_id_in,
int64_t transaction_id_in,
int64_t version_in);
+ IndexedDBPendingConnection(const IndexedDBPendingConnection& other);
~IndexedDBPendingConnection();
scoped_refptr<IndexedDBCallbacks> callbacks;
scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks;
diff --git a/chromium/content/browser/indexed_db/indexed_db_quota_client.cc b/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
index 433b2c130e0..8fc9ce8cd96 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -11,7 +11,7 @@
#include "base/logging.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/database/database_util.h"
using storage::QuotaClient;
@@ -90,10 +90,9 @@ void IndexedDBQuotaClient::GetOriginUsage(const GURL& origin_url,
}
base::PostTaskAndReplyWithResult(
- indexed_db_context_->TaskRunner(),
- FROM_HERE,
- base::Bind(
- &GetOriginUsageOnIndexedDBThread, indexed_db_context_, origin_url),
+ indexed_db_context_->TaskRunner(), FROM_HERE,
+ base::Bind(&GetOriginUsageOnIndexedDBThread,
+ base::RetainedRef(indexed_db_context_), origin_url),
callback);
}
@@ -117,10 +116,9 @@ void IndexedDBQuotaClient::GetOriginsForType(
std::set<GURL>* origins_to_return = new std::set<GURL>();
indexed_db_context_->TaskRunner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GetAllOriginsOnIndexedDBThread,
- indexed_db_context_,
- base::Unretained(origins_to_return)),
+ FROM_HERE, base::Bind(&GetAllOriginsOnIndexedDBThread,
+ base::RetainedRef(indexed_db_context_),
+ base::Unretained(origins_to_return)),
base::Bind(&DidGetOrigins, callback, base::Owned(origins_to_return)));
}
@@ -145,11 +143,9 @@ void IndexedDBQuotaClient::GetOriginsForHost(
std::set<GURL>* origins_to_return = new std::set<GURL>();
indexed_db_context_->TaskRunner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GetOriginsForHostOnIndexedDBThread,
- indexed_db_context_,
- host,
- base::Unretained(origins_to_return)),
+ FROM_HERE, base::Bind(&GetOriginsForHostOnIndexedDBThread,
+ base::RetainedRef(indexed_db_context_), host,
+ base::Unretained(origins_to_return)),
base::Bind(&DidGetOrigins, callback, base::Owned(origins_to_return)));
}
@@ -168,10 +164,9 @@ void IndexedDBQuotaClient::DeleteOriginData(const GURL& origin,
}
base::PostTaskAndReplyWithResult(
- indexed_db_context_->TaskRunner(),
- FROM_HERE,
- base::Bind(
- &DeleteOriginDataOnIndexedDBThread, indexed_db_context_, origin),
+ indexed_db_context_->TaskRunner(), FROM_HERE,
+ base::Bind(&DeleteOriginDataOnIndexedDBThread,
+ base::RetainedRef(indexed_db_context_), origin),
callback);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
index 31a413693ed..a626dc06650 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -20,7 +20,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
-#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
// Declared to shorten the line lengths.
@@ -139,8 +138,8 @@ class IndexedDBQuotaClientTest : public testing::Test {
}
void AddFakeIndexedDB(const GURL& origin, int size) {
- base::FilePath file_path_origin = idb_context()->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(origin));
+ base::FilePath file_path_origin =
+ idb_context()->GetFilePathForTesting(origin);
if (!base::CreateDirectory(file_path_origin)) {
LOG(ERROR) << "failed to base::CreateDirectory "
<< file_path_origin.value();
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc
index 984296807fe..dbe63ac0f71 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -43,7 +43,7 @@ class IndexedDBTransactionTest : public testing::Test {
void CreateDB() {
// DB is created here instead of the constructor to workaround a
// "peculiarity of C++". More info at
- // https://code.google.com/p/googletest/wiki/FAQ#My_compiler_complains_that_a_constructor_(or_destructor)_cannot
+ // https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#my-compiler-complains-that-a-constructor-or-destructor-cannot-return-a-value-whats-going-on
leveldb::Status s;
db_ = IndexedDBDatabase::Create(base::ASCIIToUTF16("db"),
backing_store_.get(),
diff --git a/chromium/content/browser/indexed_db/indexed_db_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
index f7ea47817e6..7b057d599cc 100644
--- a/chromium/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
@@ -16,13 +16,13 @@
#include "content/browser/indexed_db/indexed_db_factory_impl.h"
#include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_browser_context.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/special_storage_policy.h"
-#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -37,10 +37,14 @@ class IndexedDBTest : public testing::Test {
kSessionOnlyOrigin("http://session-only/"),
task_runner_(new base::TestSimpleTaskRunner),
special_storage_policy_(new MockSpecialStoragePolicy),
+ quota_manager_proxy_(new MockQuotaManagerProxy(nullptr, nullptr)),
file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_),
io_thread_(BrowserThread::IO, &message_loop_) {
special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
}
+ ~IndexedDBTest() override {
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ }
protected:
void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
@@ -48,6 +52,7 @@ class IndexedDBTest : public testing::Test {
base::MessageLoopForIO message_loop_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
private:
BrowserThreadImpl file_thread_;
@@ -69,17 +74,16 @@ TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) {
scoped_refptr<IndexedDBContextImpl> idb_context =
new IndexedDBContextImpl(temp_dir.path(),
special_storage_policy_.get(),
- NULL,
+ quota_manager_proxy_.get(),
task_runner_.get());
- normal_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kNormalOrigin));
- session_only_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
+ normal_path = idb_context->GetFilePathForTesting(kNormalOrigin);
+ session_only_path = idb_context->GetFilePathForTesting(kSessionOnlyOrigin);
ASSERT_TRUE(base::CreateDirectory(normal_path));
ASSERT_TRUE(base::CreateDirectory(session_only_path));
FlushIndexedDBTaskRunner();
message_loop_.RunUntilIdle();
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
}
FlushIndexedDBTaskRunner();
@@ -103,16 +107,14 @@ TEST_F(IndexedDBTest, SetForceKeepSessionState) {
scoped_refptr<IndexedDBContextImpl> idb_context =
new IndexedDBContextImpl(temp_dir.path(),
special_storage_policy_.get(),
- NULL,
+ quota_manager_proxy_.get(),
task_runner_.get());
// Save session state. This should bypass the destruction-time deletion.
idb_context->SetForceKeepSessionState();
- normal_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kNormalOrigin));
- session_only_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
+ normal_path = idb_context->GetFilePathForTesting(kNormalOrigin);
+ session_only_path = idb_context->GetFilePathForTesting(kSessionOnlyOrigin);
ASSERT_TRUE(base::CreateDirectory(normal_path));
ASSERT_TRUE(base::CreateDirectory(session_only_path));
message_loop_.RunUntilIdle();
@@ -174,7 +176,7 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
scoped_refptr<IndexedDBContextImpl> idb_context =
new IndexedDBContextImpl(temp_dir.path(),
special_storage_policy_.get(),
- NULL,
+ quota_manager_proxy_.get(),
task_runner_.get());
scoped_refptr<ForceCloseDBCallbacks> open_callbacks =
@@ -185,8 +187,7 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
IndexedDBFactory* factory = idb_context->GetIDBFactory();
- test_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kTestOrigin));
+ test_path = idb_context->GetFilePathForTesting(kTestOrigin);
IndexedDBPendingConnection open_connection(open_callbacks,
open_db_callbacks,
@@ -233,10 +234,10 @@ TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
const GURL kTestOrigin("http://test/");
scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
+ temp_dir.path(), special_storage_policy_.get(),
+ quota_manager_proxy_.get(), task_runner_.get());
- base::FilePath test_path = idb_context->GetFilePathForTesting(
- storage::GetIdentifierFromOrigin(kTestOrigin));
+ base::FilePath test_path = idb_context->GetFilePathForTesting(kTestOrigin);
ASSERT_TRUE(base::CreateDirectory(test_path));
scoped_ptr<LevelDBLock> lock =
@@ -258,8 +259,9 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
+ scoped_refptr<IndexedDBContextImpl> context =
+ new IndexedDBContextImpl(temp_dir.path(), special_storage_policy_.get(),
+ quota_manager_proxy_.get(), task_runner_.get());
scoped_refptr<IndexedDBFactoryImpl> factory =
static_cast<IndexedDBFactoryImpl*>(context->GetIDBFactory());
@@ -269,11 +271,8 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
new MockIndexedDBDatabaseCallbacks());
const int64_t transaction_id = 1;
IndexedDBPendingConnection connection(
- callbacks,
- db_callbacks,
- 0 /* child_process_id */,
- transaction_id,
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+ callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION);
factory->Open(base::ASCIIToUTF16("db"),
connection,
NULL /* request_context */,
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
index 8bd919e7c5d..4cb277cc346 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -14,10 +14,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/process_memory_dump.h"
#include "build/build_config.h"
#include "content/browser/indexed_db/indexed_db_class_factory.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
@@ -89,6 +92,8 @@ LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); }
LevelDBDatabase::LevelDBDatabase() {}
LevelDBDatabase::~LevelDBDatabase() {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
// db_'s destructor uses comparator_adapter_; order of deletion is important.
CloseDatabase();
comparator_adapter_.reset();
@@ -311,6 +316,7 @@ leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name,
(*result)->comparator_adapter_ = std::move(comparator_adapter);
(*result)->comparator_ = comparator;
(*result)->filter_policy_ = std::move(filter_policy);
+ (*result)->file_name_for_tracing = file_name.BaseName().AsUTF8Unsafe();
return s;
}
@@ -340,6 +346,7 @@ scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
result->comparator_adapter_ = std::move(comparator_adapter);
result->comparator_ = comparator;
result->filter_policy_ = std::move(filter_policy);
+ result->file_name_for_tracing = "in-memory-database";
return result;
}
@@ -438,4 +445,29 @@ void LevelDBDatabase::Compact(const base::StringPiece& start,
void LevelDBDatabase::CompactAll() { db_->CompactRange(NULL, NULL); }
+bool LevelDBDatabase::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ if (!db_)
+ return false;
+
+ std::string value;
+ uint64_t size;
+ bool res = db_->GetProperty("leveldb.approximate-memory-usage", &value);
+ DCHECK(res);
+ base::StringToUint64(value, &size);
+
+ auto dump = pmd->CreateAllocatorDump(
+ base::StringPrintf("leveldb/index_db/%p", db_.get()));
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
+ dump->AddString("file_name", "", file_name_for_tracing);
+
+ // Memory is allocated from system allocator (malloc).
+ pmd->AddSuballocation(dump->guid(),
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->system_allocator_pool_name());
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_database.h b/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
index d5e469a6861..1ddc0bc4216 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
+#include "base/trace_event/memory_dump_provider.h"
#include "content/common/content_export.h"
#include "third_party/leveldatabase/src/include/leveldb/comparator.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -54,7 +55,8 @@ class CONTENT_EXPORT LevelDBLock {
DISALLOW_COPY_AND_ASSIGN(LevelDBLock);
};
-class CONTENT_EXPORT LevelDBDatabase {
+class CONTENT_EXPORT LevelDBDatabase
+ : public base::trace_event::MemoryDumpProvider {
public:
class ComparatorAdapter : public leveldb::Comparator {
public:
@@ -82,7 +84,7 @@ class CONTENT_EXPORT LevelDBDatabase {
static leveldb::Status Destroy(const base::FilePath& file_name);
static scoped_ptr<LevelDBLock> LockForTesting(
const base::FilePath& file_name);
- virtual ~LevelDBDatabase();
+ ~LevelDBDatabase() override;
leveldb::Status Put(const base::StringPiece& key, std::string* value);
leveldb::Status Remove(const base::StringPiece& key);
@@ -96,6 +98,10 @@ class CONTENT_EXPORT LevelDBDatabase {
void Compact(const base::StringPiece& start, const base::StringPiece& stop);
void CompactAll();
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) override;
+
protected:
LevelDBDatabase();
@@ -109,6 +115,7 @@ class CONTENT_EXPORT LevelDBDatabase {
scoped_ptr<leveldb::DB> db_;
scoped_ptr<const leveldb::FilterPolicy> filter_policy_;
const LevelDBComparator* comparator_;
+ std::string file_name_for_tracing;
};
} // namespace content
diff --git a/chromium/content/browser/indexed_db/leveldb_coding_scheme.md b/chromium/content/browser/indexed_db/leveldb_coding_scheme.md
new file mode 100644
index 00000000000..f5674161d71
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb_coding_scheme.md
@@ -0,0 +1,323 @@
+# LevelDB Coding Scheme
+
+LevelDB stores key/value pairs. Keys and values are strings of bytes,
+normally of type `std::string`.
+
+The keys in the backing store are variable-length tuples with
+different types of fields, described here using the notation «a, b, c,
+...». Each key in the backing store starts with a ternary prefix:
+«database id, object store id, index id». For each, the id `0` is
+always reserved for metadata; other ids may be reserved as well.
+
+*** aside
+The prefix makes sure that data for a specific database, object store,
+and index are grouped together. The locality is important for
+performance: common operations should only need a minimal number of
+seek operations. For example, all the metadata for a database is
+grouped together so that reading that metadata only requires one seek.
+***
+
+Each key type has a class - in [`square brackets`] below - which knows
+how to encode, decode, and compare that key type.
+
+The term "user key" refers to an Indexed DB key value specified by
+user code as opposed to the internal keys as described here.
+
+Integer literals used below (e.g. «0, 0, 0, 201, ...») are defined as
+constants in `indexed_db_leveldb_coding.cc`
+
+*** note
+**Warning:** In order to be compatible with LevelDB's Bloom filter each
+bit of the encoded key needs to used and "not ignored" by the
+comparator.
+***
+
+*** note
+**Warning:** As a custom comparator is used, some code to handle obsolete
+data is still needed as the sort order must be maintained.
+***
+
+- - - -
+
+## Types
+
+### Primitive Types
+
+Generic types which may appear as parts of keys or values are:
+
+* **Byte** - what it says on the tin
+* **Bool** - single byte, 0 = false, otherwise true
+* **Int** - int64_t >= 0; 8 bytes in little-endian order
+* **VarInt** - int64_t >= 0; variable-width, little-endian, 7 bits per
+ byte with high bit set until last
+* **String** - UTF-16BE (must be byte-swapped on x86/x64/ARM); length
+ must be implicit
+* **StringWithLength** - VarInt prefix with length in code units (i.e.
+ bytes/2), followed by String
+* **Binary** - VarInt prefix with length in bytes, followed by data
+ bytes
+* **Double** - IEEE754 64-bit (double), in *host endianness*
+
+*** aside
+There is a mix of network-endian, little-endian, and host-endian. In
+particular, the String encoding requires byte-swapping. Sorry about
+that.
+***
+
+### IDBKey (keys and values)
+
+First byte is the type, followed by type-specific serialization:
+
+* Null (no key): `0` (Byte) _Should not appear in data._
+* Number: `3` (Byte), Double
+* Date: `2` (Byte), Double
+* String: `1` (Byte), StringWithLength
+* Binary: `6` (Byte), Binary
+* Array: `4` (Byte), count (VarInt), IDBKey...
+
+### IDBKeyPath (values)
+
+* Null: `0` (Byte), `0` (Byte), `0` (Byte)
+* String: `0` (Byte), `0` (Byte), `1` (Byte), StringWithLength
+* Array: `0` (Byte), `0` (Byte), `2` (Byte), count (VarInt), StringWithLength...
+
+*** note
+**Compatibility:**
+If length is < 3 or the first two bytes are not `0`, `0` whole value
+is decoded as a String.
+***
+
+### Blob Journal (value)
+
+Blob journals are zero-or-more instances of the structure:
+
+```
+{
+ database_id (VarInt),
+ blobKey (VarInt)
+}
+```
+
+There is no length prefix; just read until you run out of data.
+
+If the blobKey is `DatabaseMetaDataKey::kAllBlobsKey`, the whole
+database should be deleted.
+
+### BlobData (value)
+
+Blob data is zero-or-more instances of the structure:
+
+```
+{
+ is_file (Bool),
+ key (VarInt),
+ type (StringWithLength), // may be empty
+ /*for Blobs only*/ size (VarInt),
+ /*for Files only*/ filename (StringWithLength)
+}
+```
+
+There is no length prefix; just read until you run out of data.
+
+- - - -
+
+## Key Prefix
+[`KeyPrefix`]
+
+Each key is prefixed with «database id, object store id, index id»
+with `0` reserved for metadata.
+
+To save space, the prefix is not encoded with the usual types. The
+first byte defines the lengths of the other fields:
+
+* The top 3 bits are the length of the database id - 1 (in bytes)
+* The next 3 bits are the length of the object store id - 1 (in bytes)
+* The bottom 2 bits are the length of the index id - 1 (in bytes)
+
+This is followed by:
+
+* The database id in little-endian order (1 - 8 bytes)
+* The object store id in little-endian order (1 - 8 bytes)
+* The index id in little-endian order (1 - 4 bytes)
+
+- - - -
+
+## Global metadata
+
+The prefix is «0, 0, 0», followed by a metadata type byte:
+
+key | value
+------------------------------------|------
+«0, 0, 0, 0» | backing store schema version (Int) [`SchemaVersionKey`]
+«0, 0, 0, 1» | maximum allocated database (Int) [`MaxDatabaseIdKey`]
+«0, 0, 0, 2» | SerializedScriptValue version (Int) [`DataVersionKey`]
+«0, 0, 0, 3» | primary BlobJournal [`BlobJournalKey`]
+«0, 0, 0, 4» | live BlobJournal [`LiveBlobJournalKey`]
+«0, 0, 0, 100, database id (VarInt)» | Existence implies the database id is in the free list [`DatabaseFreeListKey`] - _obsolete_
+«0, 0, 0, 201, origin (StringWithLength), database name (StringWithLength)» | Database id (Int) [`DatabaseNameKey`]
+
+*** aside
+Free lists (#100) are no longer used. The ID space is assumed to be
+sufficient.
+***
+
+
+## Database metadata
+[`DatabaseMetaDataKey`]
+
+The prefix is «database id, 0, 0» followed by a metadata type Byte:
+
+key | value
+-----------------------|-------
+«database id, 0, 0, 0» | origin name (String)
+«database id, 0, 0, 1» | database name (String)
+«database id, 0, 0, 2» | IDB string version data (String) - _obsolete_
+«database id, 0, 0, 3» | maximum allocated object store id (Int)
+«database id, 0, 0, 4» | IDB integer version (VarInt)
+«database id, 0, 0, 5» | blob key generator current number (VarInt)
+
+*** aside
+Early versions of the Indexed DB spec used strings for versions
+(#2) instead of monotonically increasing integers.
+***
+
+
+### More database metadata
+
+The prefix is «database id, 0, 0» followed by a type Byte. The object
+store and index id are VarInt, the names are StringWithLength.
+
+key | value
+------------------------------------------------------|-------
+«database id, 0, 0, 150, object store id» | existence implies the object store id is in the free list [`ObjectStoreFreeListKey`] - _obsolete_
+«database id, 0, 0, 151, object store id, index id» | existence implies the index id is in the free list [`IndexFreeListKey`] - _obsolete_
+«database id, 0, 0, 200, object store name» | object store id (Int) [`ObjectStoreNamesKey`] - _obsolete_
+«database id, 0, 0, 201, object store id, index name» | index id (Int) [`IndexNamesKey`] - _obsolete_
+
+*** aside
+Free lists (#150, #151) are no longer used. The ID space is assumed to
+be sufficient.
+
+The name-to-id mappings (#200, #201) are written but no longer read;
+instead the mapping is inferred from the object store and index
+metadata. _These should probably be removed._
+***
+
+
+## Object store metadata
+[`ObjectStoreMetaDataKey`]
+
+The prefix is «database id, 0, 0», followed by a type Byte (`50`),
+then the object store id (VarInt), then a metadata type Byte.
+
+key | value
+--------------------------------------------|-------
+«database id, 0, 0, 50, object store id, 0» | object store name (String)
+«database id, 0, 0, 50, object store id, 1» | key path (IDBKeyPath)
+«database id, 0, 0, 50, object store id, 2» | auto increment flag (Bool)
+«database id, 0, 0, 50, object store id, 3» | is evictable (Bool) - _obsolete_
+«database id, 0, 0, 50, object store id, 4» | last version number (Int)
+«database id, 0, 0, 50, object store id, 5» | maximum allocated index id (Int)
+«database id, 0, 0, 50, object store id, 6» | "has key path" flag (Bool) - _obsolete_
+«database id, 0, 0, 50, object store id, 7» | key generator current number (Int)
+
+The version field is used to weed out stale index data. Whenever new
+object store data is inserted, it gets a new version number, and new
+index data is written with this number. When the index is used for
+look-ups, entries are validated against the "exists" entries, and
+records with old version numbers are deleted when they are encountered
+in `GetPrimaryKeyViaIndex`, `IndexCursorImpl::LoadCurrentRow` and
+`IndexKeyCursorImpl::LoadCurrentRow`.
+
+*** aside
+Evictable stores (#3) were present in early iterations of the Indexed
+DB specification.
+
+The key path was originally just a string (#1) or null (identified by
+flag, #6). To support null, string, or array the coding is now
+identified by the leading bytes in #1 - see **IDBKeyPath**.
+***
+
+*** note
+**Compatibility:**
+If #6 is not present then a String key path can be assumed.
+If #7 is not present, the key generator state is lazily initialized
+using the maximum numeric key present in existing data.
+***
+
+
+## Index metadata
+[`IndexMetaDataKey`]
+
+The prefix is «database id, 0, 0», followed by a type Byte (100), then
+the object store id (VarInt), then the index id (VarInt), then a
+metadata type Byte.
+
+key | value
+-------------------------------------------------------|-------
+«database id, 0, 0, 100, object store id, index id, 0» | index name (String)
+«database id, 0, 0, 100, object store id, index id, 1» | unique flag (Bool)
+«database id, 0, 0, 100, object store id, index id, 2» | key path (IDBKeyPath)
+«database id, 0, 0, 100, object store id, index id, 3» | multi-entry flag (Bool)
+
+*** note
+**Compatibility:**
+If #3 is not present, the multi-entry flag is unset.
+***
+
+
+## Object store data
+[`ObjectStoreDataKey`]
+
+The reserved index id `1` is used in the prefix. The prefix is
+followed the encoded IDB primary key (IDBKey). The data has a
+version prefix followed by the serialized script value.
+
+key | value
+-----------------------------------------------------|-------
+«database id, object store id, 1, user key (IDBKey)» | version (VarInt), serialized script value
+
+
+## "Exists" entry
+[`ExistsEntryKey`]
+
+The reserved index id `2` is used in the prefix. The prefix is
+followed the encoded IDB primary key (IDBKey).
+
+key | value
+-----------------------------------------------------|-------
+«database id, object store id, 2, user key (IDBKey)» | version (VarInt)
+
+
+## Blob entry table
+[`BlobEntryKey`]
+
+The reserved index id `3` is used in the prefix. The prefix is
+followed the encoded IDB primary key.
+
+key | value
+-----------------------------------------------------|-------
+«database id, object store id, 3, user key (IDBKey)» | BlobData
+
+
+## Index data
+[`IndexDataKey`]
+
+The prefix is followed by a type byte, the encoded index key (IDBKey),
+a sequence number (VarInt), and the encoded primary key (IDBKey).
+
+key | value
+----|-------
+«database id, object store id, index id, index key (IDBKey), sequence number (VarInt), primary key (IDBKey)» | version (VarInt), primary key (IDBKey)
+
+The sequence number is obsolete; it was used to allow two entries with
+the same user (index) key in non-unique indexes prior to the inclusion
+of the primary key in the key itself. `0` is always written now
+(which, as a VarInt, takes a single byte)
+
+*** note
+**Compatibility:**
+The sequence number and primary key, or just the primary key may not
+be present. In that case, enumerators that need the primary key must
+access the value.
+***
diff --git a/chromium/content/browser/leveldb_wrapper_impl.cc b/chromium/content/browser/leveldb_wrapper_impl.cc
new file mode 100644
index 00000000000..7b7deb5a68b
--- /dev/null
+++ b/chromium/content/browser/leveldb_wrapper_impl.cc
@@ -0,0 +1,143 @@
+// 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 "content/browser/leveldb_wrapper_impl.h"
+
+#include "base/bind.h"
+#include "mojo/common/common_type_converters.h"
+
+namespace content {
+
+LevelDBWrapperImpl::LevelDBWrapperImpl(
+ leveldb::LevelDBDatabase* database,
+ const std::string& prefix,
+ size_t max_size,
+ const base::Closure& no_bindings_callback)
+ : prefix_(prefix),
+ no_bindings_callback_(no_bindings_callback),
+ database_(database),
+ bytes_used_(0),
+ max_size_(max_size) {
+ bindings_.set_connection_error_handler(base::Bind(
+ &LevelDBWrapperImpl::OnConnectionError, base::Unretained(this)));
+}
+
+void LevelDBWrapperImpl::Bind(mojom::LevelDBWrapperRequest request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void LevelDBWrapperImpl::AddObserver(mojom::LevelDBObserverPtr observer) {
+ observers_.AddPtr(std::move(observer));
+}
+
+LevelDBWrapperImpl::~LevelDBWrapperImpl() {}
+
+void LevelDBWrapperImpl::Put(mojo::Array<uint8_t> key,
+ mojo::Array<uint8_t> value,
+ const mojo::String& source,
+ const PutCallback& callback) {
+ bool has_old_item = false;
+ mojo::Array<uint8_t> old_value;
+ size_t old_item_size = 0;
+ auto found = map_.find(key);
+ if (found != map_.end()) {
+ old_value = std::move(found->second);
+ old_item_size = key.size() + old_value.size();
+ has_old_item = true;
+ }
+ size_t new_item_size = key.size() + value.size();
+ size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size;
+
+ // Only check quota if the size is increasing, this allows
+ // shrinking changes to pre-existing maps that are over budget.
+ if (new_item_size > old_item_size && new_bytes_used > max_size_) {
+ callback.Run(false);
+ return;
+ }
+
+ map_[key.Clone()] = value.Clone();
+ bytes_used_ = new_bytes_used;
+ if (!has_old_item) {
+ // We added a new key/value pair.
+ observers_.ForAllPtrs(
+ [&key, &value, &source](mojom::LevelDBObserver* observer) {
+ observer->KeyAdded(key.Clone(), value.Clone(), source);
+ });
+ } else {
+ // We changed the value for an existing key.
+ observers_.ForAllPtrs(
+ [&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) {
+ observer->KeyChanged(
+ key.Clone(), value.Clone(), old_value.Clone(), source);
+ });
+ }
+ callback.Run(true);
+}
+
+void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key,
+ const mojo::String& source,
+ const DeleteCallback& callback) {
+ auto found = map_.find(key);
+ if (found == map_.end()) {
+ callback.Run(true);
+ return;
+ }
+
+ mojo::Array<uint8_t> old_value = std::move(found->second);
+ map_.erase(found);
+ bytes_used_ -= key.size() + old_value.size();
+ observers_.ForAllPtrs(
+ [&key, &source, &old_value](mojom::LevelDBObserver* observer) {
+ observer->KeyDeleted(
+ key.Clone(), old_value.Clone(), source);
+ });
+ callback.Run(true);
+}
+
+void LevelDBWrapperImpl::DeleteAll(const mojo::String& source,
+ const DeleteAllCallback& callback) {
+ map_.clear();
+ bytes_used_ = 0;
+ observers_.ForAllPtrs(
+ [&source](mojom::LevelDBObserver* observer) {
+ observer->AllDeleted(source);
+ });
+ callback.Run(true);
+}
+
+void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key,
+ const GetCallback& callback) {
+ auto found = map_.find(key);
+ if (found == map_.end()) {
+ callback.Run(false, mojo::Array<uint8_t>());
+ return;
+ }
+ callback.Run(true, found->second.Clone());
+}
+
+void LevelDBWrapperImpl::GetAll(const mojo::String& source,
+ const GetAllCallback& callback) {
+
+ mojo::Array<mojom::KeyValuePtr> all(map_.size());
+ for (const auto& it : map_) {
+ mojom::KeyValuePtr kv = mojom::KeyValue::New();
+ kv->key = it.first.Clone();
+ kv->value = it.second.Clone();
+ all.push_back(std::move(kv));
+ }
+ callback.Run(leveldb::DatabaseError::OK, std::move(all));
+ observers_.ForAllPtrs(
+ [source](mojom::LevelDBObserver* observer) {
+ observer->GetAllComplete(source);
+ });
+}
+
+void LevelDBWrapperImpl::OnConnectionError() {
+ if (!bindings_.empty())
+ return;
+
+ no_bindings_callback_.Run();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/leveldb_wrapper_impl.h b/chromium/content/browser/leveldb_wrapper_impl.h
new file mode 100644
index 00000000000..c96edf9ca6b
--- /dev/null
+++ b/chromium/content/browser/leveldb_wrapper_impl.h
@@ -0,0 +1,68 @@
+// 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 CONTENT_BROWSER_LEVELDB_WRAPPER_IMPL_H_
+#define CONTENT_BROWSER_LEVELDB_WRAPPER_IMPL_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "content/common/leveldb_wrapper.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+
+namespace content {
+
+// This is a wrapper around a leveldb::LevelDBDatabase. It adds a couple of
+// features:
+// 1) Adds the given prefix, if any, to all keys. This allows the sharing of one
+// database across many, possibly untrusted, consumers and ensuring that they
+// can't access each other's values.
+// 2) Enforces a max_size constraint.
+// 3) Informs an observer when the given prefix' values are modified.
+// 4) Throttles requests to avoid overwhelming the disk.
+class LevelDBWrapperImpl : public mojom::LevelDBWrapper {
+ public:
+ // |no_bindings_callback| will be called when this object has no more
+ // bindings.
+ LevelDBWrapperImpl(leveldb::LevelDBDatabase* database,
+ const std::string& prefix,
+ size_t max_size,
+ const base::Closure& no_bindings_callback);
+ ~LevelDBWrapperImpl() override;
+
+ void Bind(mojom::LevelDBWrapperRequest request);
+ void AddObserver(mojom::LevelDBObserverPtr observer);
+
+ private:
+ // LevelDBWrapperImpl:
+ void Put(mojo::Array<uint8_t> key,
+ mojo::Array<uint8_t> value,
+ const mojo::String& source,
+ const PutCallback& callback) override;
+ void Delete(mojo::Array<uint8_t> key,
+ const mojo::String& source,
+ const DeleteCallback& callback) override;
+ void DeleteAll(const mojo::String& source,
+ const DeleteAllCallback& callback) override;
+ void Get(mojo::Array<uint8_t> key, const GetCallback& callback) override;
+ void GetAll(const mojo::String& source,
+ const GetAllCallback& callback) override;
+
+ void OnConnectionError();
+
+ std::string prefix_;
+ mojo::BindingSet<mojom::LevelDBWrapper> bindings_;
+ mojo::InterfacePtrSet<mojom::LevelDBObserver> observers_;
+ base::Closure no_bindings_callback_;
+ leveldb::LevelDBDatabase* database_;
+ std::map<mojo::Array<uint8_t>, mojo::Array<uint8_t>> map_;
+ size_t bytes_used_;
+ size_t max_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(LevelDBWrapperImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LEVELDB_WRAPPER_IMPL_H_
diff --git a/chromium/content/browser/loader/async_resource_handler.cc b/chromium/content/browser/loader/async_resource_handler.cc
index df08aa79537..599767b01c1 100644
--- a/chromium/content/browser/loader/async_resource_handler.cc
+++ b/chromium/content/browser/loader/async_resource_handler.cc
@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/debug/alias.h"
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/shared_memory.h"
@@ -26,10 +27,10 @@
#include "content/common/resource_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/resource_response.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
-#include "net/base/net_util.h"
#include "net/log/net_log.h"
#include "net/url_request/redirect_info.h"
@@ -45,6 +46,14 @@ static int kMaxAllocationSize = 1024 * 32;
// The interval for calls to ReportUploadProgress.
static int kUploadProgressIntervalMsec = 10;
+// Used when kOptimizeIPCForSmallResource is enabled.
+// Small resource typically issues two Read call: one for the content itself
+// and another for getting zero response to detect EOF.
+// Inline these two into the IPC message to avoid allocating an expensive
+// SharedMemory for small resources.
+const int kNumLeadingChunk = 2;
+const int kInlinedLeadingChunkSize = 2048;
+
void GetNumericArg(const std::string& name, int* result) {
const std::string& value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
@@ -65,6 +74,111 @@ void InitializeResourceBufferConstants() {
} // namespace
+// Used when kOptimizeIPCForSmallResource is enabled.
+// The instance hooks the buffer allocation of AsyncResourceHandler, and
+// determine if we should use SharedMemory or should inline the data into
+// the IPC message.
+class AsyncResourceHandler::InliningHelper {
+ public:
+
+ InliningHelper() {}
+ ~InliningHelper() {}
+
+ void OnResponseReceived(const ResourceResponse& response) {
+ InliningStatus status = IsInliningApplicable(response);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.ResourceLoader.InliningStatus",
+ static_cast<int>(status),
+ static_cast<int>(InliningStatus::INLINING_STATUS_COUNT));
+ inlining_applicable_ = status == InliningStatus::APPLICABLE;
+ }
+
+ // Returns true if InliningHelper allocates the buffer for inlining.
+ bool PrepareInlineBufferIfApplicable(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size) {
+ ++num_allocation_;
+
+ // If the server sends the resource in multiple small chunks,
+ // |num_allocation_| may exceed |kNumLeadingChunk|. Disable inlining and
+ // fall back to the regular resource loading path in that case.
+ if (!inlining_applicable_ ||
+ num_allocation_ > kNumLeadingChunk ||
+ !base::FeatureList::IsEnabled(features::kOptimizeIPCForSmallResource)) {
+ return false;
+ }
+
+ leading_chunk_buffer_ = new net::IOBuffer(kInlinedLeadingChunkSize);
+ *buf = leading_chunk_buffer_;
+ *buf_size = kInlinedLeadingChunkSize;
+ return true;
+ }
+
+ // Returns true if the received data is sent to the consumer.
+ bool SendInlinedDataIfApplicable(int bytes_read,
+ int encoded_data_length,
+ IPC::Sender* sender,
+ int request_id) {
+ DCHECK(sender);
+ if (!leading_chunk_buffer_)
+ return false;
+
+ std::vector<char> data(
+ leading_chunk_buffer_->data(),
+ leading_chunk_buffer_->data() + bytes_read);
+ leading_chunk_buffer_ = nullptr;
+
+ sender->Send(new ResourceMsg_InlinedDataChunkReceived(
+ request_id, data, encoded_data_length));
+ return true;
+ }
+
+ void RecordHistogram(int64_t elapsed_time) {
+ if (inlining_applicable_) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.ResourceLoader.ResponseStartToEnd.InliningApplicable",
+ elapsed_time, 1, 100000, 100);
+ }
+ }
+
+ private:
+ enum class InliningStatus : int {
+ APPLICABLE = 0,
+ EARLY_ALLOCATION = 1,
+ UNKNOWN_CONTENT_LENGTH = 2,
+ LARGE_CONTENT = 3,
+ HAS_TRANSFER_ENCODING = 4,
+ HAS_CONTENT_ENCODING = 5,
+ INLINING_STATUS_COUNT,
+ };
+
+ InliningStatus IsInliningApplicable(const ResourceResponse& response) {
+ // Disable if the leading chunk is already arrived.
+ if (num_allocation_)
+ return InliningStatus::EARLY_ALLOCATION;
+
+ // Disable if the content is known to be large.
+ if (response.head.content_length > kInlinedLeadingChunkSize)
+ return InliningStatus::LARGE_CONTENT;
+
+ // Disable if the length of the content is unknown.
+ if (response.head.content_length < 0)
+ return InliningStatus::UNKNOWN_CONTENT_LENGTH;
+
+ if (response.head.headers) {
+ if (response.head.headers->HasHeader("Transfer-Encoding"))
+ return InliningStatus::HAS_TRANSFER_ENCODING;
+ if (response.head.headers->HasHeader("Content-Encoding"))
+ return InliningStatus::HAS_CONTENT_ENCODING;
+ }
+
+ return InliningStatus::APPLICABLE;
+ }
+
+ int num_allocation_ = 0;
+ bool inlining_applicable_ = false;
+ scoped_refptr<net::IOBuffer> leading_chunk_buffer_;
+};
+
class DependentIOBuffer : public net::WrappedIOBuffer {
public:
DependentIOBuffer(ResourceBuffer* backing, char* memory)
@@ -87,7 +201,8 @@ AsyncResourceHandler::AsyncResourceHandler(
did_defer_(false),
has_checked_for_sufficient_resources_(false),
sent_received_response_msg_(false),
- sent_first_data_msg_(false),
+ sent_data_buffer_msg_(false),
+ inlining_helper_(new InliningHelper),
last_upload_position_(0),
waiting_for_upload_progress_ack_(false),
reported_transfer_size_(0) {
@@ -207,6 +322,8 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
// request commits, avoiding the possibility of e.g. zooming the old content
// or of having to layout the new content twice.
+ response_started_ticks_ = base::TimeTicks::Now();
+
progress_timer_.Stop();
const ResourceRequestInfoImpl* info = GetRequestInfo();
if (!info->filter())
@@ -264,6 +381,7 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
copy));
}
+ inlining_helper_->OnResponseReceived(*response);
return true;
}
@@ -289,6 +407,14 @@ bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int min_size) {
DCHECK_EQ(-1, min_size);
+ if (!CheckForSufficientResource())
+ return false;
+
+ // Return early if InliningHelper allocates the buffer, so that we should
+ // inline the data into the IPC message without allocating SharedMemory.
+ if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size))
+ return true;
+
if (!EnsureResourceBufferIsInitialized())
return false;
@@ -312,31 +438,28 @@ bool AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
if (!filter)
return false;
+ int encoded_data_length = CalculateEncodedDataLengthToReport();
+
+ // Return early if InliningHelper handled the received data.
+ if (inlining_helper_->SendInlinedDataIfApplicable(
+ bytes_read, encoded_data_length, filter, GetRequestID()))
+ return true;
+
buffer_->ShrinkLastAllocation(bytes_read);
- if (!sent_first_data_msg_) {
- base::SharedMemoryHandle handle;
- int size;
- if (!buffer_->ShareToProcess(filter->PeerHandle(), &handle, &size))
+ if (!sent_data_buffer_msg_) {
+ base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle(
+ buffer_->GetSharedMemory().handle());
+ if (!base::SharedMemory::IsHandleValid(handle))
return false;
-
- // TODO(erikchen): Temporary debugging. http://crbug.com/527588.
- CHECK_LE(size, kBufferSize);
filter->Send(new ResourceMsg_SetDataBuffer(
- GetRequestID(), handle, size, filter->peer_pid()));
- sent_first_data_msg_ = true;
+ GetRequestID(), handle, buffer_->GetSharedMemory().mapped_size(),
+ filter->peer_pid()));
+ sent_data_buffer_msg_ = true;
}
int data_offset = buffer_->GetLastAllocationOffset();
- int64_t current_transfer_size = request()->GetTotalReceivedBytes();
- int encoded_data_length = current_transfer_size - reported_transfer_size_;
- reported_transfer_size_ = current_transfer_size;
-
- // TODO(erikchen): Temporary debugging. http://crbug.com/527588.
- CHECK_LE(data_offset, kBufferSize);
-
- filter->Send(new ResourceMsg_DataReceivedDebug(GetRequestID(), data_offset));
filter->Send(new ResourceMsg_DataReceived(
GetRequestID(), data_offset, bytes_read, encoded_data_length));
++pending_data_count_;
@@ -350,9 +473,7 @@ bool AsyncResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
}
void AsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
- int64_t current_transfer_size = request()->GetTotalReceivedBytes();
- int encoded_data_length = current_transfer_size - reported_transfer_size_;
- reported_transfer_size_ = current_transfer_size;
+ int encoded_data_length = CalculateEncodedDataLengthToReport();
ResourceMessageFilter* filter = GetFilter();
if (filter) {
@@ -412,20 +533,17 @@ void AsyncResourceHandler::OnResponseCompleted(
request()->GetTotalReceivedBytes();
info->filter()->Send(
new ResourceMsg_RequestComplete(GetRequestID(), request_complete_data));
+
+ if (status.is_success())
+ RecordHistogram();
}
bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() {
+ DCHECK(has_checked_for_sufficient_resources_);
+
if (buffer_.get() && buffer_->IsInitialized())
return true;
- if (!has_checked_for_sufficient_resources_) {
- has_checked_for_sufficient_resources_ = true;
- if (!rdh_->HasSufficientResourcesForRequest(request())) {
- controller()->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
- return false;
- }
- }
-
buffer_ = new ResourceBuffer();
return buffer_->Initialize(kBufferSize,
kMinAllocationSize,
@@ -444,4 +562,49 @@ void AsyncResourceHandler::OnDefer() {
request()->LogBlockedBy("AsyncResourceHandler");
}
+bool AsyncResourceHandler::CheckForSufficientResource() {
+ if (has_checked_for_sufficient_resources_)
+ return true;
+ has_checked_for_sufficient_resources_ = true;
+
+ if (rdh_->HasSufficientResourcesForRequest(request()))
+ return true;
+
+ controller()->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
+ return false;
+}
+
+int AsyncResourceHandler::CalculateEncodedDataLengthToReport() {
+ int64_t current_transfer_size = request()->GetTotalReceivedBytes();
+ int encoded_data_length = current_transfer_size - reported_transfer_size_;
+ reported_transfer_size_ = current_transfer_size;
+ return encoded_data_length;
+}
+
+void AsyncResourceHandler::RecordHistogram() {
+ int64_t elapsed_time =
+ (base::TimeTicks::Now() - response_started_ticks_).InMicroseconds();
+ int64_t encoded_length = request()->GetTotalReceivedBytes();
+ if (encoded_length < 2 * 1024) {
+ // The resource was smaller than the smallest required buffer size.
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ResourceLoader.ResponseStartToEnd.LT_2kB",
+ elapsed_time, 1, 100000, 100);
+ } else if (encoded_length < 32 * 1024) {
+ // The resource was smaller than single chunk.
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ResourceLoader.ResponseStartToEnd.LT_32kB",
+ elapsed_time, 1, 100000, 100);
+ } else if (encoded_length < 512 * 1024) {
+ // The resource was smaller than single chunk.
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.ResourceLoader.ResponseStartToEnd.LT_512kB",
+ elapsed_time, 1, 100000, 100);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.ResourceLoader.ResponseStartToEnd.Over_512kB",
+ elapsed_time, 1, 100000, 100);
+ }
+
+ inlining_helper_->RecordHistogram(elapsed_time);
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/async_resource_handler.h b/chromium/content/browser/loader/async_resource_handler.h
index d7f70c2b504..09910213360 100644
--- a/chromium/content/browser/loader/async_resource_handler.h
+++ b/chromium/content/browser/loader/async_resource_handler.h
@@ -14,6 +14,7 @@
#include "base/timer/timer.h"
#include "content/browser/loader/resource_handler.h"
#include "content/browser/loader/resource_message_delegate.h"
+#include "net/base/io_buffer.h"
#include "url/gurl.h"
namespace net {
@@ -55,6 +56,8 @@ class AsyncResourceHandler : public ResourceHandler,
void OnDataDownloaded(int bytes_downloaded) override;
private:
+ class InliningHelper;
+
// IPC message handlers:
void OnFollowRedirect(int request_id);
void OnDataReceivedACK(int request_id);
@@ -65,6 +68,9 @@ class AsyncResourceHandler : public ResourceHandler,
bool EnsureResourceBufferIsInitialized();
void ResumeIfDeferred();
void OnDefer();
+ bool CheckForSufficientResource();
+ int CalculateEncodedDataLengthToReport();
+ void RecordHistogram();
scoped_refptr<ResourceBuffer> buffer_;
ResourceDispatcherHostImpl* rdh_;
@@ -79,7 +85,10 @@ class AsyncResourceHandler : public ResourceHandler,
bool has_checked_for_sufficient_resources_;
bool sent_received_response_msg_;
- bool sent_first_data_msg_;
+ bool sent_data_buffer_msg_;
+
+ std::unique_ptr<InliningHelper> inlining_helper_;
+ base::TimeTicks response_started_ticks_;
uint64_t last_upload_position_;
bool waiting_for_upload_progress_ack_;
diff --git a/chromium/content/browser/loader/async_resource_handler_browsertest.cc b/chromium/content/browser/loader/async_resource_handler_browsertest.cc
index 456c31a544f..4a9c4409534 100644
--- a/chromium/content/browser/loader/async_resource_handler_browsertest.cc
+++ b/chromium/content/browser/loader/async_resource_handler_browsertest.cc
@@ -40,10 +40,10 @@ const size_t kPayloadSize = 1062882; // 2*3^12
const size_t kPayloadSize = 28697814; // 2*3^15
#endif
-scoped_ptr<net::test_server::HttpResponse> HandlePostAndRedirectURLs(
- const std::string& request_path,
- const net::test_server::HttpRequest& request) {
- scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+std::unique_ptr<net::test_server::HttpResponse> HandlePostAndRedirectURLs(
+ const std::string& request_path,
+ const net::test_server::HttpRequest& request) {
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse());
if (base::StartsWith(request.relative_url, kRedirectPostPath,
base::CompareCase::SENSITIVE)) {
@@ -58,7 +58,7 @@ scoped_ptr<net::test_server::HttpResponse> HandlePostAndRedirectURLs(
EXPECT_EQ(request.content.length(), kPayloadSize);
return std::move(http_response);
} else {
- return scoped_ptr<net::test_server::HttpResponse>();
+ return std::unique_ptr<net::test_server::HttpResponse>();
}
}
diff --git a/chromium/content/browser/loader/async_revalidation_driver.cc b/chromium/content/browser/loader/async_revalidation_driver.cc
index 3c5d45bc13b..b04d32af91f 100644
--- a/chromium/content/browser/loader/async_revalidation_driver.cc
+++ b/chromium/content/browser/loader/async_revalidation_driver.cc
@@ -37,8 +37,8 @@ const int kReadTimeoutInSeconds = 30;
} // namespace
AsyncRevalidationDriver::AsyncRevalidationDriver(
- scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceThrottle> throttle,
+ std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceThrottle> throttle,
const base::Closure& completion_callback)
: request_(std::move(request)),
throttle_(std::move(throttle)),
diff --git a/chromium/content/browser/loader/async_revalidation_driver.h b/chromium/content/browser/loader/async_revalidation_driver.h
index b96e06ebd5c..4caf263cf85 100644
--- a/chromium/content/browser/loader/async_revalidation_driver.h
+++ b/chromium/content/browser/loader/async_revalidation_driver.h
@@ -5,12 +5,12 @@
#ifndef CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_DRIVER_H_
#define CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_DRIVER_H_
+#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "content/common/content_export.h"
@@ -33,8 +33,8 @@ class CONTENT_EXPORT AsyncRevalidationDriver : public net::URLRequest::Delegate,
public:
// |completion_callback| is guaranteed to be called on completion,
// regardless of success or failure.
- AsyncRevalidationDriver(scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceThrottle> throttle,
+ AsyncRevalidationDriver(std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceThrottle> throttle,
const base::Closure& completion_callback);
~AsyncRevalidationDriver() override;
@@ -89,8 +89,8 @@ class CONTENT_EXPORT AsyncRevalidationDriver : public net::URLRequest::Delegate,
scoped_refptr<net::IOBuffer> read_buffer_;
base::OneShotTimer timer_;
- scoped_ptr<net::URLRequest> request_;
- scoped_ptr<ResourceThrottle> throttle_;
+ std::unique_ptr<net::URLRequest> request_;
+ std::unique_ptr<ResourceThrottle> throttle_;
base::Closure completion_callback_;
diff --git a/chromium/content/browser/loader/async_revalidation_driver_unittest.cc b/chromium/content/browser/loader/async_revalidation_driver_unittest.cc
index 1f5a7e4b1f0..a39d9fe3eca 100644
--- a/chromium/content/browser/loader/async_revalidation_driver_unittest.cc
+++ b/chromium/content/browser/loader/async_revalidation_driver_unittest.cc
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/common/content_client.h"
@@ -63,8 +64,8 @@ class ResourceThrottleStub : public ResourceThrottle {
// There are multiple layers of boilerplate needed to use a URLRequestTestJob
// subclass. Subclasses of AsyncRevalidationDriverTest can use
// BindCreateProtocolHandlerCallback() to bypass most of that boilerplate.
-using CreateProtocolHandlerCallback =
- base::Callback<scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>()>;
+using CreateProtocolHandlerCallback = base::Callback<
+ std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>()>;
template <typename T>
CreateProtocolHandlerCallback BindCreateProtocolHandlerCallback() {
@@ -75,8 +76,9 @@ CreateProtocolHandlerCallback BindCreateProtocolHandlerCallback() {
class TemplatedProtocolHandler
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- static scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> Create() {
- return make_scoped_ptr(new TemplatedProtocolHandler());
+ static std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
+ Create() {
+ return base::WrapUnique(new TemplatedProtocolHandler());
}
// URLRequestJobFactory::ProtocolHandler implementation:
@@ -132,14 +134,15 @@ class AsyncRevalidationDriverTest : public testing::Test {
}
void SetUpAsyncRevalidationDriverWithRequestToUrl(const GURL& url) {
- scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest(
- url, net::DEFAULT_PRIORITY, nullptr /* delegate */));
+ std::unique_ptr<net::URLRequest> request(
+ test_url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY,
+ nullptr /* delegate */));
raw_ptr_request_ = request.get();
raw_ptr_resource_throttle_ = new ResourceThrottleStub();
// This use of base::Unretained() is safe because |driver_|, and the closure
// passed to it, will be destroyed before this object is.
driver_.reset(new AsyncRevalidationDriver(
- std::move(request), make_scoped_ptr(raw_ptr_resource_throttle_),
+ std::move(request), base::WrapUnique(raw_ptr_resource_throttle_),
base::Bind(&AsyncRevalidationDriverTest::OnAsyncRevalidationComplete,
base::Unretained(this))));
}
@@ -170,7 +173,7 @@ class AsyncRevalidationDriverTest : public testing::Test {
// The AsyncRevalidationDriver owns the URLRequest and the ResourceThrottle.
ResourceThrottleStub* raw_ptr_resource_throttle_;
net::URLRequest* raw_ptr_request_;
- scoped_ptr<AsyncRevalidationDriver> driver_;
+ std::unique_ptr<AsyncRevalidationDriver> driver_;
bool async_revalidation_complete_called_ = false;
};
@@ -233,7 +236,8 @@ class MockClientCertURLRequestJob : public net::URLRequestTestJob {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
- weak_factory_.GetWeakPtr(), cert_request_info));
+ weak_factory_.GetWeakPtr(),
+ base::RetainedRef(cert_request_info)));
}
void ContinueWithCertificate(
@@ -276,7 +280,7 @@ class ScopedDontSelectCertificateBrowserClient
void SelectClientCertificate(
WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- scoped_ptr<ClientCertificateDelegate> delegate) override {
+ std::unique_ptr<ClientCertificateDelegate> delegate) override {
ADD_FAILURE() << "SelectClientCertificate was called.";
}
diff --git a/chromium/content/browser/loader/async_revalidation_manager.cc b/chromium/content/browser/loader/async_revalidation_manager.cc
index aaaeb68ab83..4b364023e37 100644
--- a/chromium/content/browser/loader/async_revalidation_manager.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager.cc
@@ -96,7 +96,7 @@ void AsyncRevalidationManager::BeginAsyncRevalidation(
for_request.url());
std::pair<AsyncRevalidationMap::iterator, bool> insert_result =
in_progress_.insert(AsyncRevalidationMap::value_type(
- async_revalidation_key, scoped_ptr<AsyncRevalidationDriver>()));
+ async_revalidation_key, std::unique_ptr<AsyncRevalidationDriver>()));
if (!insert_result.second) {
// A matching async revalidation is already in progress for this cache; we
// don't need another one.
@@ -107,7 +107,7 @@ void AsyncRevalidationManager::BeginAsyncRevalidation(
headers.AddHeadersFromString(info->original_headers());
// Construct the request.
- scoped_ptr<net::URLRequest> new_request = request_context->CreateRequest(
+ std::unique_ptr<net::URLRequest> new_request = request_context->CreateRequest(
for_request.url(), net::MINIMUM_PRIORITY, nullptr);
new_request->set_method(for_request.method());
@@ -139,7 +139,7 @@ void AsyncRevalidationManager::BeginAsyncRevalidation(
int child_id = info->GetChildID();
int route_id = info->GetRouteID();
- scoped_ptr<ResourceThrottle> throttle =
+ std::unique_ptr<ResourceThrottle> throttle =
scheduler->ScheduleRequest(child_id, route_id, false, new_request.get());
// AsyncRevalidationDriver does not outlive its entry in |in_progress_|,
diff --git a/chromium/content/browser/loader/async_revalidation_manager.h b/chromium/content/browser/loader/async_revalidation_manager.h
index 1070ea9c8bc..e866b4abc97 100644
--- a/chromium/content/browser/loader/async_revalidation_manager.h
+++ b/chromium/content/browser/loader/async_revalidation_manager.h
@@ -6,10 +6,10 @@
#define CONTENT_BROWSER_LOADER_ASYNC_REVALIDATION_MANAGER_H_
#include <map>
+#include <memory>
#include <string>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
class GURL;
struct ResourceHostMsg_Request;
@@ -89,9 +89,10 @@ class AsyncRevalidationManager {
};
};
- using AsyncRevalidationMap = std::map<AsyncRevalidationKey,
- scoped_ptr<AsyncRevalidationDriver>,
- AsyncRevalidationKey::LessThan>;
+ using AsyncRevalidationMap =
+ std::map<AsyncRevalidationKey,
+ std::unique_ptr<AsyncRevalidationDriver>,
+ AsyncRevalidationKey::LessThan>;
void OnAsyncRevalidationComplete(AsyncRevalidationMap::iterator it);
diff --git a/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc b/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
index f7999431b42..56b6a128b62 100644
--- a/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager_browsertest.cc
@@ -2,19 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/browser_side_navigation_policy.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"
@@ -42,6 +43,12 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
~AsyncRevalidationManagerBrowserTest() override {}
void SetUp() override {
+ base::FeatureList::ClearInstanceForTesting();
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(
+ "StaleWhileRevalidate2", std::string());
+ base::FeatureList::SetInstance(std::move(feature_list));
+
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
ContentBrowserTest::SetUp();
}
@@ -50,10 +57,6 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
embedded_test_server()->StartAcceptingConnections();
}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitch("enable-stale-while-revalidate");
- }
-
base::RunLoop* run_loop() { return &run_loop_; }
int requests_counted() const { return requests_counted_; }
@@ -80,13 +83,15 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
private:
// A request handler which increases the number in the title tag on every
// request.
- scoped_ptr<HttpResponse> CountingRequestHandler(const HttpRequest& request) {
+ std::unique_ptr<HttpResponse> CountingRequestHandler(
+ const HttpRequest& request) {
if (request.relative_url != kCountedHtmlPath)
return nullptr;
int version = ++requests_counted_;
- scoped_ptr<BasicHttpResponse> http_response(StaleWhileRevalidateHeaders());
+ std::unique_ptr<BasicHttpResponse> http_response(
+ StaleWhileRevalidateHeaders());
http_response->set_content(
base::StringPrintf("<title>Version %d</title>", version));
@@ -98,7 +103,8 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
}
// A request handler which increases a cookie value on every request.
- scoped_ptr<HttpResponse> CookieRequestHandler(const HttpRequest& request) {
+ std::unique_ptr<HttpResponse> CookieRequestHandler(
+ const HttpRequest& request) {
static const char kHtml[] =
"<script>\n"
"var intervalId;\n"
@@ -117,7 +123,8 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
int version = ++requests_counted_;
- scoped_ptr<BasicHttpResponse> http_response(StaleWhileRevalidateHeaders());
+ std::unique_ptr<BasicHttpResponse> http_response(
+ StaleWhileRevalidateHeaders());
http_response->AddCustomHeader("Set-Cookie",
base::StringPrintf("version=%d", version));
http_response->set_content(kHtml);
@@ -126,8 +133,8 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
}
// Generate the standard response headers common to all request handlers.
- scoped_ptr<BasicHttpResponse> StaleWhileRevalidateHeaders() {
- scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+ std::unique_ptr<BasicHttpResponse> StaleWhileRevalidateHeaders() {
+ std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
http_response->set_content_type("text/html; charset=utf-8");
http_response->AddCustomHeader("Cache-Control",
@@ -150,6 +157,10 @@ class AsyncRevalidationManagerBrowserTest : public ContentBrowserTest {
// triggers an async revalidation.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
StaleWhileRevalidateIsApplied) {
+ // PlzNavigate: Stale while revalidate is disabled.
+ // TODO(clamy): Re-enable the test when there is support.
+ if (IsBrowserSideNavigationEnabled())
+ return;
RegisterCountingRequestHandler();
GURL url(embedded_test_server()->GetURL(kCountedHtmlPath));
@@ -173,6 +184,10 @@ IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
// The fresh cache entry must become visible once the async revalidation request
// has been sent.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest, CacheIsUpdated) {
+ // PlzNavigate: Stale while revalidate is disabled.
+ // TODO(clamy): Re-enable the test when there is support.
+ if (IsBrowserSideNavigationEnabled())
+ return;
using base::ASCIIToUTF16;
RegisterCountingRequestHandler();
GURL url(embedded_test_server()->GetURL(kCountedHtmlPath));
@@ -201,6 +216,10 @@ IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest, CacheIsUpdated) {
// applied immediately.
IN_PROC_BROWSER_TEST_F(AsyncRevalidationManagerBrowserTest,
CookieSetAsynchronously) {
+ // PlzNavigate: Stale while revalidate is disabled.
+ // TODO(clamy): Re-enable the test when there is support.
+ if (IsBrowserSideNavigationEnabled())
+ return;
RegisterCookieRequestHandler();
GURL url(embedded_test_server()->GetURL(kCookieHtmlPath));
diff --git a/chromium/content/browser/loader/async_revalidation_manager_unittest.cc b/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
index d0ec206130d..09a70929d88 100644
--- a/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
+++ b/chromium/content/browser/loader/async_revalidation_manager_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory_handle.h"
#include "base/pickle.h"
#include "base/run_loop.h"
@@ -216,7 +217,7 @@ class BlackholeFilter : public ResourceMessageFilter {
}
bool Send(IPC::Message* msg) override {
- scoped_ptr<IPC::Message> take_ownership(msg);
+ std::unique_ptr<IPC::Message> take_ownership(msg);
ReleaseHandlesInMessage(*msg);
return true;
}
@@ -265,7 +266,7 @@ ResourceHostMsg_Request CreateResourceRequest(const char* method,
class AsyncRevalidationManagerTest : public ::testing::Test {
protected:
AsyncRevalidationManagerTest(
- scoped_ptr<net::TestNetworkDelegate> network_delegate)
+ std::unique_ptr<net::TestNetworkDelegate> network_delegate)
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
network_delegate_(std::move(network_delegate)) {
browser_context_.reset(new TestBrowserContext());
@@ -283,7 +284,7 @@ class AsyncRevalidationManagerTest : public ::testing::Test {
AsyncRevalidationManagerTest()
: AsyncRevalidationManagerTest(
- make_scoped_ptr(new net::TestNetworkDelegate)) {}
+ base::WrapUnique(new net::TestNetworkDelegate)) {}
void TearDown() override {
host_.CancelRequestsForProcess(filter_->child_id());
@@ -315,10 +316,10 @@ class AsyncRevalidationManagerTest : public ::testing::Test {
}
content::TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<TestBrowserContext> browser_context_;
- scoped_ptr<TestURLRequestJobFactory> job_factory_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
+ std::unique_ptr<TestURLRequestJobFactory> job_factory_;
scoped_refptr<BlackholeFilter> filter_;
- scoped_ptr<net::TestNetworkDelegate> network_delegate_;
+ std::unique_ptr<net::TestNetworkDelegate> network_delegate_;
ResourceDispatcherHostImpl host_;
};
@@ -417,7 +418,7 @@ class AsyncRevalidationManagerRecordingTest
public:
AsyncRevalidationManagerRecordingTest()
: AsyncRevalidationManagerTest(
- make_scoped_ptr(new URLRequestRecordingNetworkDelegate)) {}
+ base::WrapUnique(new URLRequestRecordingNetworkDelegate)) {}
void TearDown() override {
EXPECT_TRUE(IsEmpty());
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.cc b/chromium/content/browser/loader/cross_site_resource_handler.cc
index fad4024ee28..c645670d25c 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler.cc
+++ b/chromium/content/browser/loader/cross_site_resource_handler.cc
@@ -63,7 +63,7 @@ struct CrossSiteResponseParams {
};
void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
- scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request(
+ std::unique_ptr<CrossSiteTransferringRequest> cross_site_transferring_request(
new CrossSiteTransferringRequest(params.global_request_id));
RenderFrameHostImpl* rfh =
@@ -110,7 +110,7 @@ CheckNavigationPolicyOnUI(GURL real_url, int process_id, int render_frame_id) {
} // namespace
CrossSiteResourceHandler::CrossSiteResourceHandler(
- scoped_ptr<ResourceHandler> next_handler,
+ std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request)
: LayeredResourceHandler(request, std::move(next_handler)),
has_started_response_(false),
@@ -327,7 +327,8 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
int render_frame_id = info->GetRenderFrameID();
transfer_url_chain = request()->url_chain();
referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
- ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id);
+ ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id,
+ response_);
BrowserThread::PostTask(
BrowserThread::UI,
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.h b/chromium/content/browser/loader/cross_site_resource_handler.h
index 3c38fc758d4..61cb935a13e 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler.h
+++ b/chromium/content/browser/loader/cross_site_resource_handler.h
@@ -33,7 +33,7 @@ class CrossSiteResourceHandler : public LayeredResourceHandler {
CANCEL_REQUEST
};
- CrossSiteResourceHandler(scoped_ptr<ResourceHandler> next_handler,
+ CrossSiteResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request);
~CrossSiteResourceHandler() override;
diff --git a/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc b/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
index a6df689d032..eea52307c73 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
+++ b/chromium/content/browser/loader/cross_site_resource_handler_browsertest.cc
@@ -97,7 +97,8 @@ class TestResourceDispatcherHostDelegate
CallbackRunningResourceThrottle(net::URLRequest* request,
TestResourceDispatcherHostDelegate* tracker,
const RequestDeferredHook& run_on_start)
- : request_(request),
+ : resumed_(false),
+ request_(request),
tracker_(tracker),
run_on_start_(run_on_start),
weak_factory_(this) {}
@@ -116,9 +117,12 @@ class TestResourceDispatcherHostDelegate
~CallbackRunningResourceThrottle() override {
// If the request is deleted without being cancelled, its status will
// indicate it succeeded, so have to check if the request is still pending
- // as well.
+ // as well. If the request never even started, the throttle will never
+ // resume it. Check this condition as well to allow for early
+ // cancellation.
tracker_->OnTrackedRequestDestroyed(!request_->is_pending() &&
- request_->status().is_success());
+ request_->status().is_success() &&
+ resumed_);
}
// ResourceThrottle implementation:
@@ -127,7 +131,12 @@ class TestResourceDispatcherHostDelegate
}
private:
- void Resume() { controller()->Resume(); }
+ void Resume() {
+ resumed_ = true;
+ controller()->Resume();
+ }
+
+ bool resumed_;
net::URLRequest* request_;
TestResourceDispatcherHostDelegate* tracker_;
RequestDeferredHook run_on_start_;
@@ -163,7 +172,7 @@ class TestResourceDispatcherHostDelegate
RequestDeferredHook run_on_start_;
// This lives on the UI thread.
- scoped_ptr<base::RunLoop> run_loop_;
+ std::unique_ptr<base::RunLoop> run_loop_;
// Set on the IO thread while |run_loop_| is non-nullptr, read on the UI
// thread after deleting run_loop_.
diff --git a/chromium/content/browser/loader/detachable_resource_handler.cc b/chromium/content/browser/loader/detachable_resource_handler.cc
index 786252f5b6b..4e1bb8adee6 100644
--- a/chromium/content/browser/loader/detachable_resource_handler.cc
+++ b/chromium/content/browser/loader/detachable_resource_handler.cc
@@ -24,7 +24,7 @@ namespace content {
DetachableResourceHandler::DetachableResourceHandler(
net::URLRequest* request,
base::TimeDelta cancel_delay,
- scoped_ptr<ResourceHandler> next_handler)
+ std::unique_ptr<ResourceHandler> next_handler)
: ResourceHandler(request),
next_handler_(std::move(next_handler)),
cancel_delay_(cancel_delay),
diff --git a/chromium/content/browser/loader/detachable_resource_handler.h b/chromium/content/browser/loader/detachable_resource_handler.h
index 95072269956..5db9a159795 100644
--- a/chromium/content/browser/loader/detachable_resource_handler.h
+++ b/chromium/content/browser/loader/detachable_resource_handler.h
@@ -5,10 +5,11 @@
#ifndef CONTENT_BROWSER_LOADER_DETACHABLE_RESOURCE_HANDLER_H_
#define CONTENT_BROWSER_LOADER_DETACHABLE_RESOURCE_HANDLER_H_
+#include <memory>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "content/browser/loader/resource_handler.h"
@@ -36,7 +37,7 @@ class DetachableResourceHandler : public ResourceHandler,
public:
DetachableResourceHandler(net::URLRequest* request,
base::TimeDelta cancel_delay,
- scoped_ptr<ResourceHandler> next_handler);
+ std::unique_ptr<ResourceHandler> next_handler);
~DetachableResourceHandler() override;
bool is_detached() const { return next_handler_ == NULL; }
@@ -70,10 +71,10 @@ class DetachableResourceHandler : public ResourceHandler,
void CancelWithError(int error_code) override;
private:
- scoped_ptr<ResourceHandler> next_handler_;
+ std::unique_ptr<ResourceHandler> next_handler_;
scoped_refptr<net::IOBuffer> read_buffer_;
- scoped_ptr<base::OneShotTimer> detached_timer_;
+ std::unique_ptr<base::OneShotTimer> detached_timer_;
base::TimeDelta cancel_delay_;
bool is_deferred_;
diff --git a/chromium/content/browser/loader/global_routing_id.h b/chromium/content/browser/loader/global_routing_id.h
index df5f202c22e..3f5aadf94c0 100644
--- a/chromium/content/browser/loader/global_routing_id.h
+++ b/chromium/content/browser/loader/global_routing_id.h
@@ -7,6 +7,8 @@
#include <tuple>
+#include "ipc/ipc_message.h"
+
namespace content {
// Uniquely identifies the route from which a net::URLRequest comes.
@@ -38,6 +40,33 @@ struct GlobalRoutingID {
}
};
+// Same as GlobalRoutingID except the route_id must be a RenderFrameHost routing
+// id.
+struct GlobalFrameRoutingId {
+ GlobalFrameRoutingId() : child_id(0), frame_routing_id(MSG_ROUTING_NONE) {}
+
+ GlobalFrameRoutingId(int child_id, int frame_routing_id)
+ : child_id(child_id), frame_routing_id(frame_routing_id) {}
+
+ // The unique ID of the child process (different from OS's PID).
+ int child_id;
+
+ // The route ID (unique for each URLRequest source).
+ int frame_routing_id;
+
+ bool operator<(const GlobalFrameRoutingId& other) const {
+ return std::tie(child_id, frame_routing_id) <
+ std::tie(other.child_id, other.frame_routing_id);
+ }
+ bool operator==(const GlobalFrameRoutingId& other) const {
+ return child_id == other.child_id &&
+ frame_routing_id == other.frame_routing_id;
+ }
+ bool operator!=(const GlobalFrameRoutingId& other) const {
+ return !(*this == other);
+ }
+};
+
} // namespace content
#endif // CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
diff --git a/chromium/content/browser/loader/layered_resource_handler.cc b/chromium/content/browser/loader/layered_resource_handler.cc
index 9ff3d55e6f3..eada59a93f8 100644
--- a/chromium/content/browser/loader/layered_resource_handler.cc
+++ b/chromium/content/browser/loader/layered_resource_handler.cc
@@ -12,7 +12,7 @@ namespace content {
LayeredResourceHandler::LayeredResourceHandler(
net::URLRequest* request,
- scoped_ptr<ResourceHandler> next_handler)
+ std::unique_ptr<ResourceHandler> next_handler)
: ResourceHandler(request), next_handler_(std::move(next_handler)) {}
LayeredResourceHandler::~LayeredResourceHandler() {
diff --git a/chromium/content/browser/loader/layered_resource_handler.h b/chromium/content/browser/loader/layered_resource_handler.h
index 6c37dff5b0e..a71b40c41f1 100644
--- a/chromium/content/browser/loader/layered_resource_handler.h
+++ b/chromium/content/browser/loader/layered_resource_handler.h
@@ -5,7 +5,8 @@
#ifndef CONTENT_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
#define CONTENT_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
-#include "base/memory/scoped_ptr.h"
+#include <memory>
+
#include "content/browser/loader/resource_handler.h"
#include "content/common/content_export.h"
@@ -20,7 +21,7 @@ namespace content {
class CONTENT_EXPORT LayeredResourceHandler : public ResourceHandler {
public:
LayeredResourceHandler(net::URLRequest* request,
- scoped_ptr<ResourceHandler> next_handler);
+ std::unique_ptr<ResourceHandler> next_handler);
~LayeredResourceHandler() override;
// ResourceHandler implementation:
@@ -40,7 +41,7 @@ class CONTENT_EXPORT LayeredResourceHandler : public ResourceHandler {
bool* defer) override;
void OnDataDownloaded(int bytes_downloaded) override;
- scoped_ptr<ResourceHandler> next_handler_;
+ std::unique_ptr<ResourceHandler> next_handler_;
};
} // namespace content
diff --git a/chromium/content/browser/loader/mime_type_resource_handler.cc b/chromium/content/browser/loader/mime_type_resource_handler.cc
index 3c69c0ad4d2..2d23d131502 100644
--- a/chromium/content/browser/loader/mime_type_resource_handler.cc
+++ b/chromium/content/browser/loader/mime_type_resource_handler.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
@@ -35,35 +35,19 @@
#include "net/base/net_errors.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request.h"
namespace content {
namespace {
-void RecordSnifferMetrics(bool sniffing_blocked,
- bool we_would_like_to_sniff,
- const std::string& mime_type) {
- static base::HistogramBase* nosniff_usage(NULL);
- if (!nosniff_usage)
- nosniff_usage = base::BooleanHistogram::FactoryGet(
- "nosniff.usage", base::HistogramBase::kUmaTargetedHistogramFlag);
- nosniff_usage->AddBoolean(sniffing_blocked);
-
- if (sniffing_blocked) {
- static base::HistogramBase* nosniff_otherwise(NULL);
- if (!nosniff_otherwise)
- nosniff_otherwise = base::BooleanHistogram::FactoryGet(
- "nosniff.otherwise", base::HistogramBase::kUmaTargetedHistogramFlag);
- nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
-
- static base::HistogramBase* nosniff_empty_mime_type(NULL);
- if (!nosniff_empty_mime_type)
- nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet(
- "nosniff.empty_mime_type",
- base::HistogramBase::kUmaTargetedHistogramFlag);
- nosniff_empty_mime_type->AddBoolean(mime_type.empty());
- }
-}
+const char kAcceptHeader[] = "Accept";
+const char kFrameAcceptHeader[] =
+ "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
+ "*/*;q=0.8";
+const char kStylesheetAcceptHeader[] = "text/css,*/*;q=0.1";
+const char kImageAcceptHeader[] = "image/webp,image/*,*/*;q=0.8";
+const char kDefaultAcceptHeader[] = "*/*";
// Used to write into an existing IOBuffer at a given offset.
class DependentIOBuffer : public net::WrappedIOBuffer {
@@ -82,7 +66,7 @@ class DependentIOBuffer : public net::WrappedIOBuffer {
} // namespace
MimeTypeResourceHandler::MimeTypeResourceHandler(
- scoped_ptr<ResourceHandler> next_handler,
+ std::unique_ptr<ResourceHandler> next_handler,
ResourceDispatcherHostImpl* host,
PluginService* plugin_service,
net::URLRequest* request)
@@ -141,6 +125,46 @@ bool MimeTypeResourceHandler::OnResponseStarted(ResourceResponse* response,
return ProcessResponse(defer);
}
+bool MimeTypeResourceHandler::OnWillStart(const GURL& url, bool* defer) {
+ const char* accept_value = nullptr;
+ switch (GetRequestInfo()->GetResourceType()) {
+ case RESOURCE_TYPE_MAIN_FRAME:
+ case RESOURCE_TYPE_SUB_FRAME:
+ accept_value = kFrameAcceptHeader;
+ break;
+ case RESOURCE_TYPE_STYLESHEET:
+ accept_value = kStylesheetAcceptHeader;
+ break;
+ case RESOURCE_TYPE_IMAGE:
+ accept_value = kImageAcceptHeader;
+ break;
+ case RESOURCE_TYPE_SCRIPT:
+ case RESOURCE_TYPE_FONT_RESOURCE:
+ case RESOURCE_TYPE_SUB_RESOURCE:
+ case RESOURCE_TYPE_OBJECT:
+ case RESOURCE_TYPE_MEDIA:
+ case RESOURCE_TYPE_WORKER:
+ case RESOURCE_TYPE_SHARED_WORKER:
+ case RESOURCE_TYPE_PREFETCH:
+ case RESOURCE_TYPE_FAVICON:
+ case RESOURCE_TYPE_XHR:
+ case RESOURCE_TYPE_PING:
+ case RESOURCE_TYPE_SERVICE_WORKER:
+ case RESOURCE_TYPE_CSP_REPORT:
+ case RESOURCE_TYPE_PLUGIN_RESOURCE:
+ accept_value = kDefaultAcceptHeader;
+ break;
+ case RESOURCE_TYPE_LAST_TYPE:
+ NOTREACHED();
+ break;
+ }
+
+ // The false parameter prevents overwriting an existing accept header value,
+ // which is needed because JS can manually set an accept header on an XHR.
+ request()->SetExtraRequestHeaderByName(kAcceptHeader, accept_value, false);
+ return next_handler_->OnWillStart(url, defer);
+}
+
bool MimeTypeResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) {
@@ -260,8 +284,6 @@ bool MimeTypeResourceHandler::ShouldSniffContent() {
bool we_would_like_to_sniff =
net::ShouldSniffMimeType(request()->url(), mime_type);
- RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
-
if (!sniffing_blocked && we_would_like_to_sniff) {
// We're going to look at the data before deciding what the content type
// is. That means we need to delay sending the ResponseStarted message
@@ -324,7 +346,7 @@ bool MimeTypeResourceHandler::SelectPluginHandler(bool* defer,
if (has_plugin)
plugin_path = plugin.path;
std::string payload;
- scoped_ptr<ResourceHandler> handler(host_->MaybeInterceptAsStream(
+ std::unique_ptr<ResourceHandler> handler(host_->MaybeInterceptAsStream(
plugin_path, request(), response_.get(), &payload));
if (handler) {
*handled_by_plugin = true;
@@ -384,19 +406,15 @@ bool MimeTypeResourceHandler::SelectNextHandler(bool* defer) {
// Install download handler
info->set_is_download(true);
- scoped_ptr<ResourceHandler> handler(
- host_->CreateResourceHandlerForDownload(
- request(),
- true, // is_content_initiated
- must_download,
- DownloadItem::kInvalidId,
- scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()),
- DownloadUrlParameters::OnStartedCallback()));
+ std::unique_ptr<ResourceHandler> handler(
+ host_->CreateResourceHandlerForDownload(request(),
+ true, // is_content_initiated
+ must_download));
return UseAlternateNextHandler(std::move(handler), std::string());
}
bool MimeTypeResourceHandler::UseAlternateNextHandler(
- scoped_ptr<ResourceHandler> new_handler,
+ std::unique_ptr<ResourceHandler> new_handler,
const std::string& payload_for_old_handler) {
if (response_->head.headers.get() && // Can be NULL if FTP.
response_->head.headers->response_code() / 100 != 2) {
diff --git a/chromium/content/browser/loader/mime_type_resource_handler.h b/chromium/content/browser/loader/mime_type_resource_handler.h
index 9217683584d..cef22b77b65 100644
--- a/chromium/content/browser/loader/mime_type_resource_handler.h
+++ b/chromium/content/browser/loader/mime_type_resource_handler.h
@@ -34,12 +34,16 @@ struct WebPluginInfo;
// subsequent reads until it's done buffering. As a result, the buffer
// returned by the next ResourceHandler must have a capacity of at least
// net::kMaxBytesToSniff * 2.
+//
+// Before a request is sent, this ResourceHandler will also set an appropriate
+// Accept header on the request based on its ResourceType, if one isn't already
+// present.
class CONTENT_EXPORT MimeTypeResourceHandler
: public LayeredResourceHandler,
public ResourceController {
public:
// If ENABLE_PLUGINS is defined, |plugin_service| must not be NULL.
- MimeTypeResourceHandler(scoped_ptr<ResourceHandler> next_handler,
+ MimeTypeResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
ResourceDispatcherHostImpl* host,
PluginService* plugin_service,
net::URLRequest* request);
@@ -49,6 +53,7 @@ class CONTENT_EXPORT MimeTypeResourceHandler
// ResourceHandler implementation:
void SetController(ResourceController* controller) override;
bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL&, bool* defer) override;
bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) override;
@@ -77,7 +82,7 @@ class CONTENT_EXPORT MimeTypeResourceHandler
bool SelectPluginHandler(bool* defer, bool* handled_by_plugin);
// Returns false if the request should be cancelled.
bool SelectNextHandler(bool* defer);
- bool UseAlternateNextHandler(scoped_ptr<ResourceHandler> handler,
+ bool UseAlternateNextHandler(std::unique_ptr<ResourceHandler> handler,
const std::string& payload_for_old_handler);
bool ReplayReadCompleted(bool* defer);
diff --git a/chromium/content/browser/loader/mime_type_resource_handler_unittest.cc b/chromium/content/browser/loader/mime_type_resource_handler_unittest.cc
index 1b3ddcdbdf0..ca9de0b4a77 100644
--- a/chromium/content/browser/loader/mime_type_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/mime_type_resource_handler_unittest.cc
@@ -6,10 +6,11 @@
#include <stdint.h>
+#include <memory>
+
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
@@ -45,7 +46,6 @@ class TestResourceHandler : public ResourceHandler {
}
bool OnWillStart(const GURL& url, bool* defer) override {
- NOTREACHED();
return false;
}
@@ -88,17 +88,14 @@ class TestResourceDispatcherHost : public ResourceDispatcherHostImpl {
bool intercepted_as_stream() const { return intercepted_as_stream_; }
- scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
+ std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
- bool must_download,
- uint32_t id,
- scoped_ptr<DownloadSaveInfo> save_info,
- const DownloadUrlParameters::OnStartedCallback& started_cb) override {
- return scoped_ptr<ResourceHandler>(new TestResourceHandler);
+ bool must_download) override {
+ return std::unique_ptr<ResourceHandler>(new TestResourceHandler);
}
- scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
+ std::unique_ptr<ResourceHandler> MaybeInterceptAsStream(
const base::FilePath& plugin_path,
net::URLRequest* request,
ResourceResponse* response,
@@ -106,9 +103,9 @@ class TestResourceDispatcherHost : public ResourceDispatcherHostImpl {
intercepted_as_stream_count_++;
if (stream_has_handler_) {
intercepted_as_stream_ = true;
- return scoped_ptr<ResourceHandler>(new TestResourceHandler);
+ return std::unique_ptr<ResourceHandler>(new TestResourceHandler);
} else {
- return scoped_ptr<ResourceHandler>();
+ return std::unique_ptr<ResourceHandler>();
}
}
@@ -223,6 +220,11 @@ class MimeTypeResourceHandlerTest : public testing::Test {
bool must_download,
ResourceType request_resource_type);
+ std::string TestAcceptHeaderSetting(ResourceType request_resource_type);
+ std::string TestAcceptHeaderSettingWithURLRequest(
+ ResourceType request_resource_type,
+ net::URLRequest* request);
+
private:
// Whether the URL request should be intercepted as a stream.
bool stream_has_handler_;
@@ -237,7 +239,7 @@ bool MimeTypeResourceHandlerTest::TestStreamIsIntercepted(
bool must_download,
ResourceType request_resource_type) {
net::URLRequestContext context;
- scoped_ptr<net::URLRequest> request(context.CreateRequest(
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
ResourceRequestInfo::AllocateForTesting(
@@ -258,9 +260,10 @@ bool MimeTypeResourceHandlerTest::TestStreamIsIntercepted(
host.SetDelegate(&host_delegate);
TestFakePluginService plugin_service(plugin_available_, plugin_stale_);
- scoped_ptr<ResourceHandler> mime_sniffing_handler(new MimeTypeResourceHandler(
- scoped_ptr<ResourceHandler>(new TestResourceHandler()), &host,
- &plugin_service, request.get()));
+ std::unique_ptr<ResourceHandler> mime_sniffing_handler(
+ new MimeTypeResourceHandler(
+ std::unique_ptr<ResourceHandler>(new TestResourceHandler()), &host,
+ &plugin_service, request.get()));
TestResourceController resource_controller;
mime_sniffing_handler->SetController(&resource_controller);
@@ -276,6 +279,89 @@ bool MimeTypeResourceHandlerTest::TestStreamIsIntercepted(
return host.intercepted_as_stream();
}
+std::string MimeTypeResourceHandlerTest::TestAcceptHeaderSetting(
+ ResourceType request_resource_type) {
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ return TestAcceptHeaderSettingWithURLRequest(
+ request_resource_type, request.get());
+}
+
+std::string MimeTypeResourceHandlerTest::TestAcceptHeaderSettingWithURLRequest(
+ ResourceType request_resource_type,
+ net::URLRequest* request) {
+ bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
+ ResourceRequestInfo::AllocateForTesting(
+ request,
+ request_resource_type,
+ nullptr, // context
+ 0, // render_process_id
+ 0, // render_view_id
+ 0, // render_frame_id
+ is_main_frame, // is_main_frame
+ false, // parent_is_main_frame
+ false, // allow_download
+ true, // is_async
+ false); // is_using_lofi
+
+ TestResourceDispatcherHost host(stream_has_handler_);
+ TestResourceDispatcherHostDelegate host_delegate(false);
+ host.SetDelegate(&host_delegate);
+
+ std::unique_ptr<ResourceHandler> mime_sniffing_handler(
+ new MimeTypeResourceHandler(
+ std::unique_ptr<ResourceHandler>(new TestResourceHandler()), &host,
+ nullptr, request));
+
+ bool defer = false;
+ mime_sniffing_handler->OnWillStart(request->url(), &defer);
+ content::RunAllPendingInMessageLoop();
+
+ std::string accept_header;
+ request->extra_request_headers().GetHeader("Accept", &accept_header);
+ return accept_header;
+}
+
+// Test that the proper Accept: header is set based on the ResourceType
+TEST_F(MimeTypeResourceHandlerTest, AcceptHeaders) {
+ EXPECT_EQ(
+ "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
+ "*/*;q=0.8",
+ TestAcceptHeaderSetting(RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_EQ(
+ "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
+ "*/*;q=0.8",
+ TestAcceptHeaderSetting(RESOURCE_TYPE_SUB_FRAME));
+ EXPECT_EQ("text/css,*/*;q=0.1",
+ TestAcceptHeaderSetting(RESOURCE_TYPE_STYLESHEET));
+ EXPECT_EQ("*/*",
+ TestAcceptHeaderSetting(RESOURCE_TYPE_SCRIPT));
+ EXPECT_EQ("image/webp,image/*,*/*;q=0.8",
+ TestAcceptHeaderSetting(RESOURCE_TYPE_IMAGE));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_FONT_RESOURCE));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SUB_RESOURCE));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_OBJECT));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_MEDIA));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_WORKER));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SHARED_WORKER));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PREFETCH));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_FAVICON));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_XHR));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PING));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_SERVICE_WORKER));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_CSP_REPORT));
+ EXPECT_EQ("*/*", TestAcceptHeaderSetting(RESOURCE_TYPE_PLUGIN_RESOURCE));
+
+ // Ensure that if an Accept header is already set, it is not overwritten.
+ net::URLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr));
+ request->SetExtraRequestHeaderByName("Accept", "*", true);
+ EXPECT_EQ("*",
+ TestAcceptHeaderSettingWithURLRequest(RESOURCE_TYPE_XHR, request.get()));
+}
+
// Test that stream requests are correctly intercepted under the right
// circumstances. Test is not relevent when plugins are disabled.
#if defined(ENABLE_PLUGINS)
diff --git a/chromium/content/browser/loader/navigation_resource_handler.cc b/chromium/content/browser/loader/navigation_resource_handler.cc
index 94e046dbf0c..6e1694be6cd 100644
--- a/chromium/content/browser/loader/navigation_resource_handler.cc
+++ b/chromium/content/browser/loader/navigation_resource_handler.cc
@@ -44,6 +44,13 @@ void NavigationResourceHandler::FollowRedirect() {
controller()->Resume();
}
+void NavigationResourceHandler::ProceedWithResponse() {
+ // Detach from the loader; at this point, the request is now owned by the
+ // StreamHandle sent in OnResponseStarted.
+ DetachFromCore();
+ controller()->Resume();
+}
+
void NavigationResourceHandler::SetController(ResourceController* controller) {
writer_.set_controller(controller);
ResourceHandler::SetController(controller);
@@ -84,11 +91,9 @@ bool NavigationResourceHandler::OnResponseStarted(ResourceResponse* response,
writer_.InitializeStream(stream_context->registry(),
request()->url().GetOrigin());
- // Detach from the loader; at this point, the request is now owned by the
- // StreamHandle.
DevToolsNetLogObserver::PopulateResponseInfo(request(), response);
core_->NotifyResponseStarted(response, writer_.stream()->CreateHandle());
- DetachFromCore();
+ *defer = true;
return true;
}
diff --git a/chromium/content/browser/loader/navigation_resource_handler.h b/chromium/content/browser/loader/navigation_resource_handler.h
index e898663611c..b5ba53572ca 100644
--- a/chromium/content/browser/loader/navigation_resource_handler.h
+++ b/chromium/content/browser/loader/navigation_resource_handler.h
@@ -26,6 +26,9 @@ class NavigationResourceHandler : public ResourceHandler {
// Called to the loader to resume a paused redirect.
void FollowRedirect();
+ // Called to proceed with the response.
+ void ProceedWithResponse();
+
// ResourceHandler implementation.
void SetController(ResourceController* controller) override;
bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
diff --git a/chromium/content/browser/loader/navigation_resource_throttle.cc b/chromium/content/browser/loader/navigation_resource_throttle.cc
index 44fd0c131ff..63210620c9f 100644
--- a/chromium/content/browser/loader/navigation_resource_throttle.cc
+++ b/chromium/content/browser/loader/navigation_resource_throttle.cc
@@ -4,9 +4,13 @@
#include "content/browser/loader/navigation_resource_throttle.h"
+#include "base/bind.h"
#include "base/callback.h"
+#include "base/location.h"
+#include "base/logging.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_request_info.h"
@@ -26,7 +30,7 @@ typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)>
void SendCheckResultToIOThread(UIChecksPerformedCallback callback,
NavigationThrottle::ThrottleCheckResult result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- CHECK(result != NavigationThrottle::DEFER);
+ DCHECK_NE(result, NavigationThrottle::DEFER);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(callback, result));
}
@@ -93,21 +97,28 @@ void CheckWillRedirectRequestOnUIThread(
}
void WillProcessResponseOnUIThread(
+ UIChecksPerformedCallback callback,
int render_process_id,
int render_frame_host_id,
scoped_refptr<net::HttpResponseHeaders> headers) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(render_process_id, render_frame_host_id);
- if (!render_frame_host)
+ if (!render_frame_host) {
+ SendCheckResultToIOThread(callback, NavigationThrottle::PROCEED);
return;
+ }
NavigationHandleImpl* navigation_handle =
render_frame_host->navigation_handle();
- if (!navigation_handle)
+ if (!navigation_handle) {
+ SendCheckResultToIOThread(callback, NavigationThrottle::PROCEED);
return;
+ }
- navigation_handle->ReadyToCommitNavigation(render_frame_host, headers);
+ navigation_handle->WillProcessResponse(
+ render_frame_host, headers,
+ base::Bind(&SendCheckResultToIOThread, callback));
}
} // namespace
@@ -204,10 +215,15 @@ void NavigationResourceThrottle::WillProcessResponse(bool* defer) {
request_->response_headers()->raw_headers());
}
+ UIChecksPerformedCallback callback =
+ base::Bind(&NavigationResourceThrottle::OnUIChecksPerformed,
+ weak_ptr_factory_.GetWeakPtr());
+
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&WillProcessResponseOnUIThread, render_process_id,
+ base::Bind(&WillProcessResponseOnUIThread, callback, render_process_id,
render_frame_id, response_headers));
+ *defer = true;
}
const char* NavigationResourceThrottle::GetNameForLogging() const {
diff --git a/chromium/content/browser/loader/navigation_url_loader.cc b/chromium/content/browser/loader/navigation_url_loader.cc
index e2507650a81..d9b0c927543 100644
--- a/chromium/content/browser/loader/navigation_url_loader.cc
+++ b/chromium/content/browser/loader/navigation_url_loader.cc
@@ -14,16 +14,16 @@ namespace content {
static NavigationURLLoaderFactory* g_factory = nullptr;
-scoped_ptr<NavigationURLLoader> NavigationURLLoader::Create(
+std::unique_ptr<NavigationURLLoader> NavigationURLLoader::Create(
BrowserContext* browser_context,
- scoped_ptr<NavigationRequestInfo> request_info,
+ std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandle* service_worker_handle,
NavigationURLLoaderDelegate* delegate) {
if (g_factory) {
return g_factory->CreateLoader(browser_context, std::move(request_info),
service_worker_handle, delegate);
}
- return scoped_ptr<NavigationURLLoader>(
+ return std::unique_ptr<NavigationURLLoader>(
new NavigationURLLoaderImpl(browser_context, std::move(request_info),
service_worker_handle, delegate));
}
diff --git a/chromium/content/browser/loader/navigation_url_loader.h b/chromium/content/browser/loader/navigation_url_loader.h
index 0ba836a8d67..f7d3280f9b4 100644
--- a/chromium/content/browser/loader/navigation_url_loader.h
+++ b/chromium/content/browser/loader/navigation_url_loader.h
@@ -5,8 +5,9 @@
#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
namespace content {
@@ -32,9 +33,9 @@ class CONTENT_EXPORT NavigationURLLoader {
// request parameters should not come in as a navigation-specific
// structure. Information like has_user_gesture and
// should_replace_current_entry shouldn't be needed at this layer.
- static scoped_ptr<NavigationURLLoader> Create(
+ static std::unique_ptr<NavigationURLLoader> Create(
BrowserContext* browser_context,
- scoped_ptr<NavigationRequestInfo> request_info,
+ std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandle* service_worker_handle,
NavigationURLLoaderDelegate* delegate);
@@ -47,6 +48,9 @@ class CONTENT_EXPORT NavigationURLLoader {
// request.
virtual void FollowRedirect() = 0;
+ // Called in response to OnResponseStarted to process the response.
+ virtual void ProceedWithResponse() = 0;
+
protected:
NavigationURLLoader() {}
diff --git a/chromium/content/browser/loader/navigation_url_loader_delegate.h b/chromium/content/browser/loader/navigation_url_loader_delegate.h
index 62351aebf5f..201fa86297e 100644
--- a/chromium/content/browser/loader/navigation_url_loader_delegate.h
+++ b/chromium/content/browser/loader/navigation_url_loader_delegate.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_DELEGATE_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_DELEGATE_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
namespace net {
@@ -33,7 +34,7 @@ class CONTENT_EXPORT NavigationURLLoaderDelegate {
// |body_stream|.
virtual void OnResponseStarted(
const scoped_refptr<ResourceResponse>& response,
- scoped_ptr<StreamHandle> body_stream) = 0;
+ std::unique_ptr<StreamHandle> body_stream) = 0;
// Called if the request fails before receving a response. |net_error| is a
// network error code for the failure. |has_stale_copy_in_cache| is true if
diff --git a/chromium/content/browser/loader/navigation_url_loader_factory.h b/chromium/content/browser/loader/navigation_url_loader_factory.h
index a2fd37136a7..df7ae0c0cb2 100644
--- a/chromium/content/browser/loader/navigation_url_loader_factory.h
+++ b/chromium/content/browser/loader/navigation_url_loader_factory.h
@@ -5,8 +5,9 @@
#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_FACTORY_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_FACTORY_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/navigation_url_loader.h"
namespace content {
@@ -15,9 +16,9 @@ namespace content {
// the loader. This is intended for testing.
class NavigationURLLoaderFactory {
public:
- virtual scoped_ptr<NavigationURLLoader> CreateLoader(
+ virtual std::unique_ptr<NavigationURLLoader> CreateLoader(
BrowserContext* browser_context,
- scoped_ptr<NavigationRequestInfo> request_info,
+ std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandle* service_worker_handle,
NavigationURLLoaderDelegate* delegate) = 0;
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.cc b/chromium/content/browser/loader/navigation_url_loader_impl.cc
index 1f95ce3165f..8b4c670242e 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.cc
@@ -21,7 +21,7 @@ namespace content {
NavigationURLLoaderImpl::NavigationURLLoaderImpl(
BrowserContext* browser_context,
- scoped_ptr<NavigationRequestInfo> request_info,
+ std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandle* service_worker_handle,
NavigationURLLoaderDelegate* delegate)
: delegate_(delegate), weak_factory_(this) {
@@ -62,6 +62,15 @@ void NavigationURLLoaderImpl::FollowRedirect() {
base::Unretained(core_)));
}
+void NavigationURLLoaderImpl::ProceedWithResponse() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImplCore::ProceedWithResponse,
+ base::Unretained(core_)));
+}
+
void NavigationURLLoaderImpl::NotifyRequestRedirected(
const net::RedirectInfo& redirect_info,
const scoped_refptr<ResourceResponse>& response) {
@@ -72,7 +81,7 @@ void NavigationURLLoaderImpl::NotifyRequestRedirected(
void NavigationURLLoaderImpl::NotifyResponseStarted(
const scoped_refptr<ResourceResponse>& response,
- scoped_ptr<StreamHandle> body) {
+ std::unique_ptr<StreamHandle> body) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_->OnResponseStarted(response, std::move(body));
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.h b/chromium/content/browser/loader/navigation_url_loader_impl.h
index 5c7fcd0d2b0..51131cc12d0 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/loader/navigation_url_loader.h"
@@ -27,14 +28,14 @@ class NavigationURLLoaderImpl : public NavigationURLLoader {
public:
// The caller is responsible for ensuring that |delegate| outlives the loader.
NavigationURLLoaderImpl(BrowserContext* browser_context,
- scoped_ptr<NavigationRequestInfo> request_info,
+ std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandle* service_worker_handle,
NavigationURLLoaderDelegate* delegate);
~NavigationURLLoaderImpl() override;
- // Called in response to OnRequestRedirected to continue processing the
- // request.
+ // NavigationURLLoader implementation.
void FollowRedirect() override;
+ void ProceedWithResponse() override;
private:
friend class NavigationURLLoaderImplCore;
@@ -45,7 +46,7 @@ class NavigationURLLoaderImpl : public NavigationURLLoader {
// Notifies the delegate that the response has started.
void NotifyResponseStarted(const scoped_refptr<ResourceResponse>& response,
- scoped_ptr<StreamHandle> body);
+ std::unique_ptr<StreamHandle> body);
// Notifies the delegate the request failed to return a response.
void NotifyRequestFailed(bool in_cache, int net_error);
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.cc b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
index bd7ef98f8ea..84001faae57 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -39,7 +39,7 @@ NavigationURLLoaderImplCore::~NavigationURLLoaderImplCore() {
void NavigationURLLoaderImplCore::Start(
ResourceContext* resource_context,
ServiceWorkerNavigationHandleCore* service_worker_handle_core,
- scoped_ptr<NavigationRequestInfo> request_info) {
+ std::unique_ptr<NavigationRequestInfo> request_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
@@ -61,6 +61,13 @@ void NavigationURLLoaderImplCore::FollowRedirect() {
resource_handler_->FollowRedirect();
}
+void NavigationURLLoaderImplCore::ProceedWithResponse() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (resource_handler_)
+ resource_handler_->ProceedWithResponse();
+}
+
void NavigationURLLoaderImplCore::NotifyRequestRedirected(
const net::RedirectInfo& redirect_info,
ResourceResponse* response) {
@@ -87,7 +94,7 @@ void NavigationURLLoaderImplCore::NotifyRequestRedirected(
void NavigationURLLoaderImplCore::NotifyResponseStarted(
ResourceResponse* response,
- scoped_ptr<StreamHandle> body) {
+ std::unique_ptr<StreamHandle> body) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
TRACE_EVENT_ASYNC_END0("navigation", "Navigation redirectDelay", this);
TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.h b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
index b12629d92f2..67a2925dc19 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_core.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
@@ -5,8 +5,9 @@
#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_CORE_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_CORE_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
@@ -41,11 +42,14 @@ class NavigationURLLoaderImplCore {
// Starts the request.
void Start(ResourceContext* resource_context,
ServiceWorkerNavigationHandleCore* service_worker_handle_core,
- scoped_ptr<NavigationRequestInfo> request_info);
+ std::unique_ptr<NavigationRequestInfo> request_info);
// Follows the current pending redirect.
void FollowRedirect();
+ // Proceeds with processing the response.
+ void ProceedWithResponse();
+
void set_resource_handler(NavigationResourceHandler* resource_handler) {
resource_handler_ = resource_handler;
}
@@ -56,7 +60,7 @@ class NavigationURLLoaderImplCore {
// Notifies |loader_| on the UI thread that the response started.
void NotifyResponseStarted(ResourceResponse* response,
- scoped_ptr<StreamHandle> body);
+ std::unique_ptr<StreamHandle> body);
// Notifies |loader_| on the UI thread that the request failed.
void NotifyRequestFailed(bool in_cache, int net_error);
diff --git a/chromium/content/browser/loader/navigation_url_loader_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
index efee272495d..8b7c5cccd06 100644
--- a/chromium/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/browser/frame_host/navigation_request_info.h"
#include "content/browser/loader/navigation_url_loader_delegate.h"
@@ -110,7 +111,7 @@ class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
}
void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
- scoped_ptr<StreamHandle> body) override {
+ std::unique_ptr<StreamHandle> body) override {
response_ = response;
body_ = std::move(body);
ASSERT_TRUE(response_started_);
@@ -132,13 +133,13 @@ class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
net::RedirectInfo redirect_info_;
scoped_refptr<ResourceResponse> redirect_response_;
scoped_refptr<ResourceResponse> response_;
- scoped_ptr<StreamHandle> body_;
+ std::unique_ptr<StreamHandle> body_;
int net_error_;
int on_request_handled_counter_;
- scoped_ptr<base::RunLoop> request_redirected_;
- scoped_ptr<base::RunLoop> response_started_;
- scoped_ptr<base::RunLoop> request_failed_;
+ std::unique_ptr<base::RunLoop> request_redirected_;
+ std::unique_ptr<base::RunLoop> response_started_;
+ std::unique_ptr<base::RunLoop> request_failed_;
};
class RequestBlockingResourceDispatcherHostDelegate
@@ -169,7 +170,7 @@ class NavigationURLLoaderTest : public testing::Test {
"test", net::URLRequestTestJob::CreateProtocolHandler());
job_factory_.SetProtocolHandler(
"blob",
- make_scoped_ptr(new StreamProtocolHandler(
+ base::WrapUnique(new StreamProtocolHandler(
StreamContext::GetFor(browser_context_.get())->registry())));
request_context->set_job_factory(&job_factory_);
@@ -178,17 +179,17 @@ class NavigationURLLoaderTest : public testing::Test {
switches::kEnableBrowserSideNavigation);
}
- scoped_ptr<NavigationURLLoader> MakeTestLoader(
+ std::unique_ptr<NavigationURLLoader> MakeTestLoader(
const GURL& url,
NavigationURLLoaderDelegate* delegate) {
- BeginNavigationParams begin_params("GET", std::string(), net::LOAD_NORMAL,
- false, false,
- REQUEST_CONTEXT_TYPE_LOCATION);
+ BeginNavigationParams begin_params(std::string(), net::LOAD_NORMAL, false,
+ false, REQUEST_CONTEXT_TYPE_LOCATION);
CommonNavigationParams common_params;
common_params.url = url;
- scoped_ptr<NavigationRequestInfo> request_info(new NavigationRequestInfo(
- common_params, begin_params, url, url::Origin(url), true, false, -1,
- scoped_refptr<ResourceRequestBody>()));
+ std::unique_ptr<NavigationRequestInfo> request_info(
+ new NavigationRequestInfo(common_params, begin_params, url,
+ url::Origin(url), true, false, -1,
+ scoped_refptr<ResourceRequestBody>()));
return NavigationURLLoader::Create(
browser_context_.get(), std::move(request_info), nullptr, delegate);
@@ -199,8 +200,8 @@ class NavigationURLLoaderTest : public testing::Test {
net::TestDelegate delegate;
net::URLRequestContext* request_context =
browser_context_->GetResourceContext()->GetRequestContext();
- scoped_ptr<net::URLRequest> request(request_context->CreateRequest(
- url, net::DEFAULT_PRIORITY, &delegate));
+ std::unique_ptr<net::URLRequest> request(
+ request_context->CreateRequest(url, net::DEFAULT_PRIORITY, &delegate));
request->Start();
base::RunLoop().Run();
@@ -212,19 +213,22 @@ class NavigationURLLoaderTest : public testing::Test {
protected:
TestBrowserThreadBundle thread_bundle_;
net::URLRequestJobFactoryImpl job_factory_;
- scoped_ptr<TestBrowserContext> browser_context_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
ResourceDispatcherHostImpl host_;
};
// Tests that a basic request works.
TEST_F(NavigationURLLoaderTest, Basic) {
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
+ std::unique_ptr<NavigationURLLoader> loader =
MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
// Wait for the response to come back.
delegate.WaitForResponseStarted();
+ // Proceed with the response.
+ loader->ProceedWithResponse();
+
// Check the response is correct.
EXPECT_EQ("text/html", delegate.response()->head.mime_type);
EXPECT_EQ(200, delegate.response()->head.headers->response_code());
@@ -239,7 +243,7 @@ TEST_F(NavigationURLLoaderTest, Basic) {
// Tests that request failures are propagated correctly.
TEST_F(NavigationURLLoaderTest, RequestFailed) {
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
+ std::unique_ptr<NavigationURLLoader> loader =
MakeTestLoader(GURL("bogus:bogus"), &delegate);
// Wait for the request to fail as expected.
@@ -253,9 +257,8 @@ TEST_F(NavigationURLLoaderTest, RequestRedirected) {
// Fake a top-level request. Choose a URL which redirects so the request can
// be paused before the response comes in.
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
- MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
- &delegate);
+ std::unique_ptr<NavigationURLLoader> loader = MakeTestLoader(
+ net::URLRequestTestJob::test_url_redirect_to_url_2(), &delegate);
// Wait for the request to redirect.
delegate.WaitForRequestRedirected();
@@ -271,6 +274,9 @@ TEST_F(NavigationURLLoaderTest, RequestRedirected) {
loader->FollowRedirect();
delegate.WaitForResponseStarted();
+ // Proceed with the response.
+ loader->ProceedWithResponse();
+
// Check the response is correct.
EXPECT_EQ("text/html", delegate.response()->head.mime_type);
EXPECT_EQ(200, delegate.response()->head.headers->response_code());
@@ -288,9 +294,8 @@ TEST_F(NavigationURLLoaderTest, CancelOnDestruct) {
// Fake a top-level request. Choose a URL which redirects so the request can
// be paused before the response comes in.
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
- MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
- &delegate);
+ std::unique_ptr<NavigationURLLoader> loader = MakeTestLoader(
+ net::URLRequestTestJob::test_url_redirect_to_url_2(), &delegate);
// Wait for the request to redirect.
delegate.WaitForRequestRedirected();
@@ -306,9 +311,8 @@ TEST_F(NavigationURLLoaderTest, CancelOnDestruct) {
// loader race.
TEST_F(NavigationURLLoaderTest, CancelResponseRace) {
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
- MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
- &delegate);
+ std::unique_ptr<NavigationURLLoader> loader = MakeTestLoader(
+ net::URLRequestTestJob::test_url_redirect_to_url_2(), &delegate);
// Wait for the request to redirect.
delegate.WaitForRequestRedirected();
@@ -328,9 +332,8 @@ TEST_F(NavigationURLLoaderTest, CancelResponseRace) {
// Tests that the loader may be canceled by context.
TEST_F(NavigationURLLoaderTest, CancelByContext) {
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
- MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
- &delegate);
+ std::unique_ptr<NavigationURLLoader> loader = MakeTestLoader(
+ net::URLRequestTestJob::test_url_redirect_to_url_2(), &delegate);
// Wait for the request to redirect.
delegate.WaitForRequestRedirected();
@@ -351,7 +354,7 @@ TEST_F(NavigationURLLoaderTest, RequestBlocked) {
host_.SetDelegate(&rdh_delegate);
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
+ std::unique_ptr<NavigationURLLoader> loader =
MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
// Wait for the request to fail as expected.
@@ -366,12 +369,15 @@ TEST_F(NavigationURLLoaderTest, RequestBlocked) {
TEST_F(NavigationURLLoaderTest, LoaderDetached) {
// Fake a top-level request to a URL whose body does not load immediately.
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
+ std::unique_ptr<NavigationURLLoader> loader =
MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
// Wait for the response to come back.
delegate.WaitForResponseStarted();
+ // Proceed with the response.
+ loader->ProceedWithResponse();
+
// Check the response is correct.
EXPECT_EQ("text/html", delegate.response()->head.mime_type);
EXPECT_EQ(200, delegate.response()->head.headers->response_code());
@@ -390,12 +396,15 @@ TEST_F(NavigationURLLoaderTest, LoaderDetached) {
TEST_F(NavigationURLLoaderTest, OwnedByHandle) {
// Fake a top-level request to a URL whose body does not load immediately.
TestNavigationURLLoaderDelegate delegate;
- scoped_ptr<NavigationURLLoader> loader =
+ std::unique_ptr<NavigationURLLoader> loader =
MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
// Wait for the response to come back.
delegate.WaitForResponseStarted();
+ // Proceed with the response.
+ loader->ProceedWithResponse();
+
// Release the body.
delegate.ReleaseBody();
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/loader/power_save_block_resource_throttle.h b/chromium/content/browser/loader/power_save_block_resource_throttle.h
index 4c678421a05..3f6f1d363d7 100644
--- a/chromium/content/browser/loader/power_save_block_resource_throttle.h
+++ b/chromium/content/browser/loader/power_save_block_resource_throttle.h
@@ -5,11 +5,11 @@
#ifndef CONTENT_BROWSER_LOADER_POWER_SAVE_BLOCK_RESOURCE_THROTTLE_H_
#define CONTENT_BROWSER_LOADER_POWER_SAVE_BLOCK_RESOURCE_THROTTLE_H_
+#include <memory>
#include <string>
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/timer/timer.h"
#include "content/public/browser/resource_throttle.h"
@@ -33,7 +33,7 @@ class PowerSaveBlockResourceThrottle : public ResourceThrottle {
const std::string host_;
base::OneShotTimer timer_;
- scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockResourceThrottle);
};
diff --git a/chromium/content/browser/loader/redirect_to_file_resource_handler.cc b/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
index 670b3343d30..df246069b59 100644
--- a/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
+++ b/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
@@ -61,7 +61,7 @@ static const int kMaxReadBufSize = 524288;
class RedirectToFileResourceHandler::Writer {
public:
Writer(RedirectToFileResourceHandler* handler,
- scoped_ptr<net::FileStream> file_stream,
+ std::unique_ptr<net::FileStream> file_stream,
ShareableFileReference* deletable_file)
: handler_(handler),
file_stream_(std::move(file_stream)),
@@ -119,7 +119,7 @@ class RedirectToFileResourceHandler::Writer {
RedirectToFileResourceHandler* handler_;
- scoped_ptr<net::FileStream> file_stream_;
+ std::unique_ptr<net::FileStream> file_stream_;
bool is_writing_;
// We create a ShareableFileReference that's deletable for the temp file
@@ -130,7 +130,7 @@ class RedirectToFileResourceHandler::Writer {
};
RedirectToFileResourceHandler::RedirectToFileResourceHandler(
- scoped_ptr<ResourceHandler> next_handler,
+ std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request)
: LayeredResourceHandler(request, std::move(next_handler)),
buf_(new net::GrowableIOBuffer()),
@@ -243,7 +243,7 @@ void RedirectToFileResourceHandler::OnResponseCompleted(
void RedirectToFileResourceHandler::DidCreateTemporaryFile(
base::File::Error error_code,
- scoped_ptr<net::FileStream> file_stream,
+ std::unique_ptr<net::FileStream> file_stream,
ShareableFileReference* deletable_file) {
DCHECK(!writer_);
if (error_code != base::File::FILE_OK) {
diff --git a/chromium/content/browser/loader/redirect_to_file_resource_handler.h b/chromium/content/browser/loader/redirect_to_file_resource_handler.h
index cd4d60dc058..6f9db88b03a 100644
--- a/chromium/content/browser/loader/redirect_to_file_resource_handler.h
+++ b/chromium/content/browser/loader/redirect_to_file_resource_handler.h
@@ -5,13 +5,14 @@
#ifndef CONTENT_BROWSER_LOADER_REDIRECT_TO_FILE_RESOURCE_HANDLER_H_
#define CONTENT_BROWSER_LOADER_REDIRECT_TO_FILE_RESOURCE_HANDLER_H_
+#include <memory>
+
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/layered_resource_handler.h"
#include "content/browser/loader/temporary_file_stream.h"
@@ -44,7 +45,7 @@ class CONTENT_EXPORT RedirectToFileResourceHandler
// Create a RedirectToFileResourceHandler for |request| which wraps
// |next_handler|.
- RedirectToFileResourceHandler(scoped_ptr<ResourceHandler> next_handler,
+ RedirectToFileResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request);
~RedirectToFileResourceHandler() override;
@@ -68,7 +69,7 @@ class CONTENT_EXPORT RedirectToFileResourceHandler
private:
void DidCreateTemporaryFile(base::File::Error error_code,
- scoped_ptr<net::FileStream> file_stream,
+ std::unique_ptr<net::FileStream> file_stream,
storage::ShareableFileReference* deletable_file);
// Called by RedirectToFileResourceHandler::Writer.
diff --git a/chromium/content/browser/loader/resource_buffer.cc b/chromium/content/browser/loader/resource_buffer.cc
index 9dc63d63a6c..3f5a5c89b97 100644
--- a/chromium/content/browser/loader/resource_buffer.cc
+++ b/chromium/content/browser/loader/resource_buffer.cc
@@ -61,17 +61,9 @@ bool ResourceBuffer::IsInitialized() const {
return shared_mem_.memory() != NULL;
}
-bool ResourceBuffer::ShareToProcess(
- base::ProcessHandle process_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- int* shared_memory_size) {
+base::SharedMemory& ResourceBuffer::GetSharedMemory() {
CHECK(IsInitialized());
-
- if (!shared_mem_.ShareToProcess(process_handle, shared_memory_handle))
- return false;
-
- *shared_memory_size = buf_size_;
- return true;
+ return shared_mem_;
}
bool ResourceBuffer::CanAllocate() const {
diff --git a/chromium/content/browser/loader/resource_buffer.h b/chromium/content/browser/loader/resource_buffer.h
index e323bf19a41..e071d19ba45 100644
--- a/chromium/content/browser/loader/resource_buffer.h
+++ b/chromium/content/browser/loader/resource_buffer.h
@@ -71,13 +71,8 @@ class CONTENT_EXPORT ResourceBuffer
int max_allocation_size);
bool IsInitialized() const;
- // Returns a shared memory handle that can be passed to the given process.
- // The shared memory handle is only intended to be interpretted by code
- // running in the specified process. NOTE: The caller should ensure that
- // this memory eventually be returned to the operating system.
- bool ShareToProcess(base::ProcessHandle process_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- int* shared_memory_size);
+ // Returns a reference to the underlying shared memory.
+ base::SharedMemory& GetSharedMemory();
// Returns true if Allocate will succeed.
bool CanAllocate() const;
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
index bad9b869c9f..3a3a13d5550 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -280,14 +280,14 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
namespace {
// Handles |request| by serving a redirect response.
-scoped_ptr<net::test_server::HttpResponse> NoContentResponseHandler(
+std::unique_ptr<net::test_server::HttpResponse> NoContentResponseHandler(
const std::string& path,
const net::test_server::HttpRequest& request) {
if (!base::StartsWith(path, request.relative_url,
base::CompareCase::SENSITIVE))
- return scoped_ptr<net::test_server::HttpResponse>();
+ return std::unique_ptr<net::test_server::HttpResponse>();
- scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_NO_CONTENT);
return std::move(http_response);
@@ -465,14 +465,14 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
namespace {
-scoped_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
+std::unique_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
const std::string& request_path,
const net::test_server::HttpRequest& request) {
if (!base::StartsWith(request.relative_url, request_path,
base::CompareCase::SENSITIVE))
- return scoped_ptr<net::test_server::HttpResponse>();
+ return std::unique_ptr<net::test_server::HttpResponse>();
- scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_FOUND);
http_response->AddCustomHeader(
@@ -678,7 +678,7 @@ class LoFiResourceDispatcherHostBrowserTest : public ContentBrowserTest {
}
private:
- scoped_ptr<LoFiModeResourceDispatcherHostDelegate> delegate_;
+ std::unique_ptr<LoFiModeResourceDispatcherHostDelegate> delegate_;
};
// Test that navigating with ShouldEnableLoFiMode returning true fetches the
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
index 529b9781866..21f43ed3e5f 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -7,7 +7,9 @@
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include <stddef.h>
+
#include <algorithm>
+#include <memory>
#include <set>
#include <utility>
#include <vector>
@@ -17,9 +19,10 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
@@ -39,6 +42,7 @@
#include "content/browser/download/save_file_manager.h"
#include "content/browser/download/save_file_resource_handler.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/navigation_request_info.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/loader/async_resource_handler.h"
@@ -61,6 +65,7 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/resource_context_impl.h"
#include "content/browser/service_worker/foreign_fetch_request_handler.h"
+#include "content/browser/service_worker/link_header_support.h"
#include "content/browser/service_worker/service_worker_request_handler.h"
#include "content/browser/streams/stream.h"
#include "content/browser/streams/stream_context.h"
@@ -68,6 +73,7 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/appcache_interfaces.h"
#include "content/common/navigation_params.h"
+#include "content/common/net/url_request_service_worker_data.h"
#include "content/common/resource_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/ssl_status_serialization.h"
@@ -85,6 +91,7 @@
#include "content/public/browser/stream_info.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
#include "ipc/ipc_message_macros.h"
@@ -288,9 +295,6 @@ bool ShouldServiceRequest(int process_type,
const net::HttpRequestHeaders& headers,
ResourceMessageFilter* filter,
ResourceContext* resource_context) {
- if (process_type == PROCESS_TYPE_PLUGIN)
- return true;
-
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
@@ -349,31 +353,15 @@ void RemoveDownloadFileFromChildSecurityPolicy(int child_id,
child_id, path);
}
-DownloadInterruptReason CallbackAndReturn(
- const DownloadUrlParameters::OnStartedCallback& started_cb,
- DownloadInterruptReason interrupt_reason) {
- if (started_cb.is_null())
- return interrupt_reason;
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- started_cb, static_cast<DownloadItem*>(NULL), interrupt_reason));
-
- return interrupt_reason;
-}
-
-int GetCertID(net::URLRequest* request, int child_id) {
- if (request->ssl_info().cert.get()) {
- return CertStore::GetInstance()->StoreCert(request->ssl_info().cert.get(),
- child_id);
- }
+int GetCertID(CertStore* cert_store, net::URLRequest* request, int child_id) {
+ if (request->ssl_info().cert.get())
+ return cert_store->StoreCert(request->ssl_info().cert.get(), child_id);
return 0;
}
void NotifyRedirectOnUI(int render_process_id,
int render_frame_host,
- scoped_ptr<ResourceRedirectDetails> details) {
+ std::unique_ptr<ResourceRedirectDetails> details) {
RenderFrameHostImpl* host =
RenderFrameHostImpl::FromID(render_process_id, render_frame_host);
WebContentsImpl* web_contents =
@@ -385,7 +373,7 @@ void NotifyRedirectOnUI(int render_process_id,
void NotifyResponseOnUI(int render_process_id,
int render_frame_host,
- scoped_ptr<ResourceRequestDetails> details) {
+ std::unique_ptr<ResourceRequestDetails> details) {
RenderFrameHostImpl* host =
RenderFrameHostImpl::FromID(render_process_id, render_frame_host);
WebContentsImpl* web_contents =
@@ -415,7 +403,7 @@ void AttachRequestBodyBlobDataHandles(
const ResourceRequestBody::Element& element = (*body->elements())[i];
if (element.type() != ResourceRequestBody::Element::TYPE_BLOB)
continue;
- scoped_ptr<storage::BlobDataHandle> handle =
+ std::unique_ptr<storage::BlobDataHandle> handle =
blob_context->GetBlobDataFromUUID(element.blob_uuid());
DCHECK(handle);
if (!handle)
@@ -448,8 +436,9 @@ void LogResourceRequestTimeOnUI(
bool IsUsingLoFi(LoFiState lofi_state,
ResourceDispatcherHostDelegate* delegate,
const net::URLRequest& request,
- ResourceContext* resource_context) {
- if (lofi_state == LOFI_UNSPECIFIED && delegate)
+ ResourceContext* resource_context,
+ bool is_main_frame) {
+ if (lofi_state == LOFI_UNSPECIFIED && delegate && is_main_frame)
return delegate->ShouldEnableLoFiMode(request, resource_context);
return lofi_state == LOFI_ON;
}
@@ -465,8 +454,80 @@ void RecordAbortRapporOnUI(const GURL& url,
GetContentClient()->browser()->RecordURLMetric("Net.ErrAborted.Slow", url);
}
+// The following functions simplify code paths where the UI thread notifies the
+// ResourceDispatcherHostImpl of information pertaining to loading behavior of
+// frame hosts.
+void NotifyForRouteOnIO(
+ base::Callback<void(ResourceDispatcherHostImpl*,
+ const GlobalFrameRoutingId&)> frame_callback,
+ const GlobalFrameRoutingId& global_routing_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ if (rdh)
+ frame_callback.Run(rdh, global_routing_id);
+}
+
+void NotifyForRouteFromUI(
+ const GlobalFrameRoutingId& global_routing_id,
+ base::Callback<void(ResourceDispatcherHostImpl*,
+ const GlobalFrameRoutingId&)> frame_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&NotifyForRouteOnIO, frame_callback, global_routing_id));
+}
+
+void NotifyForRouteSetOnIO(
+ base::Callback<void(ResourceDispatcherHostImpl*,
+ const GlobalFrameRoutingId&)> frame_callback,
+ std::unique_ptr<std::set<GlobalFrameRoutingId>> routing_ids) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (const auto& routing_id : *routing_ids)
+ NotifyForRouteOnIO(frame_callback, routing_id);
+}
+
+void NotifyForEachFrameFromUI(
+ RenderFrameHost* root_frame_host,
+ base::Callback<void(ResourceDispatcherHostImpl*,
+ const GlobalFrameRoutingId&)> frame_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ FrameTree* frame_tree = static_cast<RenderFrameHostImpl*>(root_frame_host)
+ ->frame_tree_node()
+ ->frame_tree();
+ DCHECK_EQ(root_frame_host, frame_tree->GetMainFrame());
+ std::unique_ptr<std::set<GlobalFrameRoutingId>> routing_ids(
+ new std::set<GlobalFrameRoutingId>());
+ for (FrameTreeNode* node : frame_tree->Nodes()) {
+ RenderFrameHostImpl* frame_host = node->current_frame_host();
+ RenderFrameHostImpl* pending_frame_host =
+ IsBrowserSideNavigationEnabled()
+ ? node->render_manager()->speculative_frame_host()
+ : node->render_manager()->pending_frame_host();
+ if (frame_host)
+ routing_ids->insert(frame_host->GetGlobalFrameRoutingId());
+ if (pending_frame_host)
+ routing_ids->insert(pending_frame_host->GetGlobalFrameRoutingId());
+ }
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&NotifyForRouteSetOnIO, frame_callback,
+ base::Passed(std::move(routing_ids))));
+}
+
} // namespace
+LoaderIOThreadNotifier::LoaderIOThreadNotifier(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+LoaderIOThreadNotifier::~LoaderIOThreadNotifier() {}
+
+void LoaderIOThreadNotifier::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ NotifyForRouteFromUI(
+ static_cast<RenderFrameHostImpl*>(render_frame_host)
+ ->GetGlobalFrameRoutingId(),
+ base::Bind(&ResourceDispatcherHostImpl::OnRenderFrameDeleted));
+}
+
// static
ResourceDispatcherHost* ResourceDispatcherHost::Get() {
return g_resource_dispatcher_host;
@@ -478,14 +539,14 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
is_shutdown_(false),
num_in_flight_requests_(0),
max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()),
- max_num_in_flight_requests_per_process_(
- static_cast<int>(
- max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)),
+ max_num_in_flight_requests_per_process_(static_cast<int>(
+ max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)),
max_outstanding_requests_cost_per_process_(
kMaxOutstandingRequestsCostPerProcess),
filter_(NULL),
delegate_(NULL),
- allow_cross_origin_auth_prompt_(false) {
+ allow_cross_origin_auth_prompt_(false),
+ cert_store_for_testing_(nullptr) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!g_resource_dispatcher_host);
g_resource_dispatcher_host = this;
@@ -503,11 +564,6 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
update_load_states_timer_.reset(new base::RepeatingTimer());
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- // This needs to be called to mark the trial as active, even if the result
- // isn't used.
- std::string stale_while_revalidate_trial_group =
- base::FieldTrialList::FindFullName("StaleWhileRevalidate");
// stale-while-revalidate currently doesn't work with browser-side navigation.
// Only enable stale-while-revalidate if browser navigation is not enabled.
//
@@ -515,9 +571,7 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
// together. Or disable stale-while-revalidate completely before browser-side
// navigation becomes the default. crbug.com/561610
if (!IsBrowserSideNavigationEnabled() &&
- (base::StartsWith(stale_while_revalidate_trial_group, "Enabled",
- base::CompareCase::SENSITIVE) ||
- command_line->HasSwitch(switches::kEnableStaleWhileRevalidate))) {
+ base::FeatureList::IsEnabled(features::kStaleWhileRevalidate)) {
async_revalidation_manager_.reset(new AsyncRevalidationManager);
}
}
@@ -533,6 +587,42 @@ ResourceDispatcherHostImpl* ResourceDispatcherHostImpl::Get() {
return g_resource_dispatcher_host;
}
+// static
+void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRouteFromUI(
+ const GlobalFrameRoutingId& global_routing_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NotifyForRouteFromUI(
+ global_routing_id,
+ base::Bind(&ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute));
+}
+
+// static
+void ResourceDispatcherHostImpl::BlockRequestsForFrameFromUI(
+ RenderFrameHost* root_frame_host) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NotifyForEachFrameFromUI(
+ root_frame_host,
+ base::Bind(&ResourceDispatcherHostImpl::BlockRequestsForRoute));
+}
+
+// static
+void ResourceDispatcherHostImpl::ResumeBlockedRequestsForFrameFromUI(
+ RenderFrameHost* root_frame_host) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NotifyForEachFrameFromUI(
+ root_frame_host,
+ base::Bind(&ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute));
+}
+
+// static
+void ResourceDispatcherHostImpl::CancelBlockedRequestsForFrameFromUI(
+ RenderFrameHostImpl* root_frame_host) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NotifyForEachFrameFromUI(
+ root_frame_host,
+ base::Bind(&ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute));
+}
+
void ResourceDispatcherHostImpl::SetDelegate(
ResourceDispatcherHostDelegate* delegate) {
delegate_ = delegate;
@@ -543,6 +633,7 @@ void ResourceDispatcherHostImpl::SetAllowCrossOriginAuthPrompt(bool value) {
}
void ResourceDispatcherHostImpl::AddResourceContext(ResourceContext* context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
active_resource_contexts_.insert(context);
}
@@ -563,14 +654,15 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
// the requests to cancel first, and then we start cancelling. We assert at
// the end that there are no more to cancel since the context is about to go
// away.
- typedef std::vector<linked_ptr<ResourceLoader>> LoaderList;
+ typedef std::vector<std::unique_ptr<ResourceLoader>> LoaderList;
LoaderList loaders_to_cancel;
for (LoaderMap::iterator i = pending_loaders_.begin();
i != pending_loaders_.end();) {
- if (i->second->GetRequestInfo()->GetContext() == context) {
- loaders_to_cancel.push_back(i->second);
- IncrementOutstandingRequestsMemory(-1, *i->second->GetRequestInfo());
+ ResourceLoader* loader = i->second.get();
+ if (loader->GetRequestInfo()->GetContext() == context) {
+ loaders_to_cancel.push_back(std::move(i->second));
+ IncrementOutstandingRequestsMemory(-1, *loader->GetRequestInfo());
pending_loaders_.erase(i++);
} else {
++i;
@@ -579,7 +671,7 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
for (BlockedLoadersMap::iterator i = blocked_loaders_map_.begin();
i != blocked_loaders_map_.end();) {
- BlockedLoadersList* loaders = i->second;
+ BlockedLoadersList* loaders = i->second.get();
if (loaders->empty()) {
// This can happen if BlockRequestsForRoute() has been called for a route,
// but we haven't blocked any matching requests yet.
@@ -588,38 +680,35 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
}
ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
if (info->GetContext() == context) {
+ std::unique_ptr<BlockedLoadersList> deleter(std::move(i->second));
blocked_loaders_map_.erase(i++);
- for (BlockedLoadersList::const_iterator it = loaders->begin();
- it != loaders->end(); ++it) {
- linked_ptr<ResourceLoader> loader = *it;
+ for (auto& loader : *loaders) {
info = loader->GetRequestInfo();
// We make the assumption that all requests on the list have the same
// ResourceContext.
DCHECK_EQ(context, info->GetContext());
IncrementOutstandingRequestsMemory(-1, *info);
- loaders_to_cancel.push_back(loader);
+ loaders_to_cancel.push_back(std::move(loader));
}
- delete loaders;
} else {
++i;
}
}
#ifndef NDEBUG
- for (LoaderList::iterator i = loaders_to_cancel.begin();
- i != loaders_to_cancel.end(); ++i) {
+ for (const auto& loader : loaders_to_cancel) {
// There is no strict requirement that this be the case, but currently
// downloads, streams, detachable requests, transferred requests, and
// browser-owned requests are the only requests that aren't cancelled when
// the associated processes go away. It may be OK for this invariant to
// change in the future, but if this assertion fires without the invariant
// changing, then it's indicative of a leak.
- DCHECK((*i)->GetRequestInfo()->IsDownload() ||
- (*i)->GetRequestInfo()->is_stream() ||
- ((*i)->GetRequestInfo()->detachable_handler() &&
- (*i)->GetRequestInfo()->detachable_handler()->is_detached()) ||
- (*i)->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER ||
- (*i)->is_transferring());
+ DCHECK(loader->GetRequestInfo()->IsDownload() ||
+ loader->GetRequestInfo()->is_stream() ||
+ (loader->GetRequestInfo()->detachable_handler() &&
+ loader->GetRequestInfo()->detachable_handler()->is_detached()) ||
+ loader->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER ||
+ loader->is_transferring());
}
#endif
@@ -633,15 +722,13 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
}
// Validate that no more requests for this context were added.
- for (LoaderMap::const_iterator i = pending_loaders_.begin();
- i != pending_loaders_.end(); ++i) {
+ for (const auto& loader : pending_loaders_) {
// http://crbug.com/90971
- CHECK_NE(i->second->GetRequestInfo()->GetContext(), context);
+ CHECK_NE(loader.second->GetRequestInfo()->GetContext(), context);
}
- for (BlockedLoadersMap::const_iterator i = blocked_loaders_map_.begin();
- i != blocked_loaders_map_.end(); ++i) {
- BlockedLoadersList* loaders = i->second;
+ for (const auto& blocked_loaders : blocked_loaders_map_) {
+ BlockedLoadersList* loaders = blocked_loaders.second.get();
if (!loaders->empty()) {
ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo();
// http://crbug.com/90971
@@ -651,21 +738,16 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
}
DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
- scoped_ptr<net::URLRequest> request,
+ std::unique_ptr<net::URLRequest> request,
const Referrer& referrer,
bool is_content_initiated,
ResourceContext* context,
int child_id,
int render_view_route_id,
int render_frame_route_id,
- bool prefer_cache,
- bool do_not_prompt_for_login,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadStartedCallback& started_callback) {
+ bool do_not_prompt_for_login) {
if (is_shutdown_)
- return CallbackAndReturn(started_callback,
- DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN);
+ return DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN;
const GURL& url = request->original_url();
@@ -677,21 +759,6 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
SetReferrerForRequest(request.get(), referrer);
- int extra_load_flags = net::LOAD_NORMAL;
- if (prefer_cache) {
- // If there is upload data attached, only retrieve from cache because there
- // is no current mechanism to prompt the user for their consent for a
- // re-post. For GETs, try to retrieve data from the cache and skip
- // validating the entry if present.
- if (request->get_upload() != NULL)
- extra_load_flags |= net::LOAD_ONLY_FROM_CACHE;
- else
- extra_load_flags |= net::LOAD_PREFERRING_CACHE;
- } else {
- extra_load_flags |= net::LOAD_DISABLE_CACHE;
- }
- request->SetLoadFlags(request->load_flags() | extra_load_flags);
-
// We treat a download as a main frame load, and thus update the policy URL on
// redirects.
//
@@ -704,20 +771,18 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
// Check if the renderer is permitted to request the requested URL.
if (!ChildProcessSecurityPolicyImpl::GetInstance()->
CanRequestURL(child_id, url)) {
- VLOG(1) << "Denied unauthorized download request for "
- << url.possibly_invalid_spec();
- return CallbackAndReturn(started_callback,
- DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
+ DVLOG(1) << "Denied unauthorized download request for "
+ << url.possibly_invalid_spec();
+ return DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST;
}
request_id_--;
const net::URLRequestContext* request_context = context->GetRequestContext();
if (!request_context->job_factory()->IsHandledURL(url)) {
- VLOG(1) << "Download request for unsupported protocol: "
- << url.possibly_invalid_spec();
- return CallbackAndReturn(started_callback,
- DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
+ DVLOG(1) << "Download request for unsupported protocol: "
+ << url.possibly_invalid_spec();
+ return DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST;
}
ResourceRequestInfoImpl* extra_info =
@@ -726,7 +791,8 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
extra_info->set_do_not_prompt_for_login(do_not_prompt_for_login);
extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
- if (request->url().SchemeIs(url::kBlobScheme)) {
+ if (request->url().SchemeIs(url::kBlobScheme) &&
+ !storage::BlobProtocolHandler::GetRequestBlobDataHandle(request.get())) {
ChromeBlobStorageContext* blob_context =
GetChromeBlobStorageContextForResourceContext(context);
storage::BlobProtocolHandler::SetRequestedBlobDataHandle(
@@ -736,9 +802,8 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
// From this point forward, the |DownloadResourceHandler| is responsible for
// |started_callback|.
- scoped_ptr<ResourceHandler> handler(CreateResourceHandlerForDownload(
- request.get(), is_content_initiated, true, download_id,
- std::move(save_info), started_callback));
+ std::unique_ptr<ResourceHandler> handler(CreateResourceHandlerForDownload(
+ request.get(), is_content_initiated, true));
BeginRequestInternal(std::move(request), std::move(handler));
@@ -763,16 +828,13 @@ void ResourceDispatcherHostImpl::Shutdown() {
base::Unretained(this)));
}
-scoped_ptr<ResourceHandler>
+std::unique_ptr<ResourceHandler>
ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
- bool must_download,
- uint32_t id,
- scoped_ptr<DownloadSaveInfo> save_info,
- const DownloadUrlParameters::OnStartedCallback& started_cb) {
- scoped_ptr<ResourceHandler> handler(new DownloadResourceHandler(
- id, request, started_cb, std::move(save_info)));
+ bool must_download) {
+ std::unique_ptr<ResourceHandler> handler(
+ new DownloadResourceHandler(request));
if (delegate_) {
const ResourceRequestInfoImpl* request_info(
ResourceRequestInfoImpl::ForRequest(request));
@@ -790,7 +852,8 @@ ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
return handler;
}
-scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::MaybeInterceptAsStream(
+std::unique_ptr<ResourceHandler>
+ResourceDispatcherHostImpl::MaybeInterceptAsStream(
const base::FilePath& plugin_path,
net::URLRequest* request,
ResourceResponse* response,
@@ -803,19 +866,17 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::MaybeInterceptAsStream(
if (!delegate_ ||
!delegate_->ShouldInterceptResourceAsStream(
request, plugin_path, mime_type, &origin, payload)) {
- return scoped_ptr<ResourceHandler>();
+ return std::unique_ptr<ResourceHandler>();
}
StreamContext* stream_context =
GetStreamContextForResourceContext(info->GetContext());
- scoped_ptr<StreamResourceHandler> handler(
- new StreamResourceHandler(request,
- stream_context->registry(),
- origin));
+ std::unique_ptr<StreamResourceHandler> handler(
+ new StreamResourceHandler(request, stream_context->registry(), origin));
info->set_is_stream(true);
- scoped_ptr<StreamInfo> stream_info(new StreamInfo);
+ std::unique_ptr<StreamInfo> stream_info(new StreamInfo);
stream_info->handle = handler->stream()->CreateHandle();
stream_info->original_url = request->url();
stream_info->mime_type = mime_type;
@@ -907,9 +968,9 @@ void ResourceDispatcherHostImpl::DidReceiveRedirect(ResourceLoader* loader,
return;
// Notify the observers on the UI thread.
- scoped_ptr<ResourceRedirectDetails> detail(new ResourceRedirectDetails(
+ std::unique_ptr<ResourceRedirectDetails> detail(new ResourceRedirectDetails(
loader->request(),
- GetCertID(loader->request(), info->GetChildID()),
+ GetCertID(GetCertStore(), loader->request(), info->GetChildID()),
new_url));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -934,6 +995,8 @@ void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
scheduler_.get());
}
+ ProcessRequestForLinkHeaders(request);
+
int render_process_id, render_frame_host;
if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host))
return;
@@ -945,8 +1008,8 @@ void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
return;
// Notify the observers on the UI thread.
- scoped_ptr<ResourceRequestDetails> detail(new ResourceRequestDetails(
- request, GetCertID(request, info->GetChildID())));
+ std::unique_ptr<ResourceRequestDetails> detail(new ResourceRequestDetails(
+ request, GetCertID(GetCertStore(), request, info->GetChildID())));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
@@ -984,6 +1047,27 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
UMA_HISTOGRAM_LONG_TIMES(
"Net.RequestTime2.ErrAborted", request_loading_time);
+ if (loader->request()->url().SchemeIsHTTPOrHTTPS()) {
+ UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.HttpScheme",
+ request_loading_time);
+ } else {
+ UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.NonHttpScheme",
+ request_loading_time);
+ }
+
+ if (loader->request()->GetTotalReceivedBytes() > 0) {
+ UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.NetworkContent",
+ request_loading_time);
+ } else if (loader->request()->received_response_content_length() > 0) {
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime2.ErrAborted.NoNetworkContent.CachedContent",
+ request_loading_time);
+ } else {
+ UMA_HISTOGRAM_LONG_TIMES(
+ "Net.RequestTime2.ErrAborted.NoBytesRead",
+ request_loading_time);
+ }
+
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&RecordAbortRapporOnUI, loader->request()->url(),
@@ -1071,17 +1155,15 @@ void ResourceDispatcherHostImpl::OnShutdown() {
// Note that we have to do this in 2 passes as we cannot call
// CancelBlockedRequestsForRoute while iterating over
// blocked_loaders_map_, as it modifies it.
- std::set<GlobalRoutingID> ids;
- for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
- iter != blocked_loaders_map_.end(); ++iter) {
- std::pair<std::set<GlobalRoutingID>::iterator, bool> result =
- ids.insert(iter->first);
+ std::set<GlobalFrameRoutingId> ids;
+ for (const auto& blocked_loaders : blocked_loaders_map_) {
+ std::pair<std::set<GlobalFrameRoutingId>::iterator, bool> result =
+ ids.insert(blocked_loaders.first);
// We should not have duplicates.
DCHECK(result.second);
}
- for (std::set<GlobalRoutingID>::const_iterator iter = ids.begin();
- iter != ids.end(); ++iter) {
- CancelBlockedRequestsForRoute(iter->child_id, iter->route_id);
+ for (const auto& routing_id : ids) {
+ CancelBlockedRequestsForRoute(routing_id);
}
scheduler_.reset();
@@ -1170,18 +1252,32 @@ void ResourceDispatcherHostImpl::OnSyncLoad(
sync_result->routing_id());
}
+bool ResourceDispatcherHostImpl::IsRequestIDInUse(
+ const GlobalRequestID& id) const {
+ if (pending_loaders_.find(id) != pending_loaders_.end())
+ return true;
+ for (const auto& blocked_loaders : blocked_loaders_map_) {
+ for (const auto& loader : *blocked_loaders.second.get()) {
+ ResourceRequestInfoImpl* info = loader->GetRequestInfo();
+ if (info->GetGlobalRequestID() == id)
+ return true;
+ }
+ }
+ return false;
+}
+
void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
int child_id,
int route_id,
int request_id,
const ResourceHostMsg_Request& request_data,
- const linked_ptr<ResourceLoader>& loader) {
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- GlobalRoutingID old_routing_id(
- request_data.transferred_request_child_id, info->GetRouteID());
+ LoaderMap::iterator iter) {
+ ResourceRequestInfoImpl* info = iter->second->GetRequestInfo();
+ GlobalFrameRoutingId old_routing_id(request_data.transferred_request_child_id,
+ info->GetRenderFrameID());
GlobalRequestID old_request_id(request_data.transferred_request_child_id,
request_data.transferred_request_request_id);
- GlobalRoutingID new_routing_id(child_id, route_id);
+ GlobalFrameRoutingId new_routing_id(child_id, request_data.render_frame_id);
GlobalRequestID new_request_id(child_id, request_id);
// Clear out data that depends on |info| before updating it.
@@ -1192,7 +1288,11 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
bool should_update_count = info->counted_as_in_flight_request();
if (should_update_count)
IncrementOutstandingRequestsCount(-1, info);
- pending_loaders_.erase(old_request_id);
+
+ DCHECK(pending_loaders_.find(old_request_id) == iter);
+ std::unique_ptr<ResourceLoader> loader = std::move(iter->second);
+ ResourceLoader* loader_ptr = loader.get();
+ pending_loaders_.erase(iter);
// ResourceHandlers should always get state related to the request from the
// ResourceRequestInfo rather than caching it locally. This lets us update
@@ -1201,9 +1301,17 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
request_data.origin_pid, request_id,
filter_->GetWeakPtr());
+ // If a certificate is stored with the ResourceResponse, it has to be
+ // updated to be associated with the new process.
+ if (loader->transferring_response()) {
+ UpdateResponseCertificateForTransfer(loader->transferring_response(),
+ loader->request()->ssl_info(),
+ child_id);
+ }
+
// Update maps that used the old IDs, if necessary. Some transfers in tests
// do not actually use a different ID, so not all maps need to be updated.
- pending_loaders_[new_request_id] = loader;
+ pending_loaders_[new_request_id] = std::move(loader);
IncrementOutstandingRequestsMemory(1, *info);
if (should_update_count)
IncrementOutstandingRequestsCount(1, info);
@@ -1211,7 +1319,7 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
if (blocked_loaders_map_.find(old_routing_id) !=
blocked_loaders_map_.end()) {
blocked_loaders_map_[new_routing_id] =
- blocked_loaders_map_[old_routing_id];
+ std::move(blocked_loaders_map_[old_routing_id]);
blocked_loaders_map_.erase(old_routing_id);
}
}
@@ -1231,15 +1339,21 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
}
AppCacheInterceptor::CompleteCrossSiteTransfer(
- loader->request(),
+ loader_ptr->request(),
child_id,
- request_data.appcache_host_id);
+ request_data.appcache_host_id,
+ filter_);
ServiceWorkerRequestHandler* handler =
- ServiceWorkerRequestHandler::GetHandler(loader->request());
+ ServiceWorkerRequestHandler::GetHandler(loader_ptr->request());
if (handler) {
- handler->CompleteCrossSiteTransfer(
- child_id, request_data.service_worker_provider_id);
+ if (!handler->SanityCheckIsSameContext(filter_->service_worker_context())) {
+ bad_message::ReceivedBadMessage(
+ filter_, bad_message::RDHI_WRONG_STORAGE_PARTITION);
+ } else {
+ handler->CompleteCrossSiteTransfer(
+ child_id, request_data.service_worker_provider_id);
+ }
}
// We should have a CrossSiteResourceHandler to finish the transfer.
@@ -1254,10 +1368,19 @@ void ResourceDispatcherHostImpl::BeginRequest(
int process_type = filter_->process_type();
int child_id = filter_->child_id();
+ // Reject request id that's currently in use.
+ if (IsRequestIDInUse(GlobalRequestID(child_id, request_id))) {
+ bad_message::ReceivedBadMessage(filter_,
+ bad_message::RDH_INVALID_REQUEST_ID);
+ return;
+ }
+
// PlzNavigate: reject invalid renderer main resource request.
- if (IsBrowserSideNavigationEnabled() &&
- IsResourceTypeFrame(request_data.resource_type) &&
- !request_data.url.SchemeIs(url::kBlobScheme)) {
+ bool is_navigation_stream_request =
+ IsBrowserSideNavigationEnabled() &&
+ IsResourceTypeFrame(request_data.resource_type);
+ if (is_navigation_stream_request &&
+ !request_data.resource_body_stream_url.SchemeIs(url::kBlobScheme)) {
bad_message::ReceivedBadMessage(filter_, bad_message::RDH_INVALID_URL);
return;
}
@@ -1284,10 +1407,9 @@ void ResourceDispatcherHostImpl::BeginRequest(
// If the request is transferring to a new process, we can update our
// state and let it resume with its existing ResourceHandlers.
if (it->second->is_transferring()) {
- linked_ptr<ResourceLoader> deferred_loader = it->second;
+ ResourceLoader* deferred_loader = it->second.get();
UpdateRequestForTransfer(child_id, route_id, request_id,
- request_data, deferred_loader);
-
+ request_data, it);
deferred_loader->CompleteTransfer();
} else {
bad_message::ReceivedBadMessage(
@@ -1325,14 +1447,29 @@ void ResourceDispatcherHostImpl::BeginRequest(
}
// Construct the request.
- scoped_ptr<net::URLRequest> new_request = request_context->CreateRequest(
- request_data.url, request_data.priority, NULL);
+ std::unique_ptr<net::URLRequest> new_request = request_context->CreateRequest(
+ is_navigation_stream_request ? request_data.resource_body_stream_url
+ : request_data.url,
+ request_data.priority, nullptr);
+
+ // PlzNavigate: Always set the method to GET when gaining access to the
+ // stream that contains the response body of a navigation. Otherwise the data
+ // that was already fetched by the browser will not be transmitted to the
+ // renderer.
+ if (is_navigation_stream_request)
+ new_request->set_method("GET");
+ else
+ new_request->set_method(request_data.method);
- new_request->set_method(request_data.method);
new_request->set_first_party_for_cookies(
request_data.first_party_for_cookies);
new_request->set_initiator(request_data.request_initiator);
+ if (request_data.originated_from_service_worker) {
+ new_request->SetUserData(URLRequestServiceWorkerData::kUserDataKey,
+ new URLRequestServiceWorkerData());
+ }
+
// If the request is a MAIN_FRAME request, the first-party URL gets updated on
// redirects.
if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME) {
@@ -1426,28 +1563,20 @@ void ResourceDispatcherHostImpl::BeginRequest(
ResourceRequestInfoImpl* extra_info = new ResourceRequestInfoImpl(
process_type, child_id, route_id,
-1, // frame_tree_node_id
- request_data.origin_pid,
- request_id,
- request_data.render_frame_id,
- request_data.is_main_frame,
- request_data.parent_is_main_frame,
- request_data.resource_type,
- request_data.transition_type,
+ request_data.origin_pid, request_id, request_data.render_frame_id,
+ request_data.is_main_frame, request_data.parent_is_main_frame,
+ request_data.resource_type, request_data.transition_type,
request_data.should_replace_current_entry,
false, // is download
false, // is stream
- allow_download,
- request_data.has_user_gesture,
- request_data.enable_load_timing,
- request_data.enable_upload_progress,
- do_not_prompt_for_login,
- request_data.referrer_policy,
- request_data.visiblity_state,
- resource_context, filter_->GetWeakPtr(),
- report_raw_headers,
- !is_sync_load,
- IsUsingLoFi(request_data.lofi_state, delegate_,
- *new_request, resource_context),
+ allow_download, request_data.has_user_gesture,
+ request_data.enable_load_timing, request_data.enable_upload_progress,
+ do_not_prompt_for_login, request_data.referrer_policy,
+ request_data.visiblity_state, resource_context, filter_->GetWeakPtr(),
+ report_raw_headers, !is_sync_load,
+ IsUsingLoFi(request_data.lofi_state, delegate_, *new_request,
+ resource_context,
+ request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME),
support_async_revalidation ? request_data.headers : std::string());
// Request takes ownership.
extra_info->AssociateWithRequest(new_request.get());
@@ -1492,17 +1621,16 @@ void ResourceDispatcherHostImpl::BeginRequest(
request_data.appcache_host_id, request_data.resource_type,
request_data.should_reset_appcache);
- scoped_ptr<ResourceHandler> handler(
- CreateResourceHandler(
- new_request.get(),
- request_data, sync_result, route_id, process_type, child_id,
- resource_context));
+ std::unique_ptr<ResourceHandler> handler(CreateResourceHandler(
+ new_request.get(), request_data, sync_result, route_id, process_type,
+ child_id, resource_context));
if (handler)
BeginRequestInternal(std::move(new_request), std::move(handler));
}
-scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
+std::unique_ptr<ResourceHandler>
+ResourceDispatcherHostImpl::CreateResourceHandler(
net::URLRequest* request,
const ResourceHostMsg_Request& request_data,
IPC::Message* sync_result,
@@ -1515,12 +1643,12 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"456331 ResourceDispatcherHostImpl::CreateResourceHandler"));
// Construct the IPC resource handler.
- scoped_ptr<ResourceHandler> handler;
+ std::unique_ptr<ResourceHandler> handler;
if (sync_result) {
// download_to_file is not supported for synchronous requests.
if (request_data.download_to_file) {
bad_message::ReceivedBadMessage(filter_, bad_message::RDH_BAD_DOWNLOAD);
- return scoped_ptr<ResourceHandler>();
+ return std::unique_ptr<ResourceHandler>();
}
handler.reset(new SyncResourceHandler(request, sync_result, this));
@@ -1569,14 +1697,15 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
child_id, route_id, std::move(handler));
}
-scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::AddStandardHandlers(
+std::unique_ptr<ResourceHandler>
+ResourceDispatcherHostImpl::AddStandardHandlers(
net::URLRequest* request,
ResourceType resource_type,
ResourceContext* resource_context,
AppCacheService* appcache_service,
int child_id,
int route_id,
- scoped_ptr<ResourceHandler> handler) {
+ std::unique_ptr<ResourceHandler> handler) {
// PlzNavigate: do not add ResourceThrottles for main resource requests from
// the renderer. Decisions about the navigation should have been done in the
// initial request.
@@ -1748,18 +1877,19 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
std::string()); // original_headers
}
+void ResourceDispatcherHostImpl::OnRenderFrameDeleted(
+ const GlobalFrameRoutingId& global_routing_id) {
+ CancelRequestsForRoute(global_routing_id);
+}
+
void ResourceDispatcherHostImpl::OnRenderViewHostCreated(int child_id,
- int route_id,
- bool is_visible,
- bool is_audible) {
- scheduler_->OnClientCreated(child_id, route_id, is_visible, is_audible);
+ int route_id) {
+ scheduler_->OnClientCreated(child_id, route_id);
}
-void ResourceDispatcherHostImpl::OnRenderViewHostDeleted(
- int child_id,
- int route_id) {
+void ResourceDispatcherHostImpl::OnRenderViewHostDeleted(int child_id,
+ int route_id) {
scheduler_->OnClientDeleted(child_id, route_id);
- CancelRequestsForRoute(child_id, route_id);
}
void ResourceDispatcherHostImpl::OnRenderViewHostSetIsLoading(int child_id,
@@ -1768,29 +1898,6 @@ void ResourceDispatcherHostImpl::OnRenderViewHostSetIsLoading(int child_id,
scheduler_->OnLoadingStateChanged(child_id, route_id, !is_loading);
}
-void ResourceDispatcherHostImpl::OnRenderViewHostWasHidden(
- int child_id,
- int route_id) {
- scheduler_->OnVisibilityChanged(child_id, route_id, false);
-}
-
-void ResourceDispatcherHostImpl::OnRenderViewHostWasShown(
- int child_id,
- int route_id) {
- scheduler_->OnVisibilityChanged(child_id, route_id, true);
-}
-
-void ResourceDispatcherHostImpl::OnAudioRenderHostStreamStateChanged(
- int child_id,
- int route_id,
- bool is_playing) {
- // The ResourceDispatcherHost may have already been shut down.
- // See http://crbug.com/455098
- if (!scheduler_)
- return;
- scheduler_->OnAudibilityChanged(child_id, route_id, is_playing);
-}
-
// This function is only used for saving feature.
void ResourceDispatcherHostImpl::BeginSaveFile(const GURL& url,
const Referrer& referrer,
@@ -1822,7 +1929,7 @@ void ResourceDispatcherHostImpl::BeginSaveFile(const GURL& url,
return;
}
- scoped_ptr<net::URLRequest> request(
+ std::unique_ptr<net::URLRequest> request(
request_context->CreateRequest(url, net::DEFAULT_PRIORITY, NULL));
request->set_method("GET");
SetReferrerForRequest(request.get(), referrer);
@@ -1837,7 +1944,7 @@ void ResourceDispatcherHostImpl::BeginSaveFile(const GURL& url,
render_frame_route_id, false, context);
extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
- scoped_ptr<ResourceHandler> handler(new SaveFileResourceHandler(
+ std::unique_ptr<ResourceHandler> handler(new SaveFileResourceHandler(
request.get(), save_item_id, save_package_id, child_id,
render_frame_route_id, url, save_file_manager_.get()));
@@ -1845,8 +1952,9 @@ void ResourceDispatcherHostImpl::BeginSaveFile(const GURL& url,
}
void ResourceDispatcherHostImpl::MarkAsTransferredNavigation(
- const GlobalRequestID& id) {
- GetLoader(id)->MarkAsTransferring();
+ const GlobalRequestID& id,
+ const scoped_refptr<ResourceResponse>& response) {
+ GetLoader(id)->MarkAsTransferring(response);
}
void ResourceDispatcherHostImpl::CancelTransferringNavigation(
@@ -1868,29 +1976,33 @@ void ResourceDispatcherHostImpl::ResumeDeferredNavigation(
// for downloads and detachable resources, which belong to the browser process
// even if initiated via a renderer.
void ResourceDispatcherHostImpl::CancelRequestsForProcess(int child_id) {
- CancelRequestsForRoute(child_id, -1 /* cancel all */);
+ CancelRequestsForRoute(
+ GlobalFrameRoutingId(child_id, MSG_ROUTING_NONE /* cancel all */));
registered_temp_files_.erase(child_id);
}
-void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id,
- int route_id) {
+void ResourceDispatcherHostImpl::CancelRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id) {
// Since pending_requests_ is a map, we first build up a list of all of the
// matching requests to be cancelled, and then we cancel them. Since there
// may be more than one request to cancel, we cannot simply hold onto the map
// iterators found in the first loop.
// Find the global ID of all matching elements.
+ int child_id = global_routing_id.child_id;
+ int route_id = global_routing_id.frame_routing_id;
+ bool cancel_all_routes = (route_id == MSG_ROUTING_NONE);
+
bool any_requests_transferring = false;
std::vector<GlobalRequestID> matching_requests;
- for (LoaderMap::const_iterator i = pending_loaders_.begin();
- i != pending_loaders_.end(); ++i) {
- if (i->first.child_id != child_id)
+ for (const auto& loader : pending_loaders_) {
+ if (loader.first.child_id != child_id)
continue;
- ResourceRequestInfoImpl* info = i->second->GetRequestInfo();
+ ResourceRequestInfoImpl* info = loader.second->GetRequestInfo();
- GlobalRequestID id(child_id, i->first.request_id);
- DCHECK(id == i->first);
+ GlobalRequestID id(child_id, loader.first.request_id);
+ DCHECK(id == loader.first);
// Don't cancel navigations that are expected to live beyond this process.
if (IsTransferredNavigation(id))
any_requests_transferring = true;
@@ -1898,7 +2010,7 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id,
info->detachable_handler()->Detach();
} else if (!info->IsDownload() && !info->is_stream() &&
!IsTransferredNavigation(id) &&
- (route_id == -1 || route_id == info->GetRouteID())) {
+ (cancel_all_routes || route_id == info->GetRenderFrameID())) {
matching_requests.push_back(id);
}
}
@@ -1928,25 +2040,23 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id,
return;
// Now deal with blocked requests if any.
- if (route_id != -1) {
- if (blocked_loaders_map_.find(GlobalRoutingID(child_id, route_id)) !=
+ if (!cancel_all_routes) {
+ if (blocked_loaders_map_.find(global_routing_id) !=
blocked_loaders_map_.end()) {
- CancelBlockedRequestsForRoute(child_id, route_id);
+ CancelBlockedRequestsForRoute(global_routing_id);
}
} else {
- // We have to do all render views for the process |child_id|.
+ // We have to do all render frames for the process |child_id|.
// Note that we have to do this in 2 passes as we cannot call
// CancelBlockedRequestsForRoute while iterating over
- // blocked_loaders_map_, as it modifies it.
- std::set<int> route_ids;
- for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin();
- iter != blocked_loaders_map_.end(); ++iter) {
- if (iter->first.child_id == child_id)
- route_ids.insert(iter->first.route_id);
+ // blocked_loaders_map_, as blocking requests modifies the map.
+ std::set<GlobalFrameRoutingId> routing_ids;
+ for (const auto& blocked_loaders : blocked_loaders_map_) {
+ if (blocked_loaders.first.child_id == child_id)
+ routing_ids.insert(blocked_loaders.first);
}
- for (std::set<int>::const_iterator iter = route_ids.begin();
- iter != route_ids.end(); ++iter) {
- CancelBlockedRequestsForRoute(child_id, *iter);
+ for (const GlobalFrameRoutingId& route_id : routing_ids) {
+ CancelBlockedRequestsForRoute(route_id);
}
}
}
@@ -2082,7 +2192,7 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// needs to be checked relative to the child that /requested/ the
// navigation. It's where file upload checks, etc., come in.
(delegate_ && !delegate_->ShouldBeginRequest(
- info.begin_params.method,
+ info.common_params.method,
info.common_params.url,
resource_type,
resource_context))) {
@@ -2113,11 +2223,11 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// requests that have the ignore limits flag set.
DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
- scoped_ptr<net::URLRequest> new_request;
+ std::unique_ptr<net::URLRequest> new_request;
new_request = request_context->CreateRequest(
info.common_params.url, net::HIGHEST, nullptr);
- new_request->set_method(info.begin_params.method);
+ new_request->set_method(info.common_params.method);
new_request->set_first_party_for_cookies(
info.first_party_for_cookies);
new_request->set_initiator(info.request_initiator);
@@ -2167,8 +2277,8 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
-1, // request_data.origin_pid,
request_id_,
-1, // request_data.render_frame_id,
- info.is_main_frame, info.parent_is_main_frame,
- resource_type, info.common_params.transition,
+ info.is_main_frame, info.parent_is_main_frame, resource_type,
+ info.common_params.transition,
// should_replace_current_entry. This was only maintained at layer for
// request transfers and isn't needed for browser-side navigations.
false,
@@ -2186,8 +2296,8 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
base::WeakPtr<ResourceMessageFilter>(), // filter
false, // request_data.report_raw_headers
true, // is_async
- IsUsingLoFi(info.common_params.lofi_state, delegate_,
- *new_request, resource_context),
+ IsUsingLoFi(info.common_params.lofi_state, delegate_, *new_request,
+ resource_context, info.is_main_frame),
// The original_headers field is for stale-while-revalidate but the
// feature doesn't work with PlzNavigate, so it's just a placeholder
// here.
@@ -2215,8 +2325,8 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// TODO(davidben): Attach AppCacheInterceptor.
- scoped_ptr<ResourceHandler> handler(new NavigationResourceHandler(
- new_request.get(), loader));
+ std::unique_ptr<ResourceHandler> handler(
+ new NavigationResourceHandler(new_request.get(), loader));
// TODO(davidben): Pass in the appropriate appcache_service. Also fix the
// dependency on child_id/route_id. Those are used by the ResourceScheduler;
@@ -2253,8 +2363,8 @@ int ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(
}
void ResourceDispatcherHostImpl::BeginRequestInternal(
- scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceHandler> handler) {
+ std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceHandler> handler) {
DCHECK(!request->is_pending());
ResourceRequestInfoImpl* info =
ResourceRequestInfoImpl::ForRequest(request.get());
@@ -2290,30 +2400,32 @@ void ResourceDispatcherHostImpl::BeginRequestInternal(
return;
}
- linked_ptr<ResourceLoader> loader(
- new ResourceLoader(std::move(request), std::move(handler), this));
+ std::unique_ptr<ResourceLoader> loader(new ResourceLoader(
+ std::move(request), std::move(handler), GetCertStore(), this));
- GlobalRoutingID id(info->GetGlobalRoutingID());
+ GlobalFrameRoutingId id(info->GetChildID(), info->GetRenderFrameID());
BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.find(id);
if (iter != blocked_loaders_map_.end()) {
// The request should be blocked.
- iter->second->push_back(loader);
+ iter->second->push_back(std::move(loader));
return;
}
- StartLoading(info, loader);
+ StartLoading(info, std::move(loader));
}
void ResourceDispatcherHostImpl::StartLoading(
ResourceRequestInfoImpl* info,
- const linked_ptr<ResourceLoader>& loader) {
+ std::unique_ptr<ResourceLoader> loader) {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"456331 ResourceDispatcherHostImpl::StartLoading"));
- pending_loaders_[info->GetGlobalRequestID()] = loader;
- loader->StartRequest();
+ ResourceLoader* loader_ptr = loader.get();
+ pending_loaders_[info->GetGlobalRequestID()] = std::move(loader);
+
+ loader_ptr->StartRequest();
}
void ResourceDispatcherHostImpl::OnUserGesture(WebContentsImpl* contents) {
@@ -2351,7 +2463,7 @@ bool ResourceDispatcherHostImpl::LoadInfoIsMoreInteresting(const LoadInfo& a,
// static
void ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread(
- scoped_ptr<LoadInfoMap> info_map) {
+ std::unique_ptr<LoadInfoMap> info_map) {
// TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466285
// is fixed.
tracked_objects::ScopedTracker tracking_profile(
@@ -2370,11 +2482,11 @@ void ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread(
}
}
-scoped_ptr<ResourceDispatcherHostImpl::LoadInfoMap>
+std::unique_ptr<ResourceDispatcherHostImpl::LoadInfoMap>
ResourceDispatcherHostImpl::GetLoadInfoForAllRoutes() {
// Populate this map with load state changes, and then send them on to the UI
// thread where they can be passed along to the respective RVHs.
- scoped_ptr<LoadInfoMap> info_map(new LoadInfoMap());
+ std::unique_ptr<LoadInfoMap> info_map(new LoadInfoMap());
for (const auto& loader : pending_loaders_) {
net::URLRequest* request = loader.second->request();
@@ -2398,7 +2510,7 @@ ResourceDispatcherHostImpl::GetLoadInfoForAllRoutes() {
}
void ResourceDispatcherHostImpl::UpdateLoadInfo() {
- scoped_ptr<LoadInfoMap> info_map(GetLoadInfoForAllRoutes());
+ std::unique_ptr<LoadInfoMap> info_map(GetLoadInfoForAllRoutes());
// Stop the timer if there are no more pending requests. Future new requests
// will restart it as necessary.
@@ -2415,54 +2527,51 @@ void ResourceDispatcherHostImpl::UpdateLoadInfo() {
base::Passed(&info_map)));
}
-void ResourceDispatcherHostImpl::BlockRequestsForRoute(int child_id,
- int route_id) {
+void ResourceDispatcherHostImpl::BlockRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- GlobalRoutingID key(child_id, route_id);
- DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) <<
- "BlockRequestsForRoute called multiple time for the same RVH";
- blocked_loaders_map_[key] = new BlockedLoadersList();
+ DCHECK(blocked_loaders_map_.find(global_routing_id) ==
+ blocked_loaders_map_.end())
+ << "BlockRequestsForRoute called multiple time for the same RFH";
+ blocked_loaders_map_[global_routing_id] =
+ base::WrapUnique(new BlockedLoadersList());
}
-void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(int child_id,
- int route_id) {
- ProcessBlockedRequestsForRoute(child_id, route_id, false);
+void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id) {
+ ProcessBlockedRequestsForRoute(global_routing_id, false);
}
-void ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute(int child_id,
- int route_id) {
- ProcessBlockedRequestsForRoute(child_id, route_id, true);
+void ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id) {
+ ProcessBlockedRequestsForRoute(global_routing_id, true);
}
void ResourceDispatcherHostImpl::ProcessBlockedRequestsForRoute(
- int child_id,
- int route_id,
+ const GlobalFrameRoutingId& global_routing_id,
bool cancel_requests) {
- BlockedLoadersMap::iterator iter = blocked_loaders_map_.find(
- GlobalRoutingID(child_id, route_id));
+ BlockedLoadersMap::iterator iter =
+ blocked_loaders_map_.find(global_routing_id);
if (iter == blocked_loaders_map_.end()) {
// It's possible to reach here if the renderer crashed while an interstitial
// page was showing.
return;
}
- BlockedLoadersList* loaders = iter->second;
+ BlockedLoadersList* loaders = iter->second.get();
+ std::unique_ptr<BlockedLoadersList> deleter(std::move(iter->second));
// Removing the vector from the map unblocks any subsequent requests.
blocked_loaders_map_.erase(iter);
- for (BlockedLoadersList::iterator loaders_iter = loaders->begin();
- loaders_iter != loaders->end(); ++loaders_iter) {
- linked_ptr<ResourceLoader> loader = *loaders_iter;
+ for (std::unique_ptr<ResourceLoader>& loader : *loaders) {
ResourceRequestInfoImpl* info = loader->GetRequestInfo();
if (cancel_requests) {
IncrementOutstandingRequestsMemory(-1, *info);
} else {
- StartLoading(info, loader);
+ StartLoading(info, std::move(loader));
}
}
-
- delete loaders;
}
ResourceDispatcherHostImpl::HttpAuthRelationType
@@ -2557,4 +2666,29 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest(
return load_flags;
}
+void ResourceDispatcherHostImpl::UpdateResponseCertificateForTransfer(
+ ResourceResponse* response,
+ const net::SSLInfo& ssl_info,
+ int child_id) {
+ if (!ssl_info.cert)
+ return;
+ SSLStatus ssl;
+ // DeserializeSecurityInfo() often takes security info sent by a
+ // renderer as input, in which case it's important to check that the
+ // security info deserializes properly and kill the renderer if
+ // not. In this case, however, the security info has been provided by
+ // the ResourceLoader, so it does not need to be treated as untrusted
+ // data.
+ bool deserialized =
+ DeserializeSecurityInfo(response->head.security_info, &ssl);
+ DCHECK(deserialized);
+ ssl.cert_id = GetCertStore()->StoreCert(ssl_info.cert.get(), child_id);
+ response->head.security_info = SerializeSecurityInfo(ssl);
+}
+
+CertStore* ResourceDispatcherHostImpl::GetCertStore() {
+ return cert_store_for_testing_ ? cert_store_for_testing_
+ : CertStore::GetInstance();
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.h b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
index 74922647f29..086f39bea06 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
@@ -15,14 +15,13 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -40,6 +39,7 @@
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/resource_type.h"
#include "ipc/ipc_message.h"
#include "net/base/request_priority.h"
@@ -64,7 +64,10 @@ class ShareableFileReference;
namespace content {
class AppCacheService;
class AsyncRevalidationManager;
+class CertStore;
+class FrameTree;
class NavigationURLLoaderImplCore;
+class RenderFrameHostImpl;
class ResourceContext;
class ResourceDispatcherHostDelegate;
class ResourceMessageDelegate;
@@ -78,6 +81,22 @@ struct DownloadSaveInfo;
struct NavigationRequestInfo;
struct Referrer;
+// This class is responsible for notifying the IO thread (specifically, the
+// ResourceDispatcherHostImpl) of frame events. It has an interace for callers
+// to use and also sends notifications on WebContentsObserver events. All
+// methods (static or class) will be called from the UI thread and post to the
+// IO thread.
+// TODO(csharrison): Add methods tracking visibility and audio changes, to
+// propogate to the ResourceScheduler.
+class LoaderIOThreadNotifier : public WebContentsObserver {
+ public:
+ explicit LoaderIOThreadNotifier(WebContents* web_contents);
+ ~LoaderIOThreadNotifier() override;
+
+ // content::WebContentsObserver:
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+};
+
class CONTENT_EXPORT ResourceDispatcherHostImpl
: public ResourceDispatcherHost,
public ResourceLoaderDelegate {
@@ -89,25 +108,28 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// hasn't been created yet.
static ResourceDispatcherHostImpl* Get();
+ // The following static methods should all be called from the UI thread.
+
+ // Resumes requests for a given render frame routing id. This will only resume
+ // requests for a single frame.
+ static void ResumeBlockedRequestsForRouteFromUI(
+ const GlobalFrameRoutingId& global_routing_id);
+
+ // Blocks (and does not start) all requests for the frame and its subframes.
+ static void BlockRequestsForFrameFromUI(RenderFrameHost* root_frame_host);
+
+ // Resumes any blocked requests for the specified frame and its subframes.
+ static void ResumeBlockedRequestsForFrameFromUI(
+ RenderFrameHost* root_frame_host);
+
+ // Cancels any blocked request for the frame and its subframes.
+ static void CancelBlockedRequestsForFrameFromUI(
+ RenderFrameHostImpl* root_frame_host);
+
// ResourceDispatcherHost implementation:
void SetDelegate(ResourceDispatcherHostDelegate* delegate) override;
void SetAllowCrossOriginAuthPrompt(bool value) override;
- DownloadInterruptReason BeginDownload(
- scoped_ptr<net::URLRequest> request,
- const Referrer& referrer,
- bool is_content_initiated,
- ResourceContext* context,
- int child_id,
- int render_view_route_id,
- int render_frame_route_id,
- bool prefer_cache,
- bool do_not_prompt_for_login,
- scoped_ptr<DownloadSaveInfo> save_info,
- uint32_t download_id,
- const DownloadStartedCallback& started_callback) override;
void ClearLoginDelegateForRequest(net::URLRequest* request) override;
- void BlockRequestsForRoute(int child_id, int route_id) override;
- void ResumeBlockedRequestsForRoute(int child_id, int route_id) override;
// Puts the resource dispatcher host in an inactive state (unable to begin
// new requests). Cancels all pending requests.
@@ -128,6 +150,16 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
bool OnMessageReceived(const IPC::Message& message,
ResourceMessageFilter* filter);
+ DownloadInterruptReason BeginDownload(
+ std::unique_ptr<net::URLRequest> request,
+ const Referrer& referrer,
+ bool is_content_initiated,
+ ResourceContext* context,
+ int child_id,
+ int render_view_route_id,
+ int render_frame_route_id,
+ bool do_not_prompt_for_login);
+
// Initiates a save file from the browser process (as opposed to a resource
// request from the renderer or another child process).
void BeginSaveFile(const GURL& url,
@@ -142,9 +174,12 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Cancels the given request if it still exists.
void CancelRequest(int child_id, int request_id);
- // Marks the request as "parked". This happens if a request is
- // redirected cross-site and needs to be resumed by a new render view.
- void MarkAsTransferredNavigation(const GlobalRequestID& id);
+ // Marks the request, with its current |response|, as "parked". This
+ // happens if a request is redirected cross-site and needs to be
+ // resumed by a new render view.
+ void MarkAsTransferredNavigation(
+ const GlobalRequestID& id,
+ const scoped_refptr<ResourceResponse>& response);
// Cancels a request previously marked as being transferred, for use when a
// navigation was cancelled.
@@ -179,9 +214,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Called when a RenderViewHost is created.
void OnRenderViewHostCreated(int child_id,
- int route_id,
- bool is_visible,
- bool is_audible);
+ int route_id);
// Called when a RenderViewHost is deleted.
void OnRenderViewHostDeleted(int child_id, int route_id);
@@ -191,17 +224,6 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int route_id,
bool is_loading);
- // Called when a RenderViewHost is hidden.
- void OnRenderViewHostWasHidden(int child_id, int route_id);
-
- // Called when a RenderViewHost is shown.
- void OnRenderViewHostWasShown(int child_id, int route_id);
-
- // Called when an AudioRenderHost starts or stops playing.
- void OnAudioRenderHostStreamStateChanged(int child_id,
- int route_id,
- bool is_playing);
-
// Force cancels any pending requests for the given process.
void CancelRequestsForProcess(int child_id);
@@ -212,8 +234,17 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
void RemovePendingRequest(int child_id, int request_id);
+ // Causes all new requests for the route identified by |routing_id| to be
+ // blocked (not being started) until ResumeBlockedRequestsForRoute is called.
+ void BlockRequestsForRoute(const GlobalFrameRoutingId& global_routing_id);
+
+ // Resumes any blocked request for the specified route id.
+ void ResumeBlockedRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id);
+
// Cancels any blocked request for the specified route id.
- void CancelBlockedRequestsForRoute(int child_id, int route_id);
+ void CancelBlockedRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id);
// Maintains a collection of temp files created in support of
// the download_to_file capability. Used to grant access to the
@@ -239,13 +270,10 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// and associated with the request.
// |id| should be |content::DownloadItem::kInvalidId| to request automatic
// assignment. This is marked virtual so it can be overriden in testing.
- virtual scoped_ptr<ResourceHandler> CreateResourceHandlerForDownload(
+ virtual std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
net::URLRequest* request,
bool is_content_initiated,
- bool must_download,
- uint32_t id,
- scoped_ptr<DownloadSaveInfo> save_info,
- const DownloadUrlParameters::OnStartedCallback& started_cb);
+ bool must_download);
// Called to determine whether the response to |request| should be intercepted
// and handled as a stream. Streams are used to pass direct access to a
@@ -259,7 +287,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// and associated with the request. If |payload| is set to a non-empty value,
// the caller must send it to the old resource handler instead of cancelling
// it.
- virtual scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
+ virtual std::unique_ptr<ResourceHandler> MaybeInterceptAsStream(
const base::FilePath& plugin_path,
net::URLRequest* request,
ResourceResponse* response,
@@ -291,6 +319,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
void EnableStaleWhileRevalidateForTesting();
private:
+ friend class LoaderIOThreadNotifier;
friend class ResourceDispatcherHostTest;
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
@@ -301,6 +330,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
DetachableResourceTimesOut);
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
TestProcessCancelDetachableTimesOut);
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessIgnoreCertErrorsBrowserTest,
+ CrossSiteRedirectCertificateStore);
struct OustandingRequestsStats {
int memory_cost;
@@ -337,12 +368,14 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// A shutdown helper that runs on the IO thread.
void OnShutdown();
+ void OnRenderFrameDeleted(const GlobalFrameRoutingId& global_routing_id);
+
// Helper function for regular and download requests.
- void BeginRequestInternal(scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceHandler> handler);
+ void BeginRequestInternal(std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceHandler> handler);
void StartLoading(ResourceRequestInfoImpl* info,
- const linked_ptr<ResourceLoader>& loader);
+ std::unique_ptr<ResourceLoader> loader);
// We keep track of how much memory each request needs and how many requests
// are issued by each renderer. These are known as OustandingRequestStats.
@@ -379,8 +412,9 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
static int CalculateApproximateMemoryCost(net::URLRequest* request);
// Force cancels any pending requests for the given route id. This method
- // acts like CancelRequestsForProcess when route_id is -1.
- void CancelRequestsForRoute(int child_id, int route_id);
+ // acts like CancelRequestsForProcess when the |route_id| member of
+ // |routing_id| is MSG_ROUTING_NONE.
+ void CancelRequestsForRoute(const GlobalFrameRoutingId& global_routing_id);
// The list of all requests that we have pending. This list is not really
// optimized, and assumes that we have relatively few requests pending at once
@@ -389,7 +423,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// It may be enhanced in the future to provide some kind of prioritization
// mechanism. We should also consider a hashtable or binary tree if it turns
// out we have a lot of things here.
- typedef std::map<GlobalRequestID, linked_ptr<ResourceLoader> > LoaderMap;
+ using LoaderMap = std::map<GlobalRequestID, std::unique_ptr<ResourceLoader>>;
// Deletes the pending request identified by the iterator passed in.
// This function will invalidate the iterator passed in. Callers should
@@ -416,18 +450,18 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Used to marshal calls to LoadStateChanged from the IO to UI threads. All
// are done as a single callback to avoid spamming the UI thread.
- static void UpdateLoadInfoOnUIThread(scoped_ptr<LoadInfoMap> info_map);
+ static void UpdateLoadInfoOnUIThread(std::unique_ptr<LoadInfoMap> info_map);
// Gets the most interesting LoadInfo for each GlobalRoutingID.
- scoped_ptr<LoadInfoMap> GetLoadInfoForAllRoutes();
+ std::unique_ptr<LoadInfoMap> GetLoadInfoForAllRoutes();
// Checks all pending requests and updates the load info if necessary.
void UpdateLoadInfo();
// Resumes or cancels (if |cancel_requests| is true) any blocked requests.
- void ProcessBlockedRequestsForRoute(int child_id,
- int route_id,
- bool cancel_requests);
+ void ProcessBlockedRequestsForRoute(
+ const GlobalFrameRoutingId& global_routing_id,
+ bool cancel_requests);
void OnRequestResource(int routing_id,
int request_id,
@@ -436,13 +470,15 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
const ResourceHostMsg_Request& request_data,
IPC::Message* sync_result);
+ bool IsRequestIDInUse(const GlobalRequestID& id) const;
+
// Update the ResourceRequestInfo and internal maps when a request is
// transferred from one process to another.
void UpdateRequestForTransfer(int child_id,
int route_id,
int request_id,
const ResourceHostMsg_Request& request_data,
- const linked_ptr<ResourceLoader>& loader);
+ LoaderMap::iterator iter);
void BeginRequest(int request_id,
const ResourceHostMsg_Request& request_data,
@@ -451,7 +487,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Creates a ResourceHandler to be used by BeginRequest() for normal resource
// loading.
- scoped_ptr<ResourceHandler> CreateResourceHandler(
+ std::unique_ptr<ResourceHandler> CreateResourceHandler(
net::URLRequest* request,
const ResourceHostMsg_Request& request_data,
IPC::Message* sync_result,
@@ -463,14 +499,14 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Wraps |handler| in the standard resource handlers for normal resource
// loading and navigation requests. This adds MimeTypeResourceHandler and
// ResourceThrottles.
- scoped_ptr<ResourceHandler> AddStandardHandlers(
+ std::unique_ptr<ResourceHandler> AddStandardHandlers(
net::URLRequest* request,
ResourceType resource_type,
ResourceContext* resource_context,
AppCacheService* appcache_service,
int child_id,
int route_id,
- scoped_ptr<ResourceHandler> handler);
+ std::unique_ptr<ResourceHandler> handler);
void OnDataDownloadedACK(int request_id);
void OnCancelRequest(int request_id);
@@ -521,6 +557,16 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int child_id,
bool is_sync_load);
+ // The certificate on a ResourceResponse is associated with a
+ // particular renderer process. As a transfer to a new process
+ // completes, the stored certificate has to be updated to reflect the
+ // new renderer process.
+ void UpdateResponseCertificateForTransfer(ResourceResponse* response,
+ const net::SSLInfo& ssl_info,
+ int child_id);
+
+ CertStore* GetCertStore();
+
LoaderMap pending_loaders_;
// Collection of temp files downloaded for child processes via
@@ -534,7 +580,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// A timer that periodically calls UpdateLoadInfo while pending_loaders_ is
// not empty and at least one RenderViewHost is loading.
- scoped_ptr<base::RepeatingTimer> update_load_states_timer_;
+ std::unique_ptr<base::RepeatingTimer> update_load_states_timer_;
// We own the save file manager.
scoped_refptr<SaveFileManager> save_file_manager_;
@@ -551,8 +597,9 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// True if the resource dispatcher host has been shut down.
bool is_shutdown_;
- typedef std::vector<linked_ptr<ResourceLoader> > BlockedLoadersList;
- typedef std::map<GlobalRoutingID, BlockedLoadersList*> BlockedLoadersMap;
+ using BlockedLoadersList = std::vector<std::unique_ptr<ResourceLoader>>;
+ using BlockedLoadersMap =
+ std::map<GlobalFrameRoutingId, std::unique_ptr<BlockedLoadersList>>;
BlockedLoadersMap blocked_loaders_map_;
// Maps the child_ids to the approximate number of bytes
@@ -600,7 +647,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// AsyncRevalidationManager is non-NULL if and only if
// stale-while-revalidate is enabled.
- scoped_ptr<AsyncRevalidationManager> async_revalidation_manager_;
+ std::unique_ptr<AsyncRevalidationManager> async_revalidation_manager_;
// http://crbug.com/90971 - Assists in tracking down use-after-frees on
// shutdown.
@@ -610,7 +657,11 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
base::ObserverList<ResourceMessageDelegate>*> DelegateMap;
DelegateMap delegate_map_;
- scoped_ptr<ResourceScheduler> scheduler_;
+ std::unique_ptr<ResourceScheduler> scheduler_;
+
+ // Allows tests to use a mock CertStore. If set, the CertStore must
+ // outlive this ResourceDispatcherHostImpl.
+ CertStore* cert_store_for_testing_;
DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHostImpl);
};
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
index 7fbe3995c21..606da908983 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
@@ -20,6 +21,7 @@
#include "base/strings/string_split.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/cert_store_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
@@ -30,6 +32,7 @@
#include "content/common/appcache_interfaces.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/resource_messages.h"
+#include "content/common/ssl_status_serialization.h"
#include "content/common/view_messages.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/render_process_host.h"
@@ -41,6 +44,7 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/child_process_host.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/process_type.h"
#include "content/public/common/resource_response.h"
#include "content/public/test/test_browser_context.h"
@@ -50,8 +54,10 @@
#include "net/base/elements_upload_data_stream.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
+#include "net/base/test_data_directory.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/http/http_util.h"
+#include "net/test/cert_test_util.h"
#include "net/test/url_request/url_request_failed_job.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -86,9 +92,8 @@ void GetResponseHead(const std::vector<IPC::Message>& messages,
ASSERT_TRUE(IPC::ReadParam(&messages[0], &iter, response_head));
}
-void GenerateIPCMessage(
- scoped_refptr<ResourceMessageFilter> filter,
- scoped_ptr<IPC::Message> message) {
+void GenerateIPCMessage(scoped_refptr<ResourceMessageFilter> filter,
+ std::unique_ptr<IPC::Message> message) {
ResourceDispatcherHostImpl::Get()->OnMessageReceived(
*message, filter.get());
}
@@ -126,6 +131,7 @@ static int RequestIDForMessage(const IPC::Message& msg) {
case ResourceMsg_ReceivedRedirect::ID:
case ResourceMsg_SetDataBuffer::ID:
case ResourceMsg_DataReceived::ID:
+ case ResourceMsg_InlinedDataChunkReceived::ID:
case ResourceMsg_DataDownloaded::ID:
case ResourceMsg_RequestComplete::ID: {
bool result = base::PickleIterator(msg).ReadInt(&request_id);
@@ -760,7 +766,7 @@ class TestResourceDispatcherHostDelegate
bool create_two_throttles_;
int flags_;
int error_code_for_cancellation_;
- scoped_ptr<base::SupportsUserData::Data> user_data_;
+ std::unique_ptr<base::SupportsUserData::Data> user_data_;
};
// Waits for a ShareableFileReference to be released.
@@ -828,7 +834,38 @@ struct LoadInfoTestRequestInfo {
net::UploadProgress upload_progress;
};
-class ResourceDispatcherHostTest : public testing::Test,
+enum class TestConfig {
+ kDefault,
+ kOptimizeIPCForSmallResourceEnabled,
+};
+
+// A mock CertStore that doesn't do anything, unless a default cert id
+// is specified with set_default_cert_id(). If a default cert id is
+// provided, then StoreCert() always returns that cert id.
+class MockCertStore : public content::CertStore {
+ public:
+ MockCertStore() : default_cert_id_(0) {}
+
+ ~MockCertStore() override {}
+
+ int StoreCert(net::X509Certificate* cert, int process_id) override {
+ return default_cert_id_;
+ }
+
+ bool RetrieveCert(int process_id,
+ scoped_refptr<net::X509Certificate>* cert) override {
+ return false;
+ }
+
+ void set_default_cert_id(int default_cert_id) {
+ default_cert_id_ = default_cert_id;
+ }
+
+ private:
+ int default_cert_id_;
+};
+
+class ResourceDispatcherHostTest : public testing::TestWithParam<TestConfig>,
public IPC::Sender {
public:
typedef ResourceDispatcherHostImpl::LoadInfo LoadInfo;
@@ -836,6 +873,7 @@ class ResourceDispatcherHostTest : public testing::Test,
ResourceDispatcherHostTest()
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+ use_test_ssl_certificate_(false),
old_factory_(NULL),
send_data_received_acks_(false) {
browser_context_.reset(new TestBrowserContext());
@@ -848,6 +886,7 @@ class ResourceDispatcherHostTest : public testing::Test,
job_factory_.reset(new TestURLRequestJobFactory(this));
request_context->set_job_factory(job_factory_.get());
request_context->set_network_delegate(&network_delegate_);
+ host_.cert_store_for_testing_ = &mock_cert_store_;
}
// IPC::Sender implementation
@@ -869,8 +908,9 @@ class ResourceDispatcherHostTest : public testing::Test,
return true;
}
- scoped_ptr<LoadInfoMap> RunLoadInfoTest(LoadInfoTestRequestInfo* request_info,
- size_t num_requests) {
+ std::unique_ptr<LoadInfoMap> RunLoadInfoTest(
+ LoadInfoTestRequestInfo* request_info,
+ size_t num_requests) {
for (size_t i = 0; i < num_requests; ++i) {
loader_test_request_info_.reset(
new LoadInfoTestRequestInfo(request_info[i]));
@@ -899,6 +939,22 @@ class ResourceDispatcherHostTest : public testing::Test,
browser_context_->GetResourceContext(),
web_contents_->GetRenderProcessHost()->GetID());
child_ids_.insert(web_contents_->GetRenderProcessHost()->GetID());
+
+ base::FeatureList::ClearInstanceForTesting();
+ switch (GetParam()) {
+ case TestConfig::kDefault:
+ base::FeatureList::InitializeInstance(std::string(), std::string());
+ break;
+ case TestConfig::kOptimizeIPCForSmallResourceEnabled: {
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->InitializeFromCommandLine(
+ features::kOptimizeIPCForSmallResource.name, std::string());
+ base::FeatureList::SetInstance(std::move(feature_list));
+ ASSERT_TRUE(base::FeatureList::IsEnabled(
+ features::kOptimizeIPCForSmallResource));
+ break;
+ }
+ }
}
void TearDown() override {
@@ -941,6 +997,12 @@ class ResourceDispatcherHostTest : public testing::Test,
int request_id,
const GURL& url);
+ void MakeTestRequestWithRenderFrame(int render_view_id,
+ int render_frame_id,
+ int request_id,
+ const GURL& url,
+ ResourceType type);
+
// Generates a request using the given filter and resource type.
void MakeTestRequestWithResourceType(ResourceMessageFilter* filter,
int render_view_id,
@@ -958,6 +1020,11 @@ class ResourceDispatcherHostTest : public testing::Test,
int request_id,
net::RequestPriority priority);
+ void MakeTestRequestWithPriorityAndRenderFrame(int render_view_id,
+ int render_frame_id,
+ int request_id,
+ net::RequestPriority priority);
+
void MakeWebContentsAssociatedDownloadRequest(int request_id,
const GURL& url);
@@ -991,6 +1058,11 @@ class ResourceDispatcherHostTest : public testing::Test,
SetResponse(headers, std::string());
}
+ // If called, requests called from now on will be created as
+ // TestHTTPSURLRequestJobs: that is, a test certificate will be set on
+ // the |ssl_info| field of the response.
+ void SetTestSSLCertificate() { use_test_ssl_certificate_ = true; }
+
void SendDataReceivedACKs(bool send_acks) {
send_data_received_acks_ = send_acks;
}
@@ -1007,7 +1079,7 @@ class ResourceDispatcherHostTest : public testing::Test,
int request_id = -1;
bool result = base::PickleIterator(msg).ReadInt(&request_id);
DCHECK(result);
- scoped_ptr<IPC::Message> ack(
+ std::unique_ptr<IPC::Message> ack(
new ResourceHostMsg_DataReceived_ACK(request_id));
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1030,14 +1102,18 @@ class ResourceDispatcherHostTest : public testing::Test,
wait_for_request_complete_loop_.reset();
}
- scoped_ptr<LoadInfoTestRequestInfo> loader_test_request_info_;
- scoped_ptr<base::RunLoop> wait_for_request_create_loop_;
+ void DeleteRenderFrame(const GlobalFrameRoutingId& global_routing_id) {
+ host_.OnRenderFrameDeleted(global_routing_id);
+ }
+
+ std::unique_ptr<LoadInfoTestRequestInfo> loader_test_request_info_;
+ std::unique_ptr<base::RunLoop> wait_for_request_create_loop_;
content::TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<TestBrowserContext> browser_context_;
- scoped_ptr<TestURLRequestJobFactory> job_factory_;
- scoped_ptr<WebContents> web_contents_;
- scoped_ptr<TestWebContentsObserver> web_contents_observer_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
+ std::unique_ptr<TestURLRequestJobFactory> job_factory_;
+ std::unique_ptr<WebContents> web_contents_;
+ std::unique_ptr<TestWebContentsObserver> web_contents_observer_;
scoped_refptr<ForwardingFilter> filter_;
scoped_refptr<TestFilterSpecifyingChild> web_contents_filter_;
net::TestNetworkDelegate network_delegate_;
@@ -1045,12 +1121,14 @@ class ResourceDispatcherHostTest : public testing::Test,
ResourceIPCAccumulator accum_;
std::string response_headers_;
std::string response_data_;
+ bool use_test_ssl_certificate_;
std::string scheme_;
net::URLRequest::ProtocolFactory* old_factory_;
bool send_data_received_acks_;
std::set<int> child_ids_;
- scoped_ptr<base::RunLoop> wait_for_request_complete_loop_;
+ std::unique_ptr<base::RunLoop> wait_for_request_complete_loop_;
RenderViewHostTestEnabler render_view_host_test_enabler_;
+ MockCertStore mock_cert_store_;
};
void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
@@ -1060,6 +1138,19 @@ void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
url, RESOURCE_TYPE_SUB_RESOURCE);
}
+void ResourceDispatcherHostTest::MakeTestRequestWithRenderFrame(
+ int render_view_id,
+ int render_frame_id,
+ int request_id,
+ const GURL& url,
+ ResourceType type) {
+ ResourceHostMsg_Request request = CreateResourceRequest("GET", type, url);
+ request.render_frame_id = render_frame_id;
+ ResourceHostMsg_RequestResource msg(render_view_id, request_id, request);
+ host_.OnMessageReceived(msg, filter_.get());
+ KickOffRequest();
+}
+
void ResourceDispatcherHostTest::MakeTestRequestWithResourceType(
ResourceMessageFilter* filter,
int render_view_id,
@@ -1097,8 +1188,18 @@ void ResourceDispatcherHostTest::MakeTestRequestWithPriority(
int render_view_id,
int request_id,
net::RequestPriority priority) {
+ MakeTestRequestWithPriorityAndRenderFrame(render_view_id, -1, request_id,
+ priority);
+}
+
+void ResourceDispatcherHostTest::MakeTestRequestWithPriorityAndRenderFrame(
+ int render_view_id,
+ int render_frame_id,
+ int request_id,
+ net::RequestPriority priority) {
ResourceHostMsg_Request request = CreateResourceRequest(
"GET", RESOURCE_TYPE_SUB_RESOURCE, GURL("http://example.com/priority"));
+ request.render_frame_id = render_frame_id;
request.priority = priority;
ResourceHostMsg_RequestResource msg(render_view_id, request_id, request);
host_.OnMessageReceived(msg, filter_.get());
@@ -1107,20 +1208,16 @@ void ResourceDispatcherHostTest::MakeTestRequestWithPriority(
void ResourceDispatcherHostTest::MakeWebContentsAssociatedDownloadRequest(
int request_id,
const GURL& url) {
- scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
- save_info->prompt_for_save_location = false;
net::URLRequestContext* request_context =
browser_context_->GetResourceContext()->GetRequestContext();
- scoped_ptr<net::URLRequest> request(
+ std::unique_ptr<net::URLRequest> request(
request_context->CreateRequest(url, net::DEFAULT_PRIORITY, NULL));
host_.BeginDownload(std::move(request), Referrer(),
false, // is_content_initiated
browser_context_->GetResourceContext(),
web_contents_->GetRenderProcessHost()->GetID(),
web_contents_->GetRoutingID(),
- web_contents_->GetMainFrame()->GetRoutingID(), false,
- false, std::move(save_info), DownloadItem::kInvalidId,
- ResourceDispatcherHostImpl::DownloadStartedCallback());
+ web_contents_->GetMainFrame()->GetRoutingID(), false);
}
void ResourceDispatcherHostTest::CancelRequest(int request_id) {
@@ -1155,6 +1252,22 @@ void CheckRequestCompleteErrorCode(const IPC::Message& message,
ASSERT_EQ(expected_error_code, error_code);
}
+testing::AssertionResult ExtractInlinedChunkData(
+ const IPC::Message& message,
+ std::string* leading_chunk_data) {
+ base::PickleIterator iter(message);
+ int request_id;
+ if (!IPC::ReadParam(&message, &iter, &request_id))
+ return testing::AssertionFailure() << "Could not read request_id";
+
+ std::vector<char> data;
+ if (!IPC::ReadParam(&message, &iter, &data))
+ return testing::AssertionFailure() << "Could not read data";
+ leading_chunk_data->assign(data.begin(), data.end());
+
+ return testing::AssertionSuccess();
+}
+
testing::AssertionResult ExtractDataOffsetAndLength(const IPC::Message& message,
int* data_offset,
int* data_length) {
@@ -1169,10 +1282,39 @@ testing::AssertionResult ExtractDataOffsetAndLength(const IPC::Message& message,
return testing::AssertionSuccess();
}
+void CheckSuccessfulRequestWithErrorCodeForInlinedCase(
+ const std::vector<IPC::Message>& messages,
+ const std::string& reference_data,
+ int expected_error) {
+ // A successful request on the inlined case will have received 3 messages:
+ // ReceivedResponse (indicates headers received)
+ // InlinedDataChunkReceived (contains the content)
+ // RequestComplete (request is done)
+
+ ASSERT_EQ(3U, messages.size());
+
+ // The first messages should be received response
+ ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type());
+ ASSERT_EQ(ResourceMsg_InlinedDataChunkReceived::ID, messages[1].type());
+
+ std::string leading_chunk_data;
+ ASSERT_TRUE(ExtractInlinedChunkData(messages[1], &leading_chunk_data));
+ ASSERT_EQ(reference_data, leading_chunk_data);
+ CheckRequestCompleteErrorCode(messages[2], expected_error);
+}
+
void CheckSuccessfulRequestWithErrorCode(
const std::vector<IPC::Message>& messages,
const std::string& reference_data,
int expected_error) {
+ ASSERT_LT(2U, messages.size());
+ if (base::FeatureList::IsEnabled(features::kOptimizeIPCForSmallResource) &&
+ messages[1].type() == ResourceMsg_InlinedDataChunkReceived::ID) {
+ CheckSuccessfulRequestWithErrorCodeForInlinedCase(
+ messages, reference_data, expected_error);
+ return;
+ }
+
// A successful request will have received 4 messages:
// ReceivedResponse (indicates headers received)
// SetDataBuffer (contains shared memory handle)
@@ -1248,7 +1390,7 @@ void CheckFailedRequest(const std::vector<IPC::Message>& messages,
}
// Tests whether many messages get dispatched properly.
-TEST_F(ResourceDispatcherHostTest, TestMany) {
+TEST_P(ResourceDispatcherHostTest, TestMany) {
MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
@@ -1281,7 +1423,7 @@ TEST_F(ResourceDispatcherHostTest, TestMany) {
// Tests whether messages get canceled properly. We issue four requests,
// cancel two of them, and make sure that each sent the proper notifications.
-TEST_F(ResourceDispatcherHostTest, Cancel) {
+TEST_P(ResourceDispatcherHostTest, Cancel) {
MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
@@ -1336,7 +1478,7 @@ TEST_F(ResourceDispatcherHostTest, Cancel) {
// Shows that detachable requests will timeout if the request takes too long to
// complete.
-TEST_F(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
+TEST_P(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_2(),
RESOURCE_TYPE_PREFETCH); // detachable type
@@ -1378,7 +1520,7 @@ TEST_F(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
// If the filter has disappeared then detachable resources should continue to
// load.
-TEST_F(ResourceDispatcherHostTest, DeletedFilterDetached) {
+TEST_P(ResourceDispatcherHostTest, DeletedFilterDetached) {
// test_url_1's data is available synchronously, so use 2 and 3.
ResourceHostMsg_Request request_prefetch = CreateResourceRequest(
"GET", RESOURCE_TYPE_PREFETCH, net::URLRequestTestJob::test_url_2());
@@ -1430,7 +1572,7 @@ TEST_F(ResourceDispatcherHostTest, DeletedFilterDetached) {
// If the filter has disappeared (original process dies) then detachable
// resources should continue to load, even when redirected.
-TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachedRedirect) {
+TEST_P(ResourceDispatcherHostTest, DeletedFilterDetachedRedirect) {
ResourceHostMsg_Request request = CreateResourceRequest(
"GET", RESOURCE_TYPE_PREFETCH,
net::URLRequestTestJob::test_url_redirect_to_url_2());
@@ -1477,7 +1619,7 @@ TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachedRedirect) {
EXPECT_EQ(0, network_delegate()->error_count());
}
-TEST_F(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) {
+TEST_P(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) {
bool was_deleted = false;
// Arrange to have requests deferred before starting.
@@ -1501,7 +1643,7 @@ TEST_F(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) {
EXPECT_TRUE(was_deleted);
}
-TEST_F(ResourceDispatcherHostTest, DetachWhileStartIsDeferred) {
+TEST_P(ResourceDispatcherHostTest, DetachWhileStartIsDeferred) {
bool was_deleted = false;
// Arrange to have requests deferred before starting.
@@ -1543,7 +1685,7 @@ TEST_F(ResourceDispatcherHostTest, DetachWhileStartIsDeferred) {
// Tests if cancel is called in ResourceThrottle::WillStartRequest, then the
// URLRequest will not be started.
-TEST_F(ResourceDispatcherHostTest, CancelInResourceThrottleWillStartRequest) {
+TEST_P(ResourceDispatcherHostTest, CancelInResourceThrottleWillStartRequest) {
TestResourceDispatcherHostDelegate delegate;
delegate.set_flags(CANCEL_BEFORE_START);
host_.SetDelegate(&delegate);
@@ -1565,7 +1707,7 @@ TEST_F(ResourceDispatcherHostTest, CancelInResourceThrottleWillStartRequest) {
EXPECT_EQ(0, job_factory_->url_request_jobs_created_count());
}
-TEST_F(ResourceDispatcherHostTest, PausedStartError) {
+TEST_P(ResourceDispatcherHostTest, PausedStartError) {
// Arrange to have requests deferred before processing response headers.
TestResourceDispatcherHostDelegate delegate;
delegate.set_flags(DEFER_PROCESSING_RESPONSE);
@@ -1583,7 +1725,7 @@ TEST_F(ResourceDispatcherHostTest, PausedStartError) {
}
// Test the WillStartUsingNetwork throttle.
-TEST_F(ResourceDispatcherHostTest, ThrottleNetworkStart) {
+TEST_P(ResourceDispatcherHostTest, ThrottleNetworkStart) {
// Arrange to have requests deferred before processing response headers.
TestResourceDispatcherHostDelegate delegate;
delegate.set_flags(DEFER_NETWORK_START);
@@ -1609,7 +1751,7 @@ TEST_F(ResourceDispatcherHostTest, ThrottleNetworkStart) {
EXPECT_EQ(0, host_.pending_requests());
}
-TEST_F(ResourceDispatcherHostTest, ThrottleAndResumeTwice) {
+TEST_P(ResourceDispatcherHostTest, ThrottleAndResumeTwice) {
// Arrange to have requests deferred before starting.
TestResourceDispatcherHostDelegate delegate;
delegate.set_flags(DEFER_STARTING_REQUEST);
@@ -1647,7 +1789,7 @@ TEST_F(ResourceDispatcherHostTest, ThrottleAndResumeTwice) {
// Tests that the delegate can cancel a request and provide a error code.
-TEST_F(ResourceDispatcherHostTest, CancelInDelegate) {
+TEST_P(ResourceDispatcherHostTest, CancelInDelegate) {
TestResourceDispatcherHostDelegate delegate;
delegate.set_flags(CANCEL_BEFORE_START);
delegate.set_error_code_for_cancellation(net::ERR_ACCESS_DENIED);
@@ -1671,7 +1813,7 @@ TEST_F(ResourceDispatcherHostTest, CancelInDelegate) {
}
// Tests CancelRequestsForProcess
-TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
+TEST_P(ResourceDispatcherHostTest, TestProcessCancel) {
scoped_refptr<TestFilter> test_filter = new TestFilter(
browser_context_->GetResourceContext());
child_ids_.insert(test_filter->child_id());
@@ -1748,7 +1890,7 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
// Tests whether the correct requests get canceled when a RenderViewHost is
// deleted.
-TEST_F(ResourceDispatcherHostTest, CancelRequestsOnRenderViewHostDeleted) {
+TEST_P(ResourceDispatcherHostTest, CancelRequestsOnRenderFrameDeleted) {
// Requests all hang once started. This prevents requests from being
// destroyed due to completion.
job_factory_->SetHangAfterStartJobGeneration(true);
@@ -1756,33 +1898,36 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsOnRenderViewHostDeleted) {
TestResourceDispatcherHostDelegate delegate;
host_.SetDelegate(&delegate);
- host_.OnRenderViewHostCreated(filter_->child_id(), 0, true, false);
+ host_.OnRenderViewHostCreated(filter_->child_id(), 0);
// One RenderView issues a high priority request and a low priority one. Both
// should be started.
- MakeTestRequestWithPriority(0, 1, net::HIGHEST);
- MakeTestRequestWithPriority(0, 2, net::LOWEST);
+ MakeTestRequestWithPriorityAndRenderFrame(0, 10, 1, net::HIGHEST);
+ MakeTestRequestWithPriorityAndRenderFrame(0, 11, 2, net::LOWEST);
KickOffRequest();
EXPECT_EQ(2, network_delegate_.created_requests());
EXPECT_EQ(0, network_delegate_.canceled_requests());
// The same RenderView issues two more low priority requests. The
// ResourceScheduler shouldn't let them start immediately.
- MakeTestRequestWithPriority(0, 3, net::LOWEST);
- MakeTestRequestWithPriority(0, 4, net::LOWEST);
+ MakeTestRequestWithPriorityAndRenderFrame(0, 10, 3, net::LOWEST);
+ MakeTestRequestWithPriorityAndRenderFrame(0, 11, 4, net::LOWEST);
KickOffRequest();
EXPECT_EQ(2, network_delegate_.created_requests());
EXPECT_EQ(0, network_delegate_.canceled_requests());
// Another RenderView in the same process as the old one issues a request,
// which is then started.
- MakeTestRequestWithPriority(1, 5, net::LOWEST);
+ MakeTestRequestWithPriorityAndRenderFrame(1, 12, 5, net::LOWEST);
KickOffRequest();
EXPECT_EQ(3, network_delegate_.created_requests());
EXPECT_EQ(0, network_delegate_.canceled_requests());
- // The first RenderView is destroyed. All 4 of its requests should be
- // cancelled, and none of the two deferred requests should be started.
+ // The first two RenderFrameHosts are destroyed. All 4 of their requests
+ // should be cancelled, and none of the two deferred requests should be
+ // started.
+ DeleteRenderFrame(GlobalFrameRoutingId(filter_->child_id(), 10));
+ DeleteRenderFrame(GlobalFrameRoutingId(filter_->child_id(), 11));
host_.OnRenderViewHostDeleted(filter_->child_id(), 0);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, network_delegate_.created_requests());
@@ -1795,7 +1940,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsOnRenderViewHostDeleted) {
EXPECT_EQ(0U, msgs.size());
}
-TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachedTimesOut) {
+TEST_P(ResourceDispatcherHostTest, TestProcessCancelDetachedTimesOut) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_4(),
RESOURCE_TYPE_PREFETCH); // detachable type
@@ -1841,17 +1986,23 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachedTimesOut) {
}
// Tests blocking and resuming requests.
-TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
- host_.BlockRequestsForRoute(filter_->child_id(), 1);
- host_.BlockRequestsForRoute(filter_->child_id(), 2);
- host_.BlockRequestsForRoute(filter_->child_id(), 3);
-
- MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
- MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2());
- MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
- MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1());
- MakeTestRequest(2, 5, net::URLRequestTestJob::test_url_2());
- MakeTestRequest(3, 6, net::URLRequestTestJob::test_url_3());
+TEST_P(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 11));
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 12));
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 13));
+
+ MakeTestRequestWithRenderFrame(0, 10, 1, net::URLRequestTestJob::test_url_1(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(1, 11, 2, net::URLRequestTestJob::test_url_2(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(0, 10, 3, net::URLRequestTestJob::test_url_3(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(1, 11, 4, net::URLRequestTestJob::test_url_1(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(2, 12, 5, net::URLRequestTestJob::test_url_2(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(3, 13, 6, net::URLRequestTestJob::test_url_3(),
+ RESOURCE_TYPE_SUB_RESOURCE);
// Flush all the pending requests
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1860,14 +2011,15 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
ResourceIPCAccumulator::ClassifiedMessages msgs;
accum_.GetClassifiedMessages(&msgs);
- // All requests but the 2 for the RVH 0 should have been blocked.
+ // All requests but the 2 for the RFH 0 should have been blocked.
ASSERT_EQ(2U, msgs.size());
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3());
- // Resume requests for RVH 1 and flush pending requests.
- host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 1);
+ // Resume requests for RFH 11 and flush pending requests.
+ host_.ResumeBlockedRequestsForRoute(
+ GlobalFrameRoutingId(filter_->child_id(), 11));
KickOffRequest();
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1877,17 +2029,20 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2());
CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_1());
- // Test that new requests are not blocked for RVH 1.
- MakeTestRequest(1, 7, net::URLRequestTestJob::test_url_1());
+ // Test that new requests are not blocked for RFH 11.
+ MakeTestRequestWithRenderFrame(1, 11, 7, net::URLRequestTestJob::test_url_1(),
+ RESOURCE_TYPE_SUB_RESOURCE);
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
msgs.clear();
accum_.GetClassifiedMessages(&msgs);
ASSERT_EQ(1U, msgs.size());
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
- // Now resumes requests for all RVH (2 and 3).
- host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 2);
- host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 3);
+ // Now resumes requests for all RFH (12 and 13).
+ host_.ResumeBlockedRequestsForRoute(
+ GlobalFrameRoutingId(filter_->child_id(), 12));
+ host_.ResumeBlockedRequestsForRoute(
+ GlobalFrameRoutingId(filter_->child_id(), 13));
KickOffRequest();
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1899,17 +2054,21 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
}
// Tests blocking and canceling requests.
-TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
- host_.BlockRequestsForRoute(filter_->child_id(), 1);
-
- MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1());
- MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2());
- MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
- MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1());
+TEST_P(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 11));
+
+ MakeTestRequestWithRenderFrame(0, 10, 1, net::URLRequestTestJob::test_url_1(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(1, 11, 2, net::URLRequestTestJob::test_url_2(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(0, 10, 3, net::URLRequestTestJob::test_url_3(),
+ RESOURCE_TYPE_SUB_RESOURCE);
+ MakeTestRequestWithRenderFrame(1, 11, 4, net::URLRequestTestJob::test_url_1(),
+ RESOURCE_TYPE_SUB_RESOURCE);
// Blocked detachable resources should not delay cancellation.
- MakeTestRequestWithResourceType(filter_.get(), 1, 5,
- net::URLRequestTestJob::test_url_4(),
- RESOURCE_TYPE_PREFETCH); // detachable type
+ //
+ MakeTestRequestWithRenderFrame(1, 11, 5, net::URLRequestTestJob::test_url_4(),
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Flush all the pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1918,14 +2077,15 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
ResourceIPCAccumulator::ClassifiedMessages msgs;
accum_.GetClassifiedMessages(&msgs);
- // The 2 requests for the RVH 0 should have been processed.
+ // The 2 requests for the RFH 10 should have been processed.
ASSERT_EQ(2U, msgs.size());
CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1());
CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3());
- // Cancel requests for RVH 1.
- host_.CancelBlockedRequestsForRoute(filter_->child_id(), 1);
+ // Cancel requests for RFH 11.
+ host_.CancelBlockedRequestsForRoute(
+ GlobalFrameRoutingId(filter_->child_id(), 11));
KickOffRequest();
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1935,11 +2095,12 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
}
// Tests that blocked requests are canceled if their associated process dies.
-TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
+TEST_P(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
- host_.BlockRequestsForRoute(second_filter->child_id(), 0);
+ host_.BlockRequestsForRoute(
+ GlobalFrameRoutingId(second_filter->child_id(), 0));
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
@@ -1981,13 +2142,14 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
// away. Note that we rely on Purify for finding the leaks if any.
// If this test turns the Purify bot red, check the ResourceDispatcherHost
// destructor to make sure the blocked requests are deleted.
-TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
+TEST_P(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
// This second filter is used to emulate a second process.
scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
- host_.BlockRequestsForRoute(filter_->child_id(), 1);
- host_.BlockRequestsForRoute(filter_->child_id(), 2);
- host_.BlockRequestsForRoute(second_filter->child_id(), 1);
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 1));
+ host_.BlockRequestsForRoute(GlobalFrameRoutingId(filter_->child_id(), 2));
+ host_.BlockRequestsForRoute(
+ GlobalFrameRoutingId(second_filter->child_id(), 1));
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
@@ -2022,9 +2184,9 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
}
// Test the private helper method "CalculateApproximateMemoryCost()".
-TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
+TEST_P(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
net::URLRequestContext context;
- scoped_ptr<net::URLRequest> req(context.CreateRequest(
+ std::unique_ptr<net::URLRequest> req(context.CreateRequest(
GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL));
EXPECT_EQ(
4427,
@@ -2040,8 +2202,9 @@ TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
std::string upload_content;
upload_content.resize(33);
std::fill(upload_content.begin(), upload_content.end(), 'x');
- scoped_ptr<net::UploadElementReader> reader(new net::UploadBytesElementReader(
- upload_content.data(), upload_content.size()));
+ std::unique_ptr<net::UploadElementReader> reader(
+ new net::UploadBytesElementReader(upload_content.data(),
+ upload_content.size()));
req->set_upload(
net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
@@ -2053,7 +2216,7 @@ TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
// Test that too much memory for outstanding requests for a particular
// render_process_host_id causes requests to fail.
-TEST_F(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) {
+TEST_P(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) {
// Expected cost of each request as measured by
// ResourceDispatcherHost::CalculateApproximateMemoryCost().
int kMemoryCostOfTest2Req =
@@ -2130,7 +2293,7 @@ TEST_F(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) {
// Test that when too many requests are outstanding for a particular
// render_process_host_id, any subsequent request from it fails. Also verify
// that the global limit is honored.
-TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
+TEST_P(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
// Tighten the bound on the ResourceDispatcherHost, to speed things up.
const size_t kMaxRequestsPerProcess = 2;
host_.set_max_num_in_flight_requests_per_process(kMaxRequestsPerProcess);
@@ -2193,7 +2356,7 @@ TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
}
// Tests that we sniff the mime type for a simple request.
-TEST_F(ResourceDispatcherHostTest, MimeSniffed) {
+TEST_P(ResourceDispatcherHostTest, MimeSniffed) {
std::string raw_headers("HTTP/1.1 200 OK\n\n");
std::string response_data("<html><title>Test One</title></html>");
SetResponse(raw_headers, response_data);
@@ -2215,7 +2378,7 @@ TEST_F(ResourceDispatcherHostTest, MimeSniffed) {
}
// Tests that we don't sniff the mime type when the server provides one.
-TEST_F(ResourceDispatcherHostTest, MimeNotSniffed) {
+TEST_P(ResourceDispatcherHostTest, MimeNotSniffed) {
std::string raw_headers("HTTP/1.1 200 OK\n"
"Content-type: image/jpeg\n\n");
std::string response_data("<html><title>Test One</title></html>");
@@ -2238,7 +2401,7 @@ TEST_F(ResourceDispatcherHostTest, MimeNotSniffed) {
}
// Tests that we don't sniff the mime type when there is no message body.
-TEST_F(ResourceDispatcherHostTest, MimeNotSniffed2) {
+TEST_P(ResourceDispatcherHostTest, MimeNotSniffed2) {
SetResponse("HTTP/1.1 304 Not Modified\n\n");
HandleScheme("http");
@@ -2257,7 +2420,7 @@ TEST_F(ResourceDispatcherHostTest, MimeNotSniffed2) {
ASSERT_EQ("", response_head.mime_type);
}
-TEST_F(ResourceDispatcherHostTest, MimeSniff204) {
+TEST_P(ResourceDispatcherHostTest, MimeSniff204) {
SetResponse("HTTP/1.1 204 No Content\n\n");
HandleScheme("http");
@@ -2276,7 +2439,7 @@ TEST_F(ResourceDispatcherHostTest, MimeSniff204) {
ASSERT_EQ("text/plain", response_head.mime_type);
}
-TEST_F(ResourceDispatcherHostTest, MimeSniffEmpty) {
+TEST_P(ResourceDispatcherHostTest, MimeSniffEmpty) {
SetResponse("HTTP/1.1 200 OK\n\n");
HandleScheme("http");
@@ -2296,7 +2459,7 @@ TEST_F(ResourceDispatcherHostTest, MimeSniffEmpty) {
}
// Tests for crbug.com/31266 (Non-2xx + application/octet-stream).
-TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) {
+TEST_P(ResourceDispatcherHostTest, ForbiddenDownload) {
std::string raw_headers("HTTP/1.1 403 Forbidden\n"
"Content-disposition: attachment; filename=blah\n"
"Content-type: application/octet-stream\n\n");
@@ -2330,7 +2493,7 @@ TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) {
// Test for http://crbug.com/76202 . We don't want to destroy a
// download request prematurely when processing a cancellation from
// the renderer.
-TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) {
+TEST_P(ResourceDispatcherHostTest, IgnoreCancelForDownloads) {
EXPECT_EQ(0, host_.pending_requests());
int render_view_id = 0;
@@ -2370,7 +2533,7 @@ TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) {
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
}
-TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) {
+TEST_P(ResourceDispatcherHostTest, CancelRequestsForContext) {
EXPECT_EQ(0, host_.pending_requests());
int render_view_id = 0;
@@ -2411,7 +2574,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) {
EXPECT_EQ(0, host_.pending_requests());
}
-TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextDetached) {
+TEST_P(ResourceDispatcherHostTest, CancelRequestsForContextDetached) {
EXPECT_EQ(0, host_.pending_requests());
int render_view_id = 0;
@@ -2440,7 +2603,11 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextDetached) {
// Test the cancelling of requests that are being transferred to a new renderer
// due to a redirection.
-TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
+TEST_P(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
+ // PlzNavigate: there are no transferred requests in PlzNavigate.
+ if (IsBrowserSideNavigationEnabled())
+ return;
+
EXPECT_EQ(0, host_.pending_requests());
int request_id = 1;
@@ -2457,7 +2624,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
GlobalRequestID global_request_id(web_contents_filter_->child_id(),
request_id);
- host_.MarkAsTransferredNavigation(global_request_id);
+ host_.MarkAsTransferredNavigation(global_request_id, nullptr);
// And now simulate a cancellation coming from the renderer.
ResourceHostMsg_CancelRequest msg(request_id);
@@ -2479,7 +2646,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
// Test transferred navigations with text/html, which doesn't trigger any
// content sniffing.
-TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) {
+TEST_P(ResourceDispatcherHostTest, TransferNavigationHtml) {
if (IsBrowserSideNavigationEnabled()) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
@@ -2551,9 +2718,103 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) {
CheckSuccessfulRequest(msgs[1], kResponseBody);
}
+// Tests that during a navigation transferred from one process to
+// another, the certificate is updated to be associated with the new
+// process.
+TEST_P(ResourceDispatcherHostTest, TransferNavigationCertificateUpdate) {
+ if (IsBrowserSideNavigationEnabled()) {
+ SUCCEED() << "Test is not applicable with browser side navigation enabled";
+ return;
+ }
+ // This test expects the cross site request to be leaked, so it can transfer
+ // the request directly.
+ CrossSiteResourceHandler::SetLeakRequestsForTesting(true);
+
+ EXPECT_EQ(0, host_.pending_requests());
+
+ int render_view_id = 0;
+ int request_id = 1;
+
+ // Configure initial request.
+ SetResponse(
+ "HTTP/1.1 302 Found\n"
+ "Location: https://example.com/blech\n\n");
+
+ HandleScheme("https");
+
+ // Temporarily replace ContentBrowserClient with one that will trigger the
+ // transfer navigation code paths.
+ TransfersAllNavigationsContentBrowserClient new_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
+
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+ GURL("https://example2.com/blah"),
+ RESOURCE_TYPE_MAIN_FRAME);
+
+ // Now that the resource loader is blocked on the redirect, update the
+ // response and unblock by telling the AsyncResourceHandler to follow
+ // the redirect.
+ const std::string kResponseBody = "hello world";
+ SetResponse(
+ "HTTP/1.1 200 OK\n"
+ "Content-Type: text/html\n\n",
+ kResponseBody);
+ SetTestSSLCertificate();
+ ResourceHostMsg_FollowRedirect redirect_msg(request_id);
+ host_.OnMessageReceived(redirect_msg, filter_.get());
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Flush all the pending requests to get the response through the
+ // MimeTypeResourceHandler.`
+ while (net::URLRequestTestJob::ProcessOnePendingMessage()) {
+ }
+
+ // Restore, now that we've set up a transfer.
+ SetBrowserClientForTesting(old_client);
+
+ // This second filter is used to emulate a second process.
+ scoped_refptr<ForwardingFilter> second_filter = MakeForwardingFilter();
+
+ int new_render_view_id = 1;
+ int new_request_id = 2;
+
+ ResourceHostMsg_Request request = CreateResourceRequest(
+ "GET", RESOURCE_TYPE_MAIN_FRAME, GURL("https://example.com/blech"));
+ request.transferred_request_child_id = filter_->child_id();
+ request.transferred_request_request_id = request_id;
+
+ // Before sending the transfer request, set up the mock cert store so
+ // that the test can assert that the cert id is set during transfer.
+ mock_cert_store_.set_default_cert_id(1);
+
+ ResourceHostMsg_RequestResource transfer_request_msg(new_render_view_id,
+ new_request_id, request);
+ host_.OnMessageReceived(transfer_request_msg, second_filter.get());
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Check generated messages.
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ ASSERT_EQ(2U, msgs.size());
+ EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type());
+ CheckSuccessfulRequest(msgs[1], kResponseBody);
+
+ // Check that the cert id was as expected in ReceivedResponse.
+ ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type());
+ base::PickleIterator iter(msgs[1][0]);
+ int sent_request_id;
+ ASSERT_TRUE(IPC::ReadParam(&msgs[1][0], &iter, &sent_request_id));
+ ResourceResponseHead response;
+ ASSERT_TRUE(IPC::ReadParam(&msgs[1][0], &iter, &response));
+ SSLStatus ssl;
+ ASSERT_TRUE(DeserializeSecurityInfo(response.security_info, &ssl));
+ EXPECT_EQ(1, ssl.cert_id);
+}
+
// Test transferring two navigations with text/html, to ensure the resource
// accounting works.
-TEST_F(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
+TEST_P(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
if (IsBrowserSideNavigationEnabled()) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
@@ -2640,7 +2901,7 @@ TEST_F(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
// Test transferred navigations with text/plain, which causes
// MimeTypeResourceHandler to buffer the response to sniff the content before
// the transfer occurs.
-TEST_F(ResourceDispatcherHostTest, TransferNavigationText) {
+TEST_P(ResourceDispatcherHostTest, TransferNavigationText) {
if (IsBrowserSideNavigationEnabled()) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
@@ -2714,7 +2975,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationText) {
CheckSuccessfulRequest(msgs[1], kResponseBody);
}
-TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
+TEST_P(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
if (IsBrowserSideNavigationEnabled()) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
@@ -2804,7 +3065,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
CheckSuccessfulRequest(msgs[1], kResponseBody);
}
-TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
+TEST_P(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
if (IsBrowserSideNavigationEnabled()) {
SUCCEED() << "Test is not applicable with browser side navigation enabled";
return;
@@ -2898,7 +3159,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
CheckSuccessfulRequest(msgs[1], kResponseBody);
}
-TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) {
+TEST_P(ResourceDispatcherHostTest, UnknownURLScheme) {
EXPECT_EQ(0, host_.pending_requests());
HandleScheme("http");
@@ -2922,7 +3183,7 @@ TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) {
CheckRequestCompleteErrorCode(msgs[0][0], net::ERR_UNKNOWN_URL_SCHEME);
}
-TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) {
+TEST_P(ResourceDispatcherHostTest, DataReceivedACKs) {
EXPECT_EQ(0, host_.pending_requests());
SendDataReceivedACKs(true);
@@ -2947,7 +3208,7 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) {
// Request a very large detachable resource and cancel part way. Some of the
// data should have been sent to the renderer, but not all.
-TEST_F(ResourceDispatcherHostTest, DataSentBeforeDetach) {
+TEST_P(ResourceDispatcherHostTest, DataSentBeforeDetach) {
EXPECT_EQ(0, host_.pending_requests());
int render_view_id = 0;
@@ -3003,7 +3264,7 @@ TEST_F(ResourceDispatcherHostTest, DataSentBeforeDetach) {
net::ERR_ABORTED);
}
-TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) {
+TEST_P(ResourceDispatcherHostTest, DelayedDataReceivedACKs) {
EXPECT_EQ(0, host_.pending_requests());
HandleScheme("big-job");
@@ -3052,7 +3313,7 @@ TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) {
// Flakyness of this test might indicate memory corruption issues with
// for example the ResourceBuffer of AsyncResourceHandler.
-TEST_F(ResourceDispatcherHostTest, DataReceivedUnexpectedACKs) {
+TEST_P(ResourceDispatcherHostTest, DataReceivedUnexpectedACKs) {
EXPECT_EQ(0, host_.pending_requests());
HandleScheme("big-job");
@@ -3105,7 +3366,7 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedUnexpectedACKs) {
}
// Tests the dispatcher host's temporary file management.
-TEST_F(ResourceDispatcherHostTest, RegisterDownloadedTempFile) {
+TEST_P(ResourceDispatcherHostTest, RegisterDownloadedTempFile) {
const int kRequestID = 1;
// Create a temporary file.
@@ -3152,7 +3413,7 @@ TEST_F(ResourceDispatcherHostTest, RegisterDownloadedTempFile) {
// Tests that temporary files held on behalf of child processes are released
// when the child process dies.
-TEST_F(ResourceDispatcherHostTest, ReleaseTemporiesOnProcessExit) {
+TEST_P(ResourceDispatcherHostTest, ReleaseTemporiesOnProcessExit) {
const int kRequestID = 1;
// Create a temporary file.
@@ -3183,7 +3444,7 @@ TEST_F(ResourceDispatcherHostTest, ReleaseTemporiesOnProcessExit) {
EXPECT_FALSE(base::PathExists(file_path));
}
-TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
+TEST_P(ResourceDispatcherHostTest, DownloadToFile) {
// Make a request which downloads to file.
ResourceHostMsg_Request request = CreateResourceRequest(
"GET", RESOURCE_TYPE_SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
@@ -3257,14 +3518,14 @@ TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
}
// Tests GetLoadInfoForAllRoutes when there are no pending requests.
-TEST_F(ResourceDispatcherHostTest, LoadInfoNoRequests) {
- scoped_ptr<LoadInfoMap> load_info_map = RunLoadInfoTest(nullptr, 0);
+TEST_P(ResourceDispatcherHostTest, LoadInfoNoRequests) {
+ std::unique_ptr<LoadInfoMap> load_info_map = RunLoadInfoTest(nullptr, 0);
EXPECT_EQ(0u, load_info_map->size());
}
// Tests GetLoadInfoForAllRoutes when there are 3 requests from the same
// RenderView. The second one is farthest along.
-TEST_F(ResourceDispatcherHostTest, LoadInfo) {
+TEST_P(ResourceDispatcherHostTest, LoadInfo) {
const GlobalRoutingID kId(filter_->child_id(), 0);
LoadInfoTestRequestInfo request_info[] = {
{kId.route_id,
@@ -3280,7 +3541,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfo) {
net::LOAD_STATE_SENDING_REQUEST,
net::UploadProgress(0, 0)},
};
- scoped_ptr<LoadInfoMap> load_info_map =
+ std::unique_ptr<LoadInfoMap> load_info_map =
RunLoadInfoTest(request_info, arraysize(request_info));
ASSERT_EQ(1u, load_info_map->size());
ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
@@ -3293,7 +3554,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfo) {
// Tests GetLoadInfoForAllRoutes when there are 2 requests with the same
// priority. The first one (Which will have the lowest ID) should be returned.
-TEST_F(ResourceDispatcherHostTest, LoadInfoSamePriority) {
+TEST_P(ResourceDispatcherHostTest, LoadInfoSamePriority) {
const GlobalRoutingID kId(filter_->child_id(), 0);
LoadInfoTestRequestInfo request_info[] = {
{kId.route_id,
@@ -3305,7 +3566,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoSamePriority) {
net::LOAD_STATE_IDLE,
net::UploadProgress(0, 0)},
};
- scoped_ptr<LoadInfoMap> load_info_map =
+ std::unique_ptr<LoadInfoMap> load_info_map =
RunLoadInfoTest(request_info, arraysize(request_info));
ASSERT_EQ(1u, load_info_map->size());
ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
@@ -3316,7 +3577,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoSamePriority) {
}
// Tests GetLoadInfoForAllRoutes when a request is uploading a body.
-TEST_F(ResourceDispatcherHostTest, LoadInfoUploadProgress) {
+TEST_P(ResourceDispatcherHostTest, LoadInfoUploadProgress) {
const GlobalRoutingID kId(filter_->child_id(), 0);
LoadInfoTestRequestInfo request_info[] = {
{kId.route_id,
@@ -3340,7 +3601,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoUploadProgress) {
net::LOAD_STATE_READING_RESPONSE,
net::UploadProgress(0, 0)},
};
- scoped_ptr<LoadInfoMap> load_info_map =
+ std::unique_ptr<LoadInfoMap> load_info_map =
RunLoadInfoTest(request_info, arraysize(request_info));
ASSERT_EQ(1u, load_info_map->size());
ASSERT_TRUE(load_info_map->find(kId) != load_info_map->end());
@@ -3354,7 +3615,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoUploadProgress) {
// Tests GetLoadInfoForAllRoutes when there are 4 requests from 2 different
// RenderViews. Also tests the case where the first / last requests are the
// most interesting ones.
-TEST_F(ResourceDispatcherHostTest, LoadInfoTwoRenderViews) {
+TEST_P(ResourceDispatcherHostTest, LoadInfoTwoRenderViews) {
const GlobalRoutingID kId1(filter_->child_id(), 0);
const GlobalRoutingID kId2(filter_->child_id(), 1);
LoadInfoTestRequestInfo request_info[] = {
@@ -3375,7 +3636,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoTwoRenderViews) {
net::LOAD_STATE_CONNECTING,
net::UploadProgress(0, 0)},
};
- scoped_ptr<LoadInfoMap> load_info_map =
+ std::unique_ptr<LoadInfoMap> load_info_map =
RunLoadInfoTest(request_info, arraysize(request_info));
ASSERT_EQ(2u, load_info_map->size());
@@ -3396,7 +3657,7 @@ TEST_F(ResourceDispatcherHostTest, LoadInfoTwoRenderViews) {
// Confirm that resource response started notifications are correctly
// transmitted to the WebContents.
-TEST_F(ResourceDispatcherHostTest, TransferResponseStarted) {
+TEST_P(ResourceDispatcherHostTest, TransferResponseStarted) {
int initial_count = web_contents_observer_->resource_response_start_count();
MakeWebContentsAssociatedTestRequest(1, net::URLRequestTestJob::test_url_1());
@@ -3408,7 +3669,7 @@ TEST_F(ResourceDispatcherHostTest, TransferResponseStarted) {
// Confirm that request redirected notifications are correctly
// transmitted to the WebContents.
-TEST_F(ResourceDispatcherHostTest, TransferRequestRedirected) {
+TEST_P(ResourceDispatcherHostTest, TransferRequestRedirected) {
int initial_count = web_contents_observer_->resource_request_redirect_count();
MakeWebContentsAssociatedTestRequest(
@@ -3420,15 +3681,13 @@ TEST_F(ResourceDispatcherHostTest, TransferRequestRedirected) {
}
// Confirm that DidChangePriority messages are respected.
-TEST_F(ResourceDispatcherHostTest, DidChangePriority) {
+TEST_P(ResourceDispatcherHostTest, DidChangePriority) {
// ResourceScheduler only throttles http and https requests.
HandleScheme("http");
// Needed to enable scheduling for this child.
host_.OnRenderViewHostCreated(filter_->child_id(), // child_id
- 0, // route_id
- true, // is_visible
- false); // is_audible
+ 0); // route_id
// Prevent any of these requests from completing.
job_factory_->SetDelayedCompleteJobGeneration(true);
@@ -3459,7 +3718,7 @@ TEST_F(ResourceDispatcherHostTest, DidChangePriority) {
// Confirm that resource response started notifications for downloads are not
// transmitted to the WebContents.
-TEST_F(ResourceDispatcherHostTest, TransferResponseStartedDownload) {
+TEST_P(ResourceDispatcherHostTest, TransferResponseStartedDownload) {
int initial_count(web_contents_observer_->resource_response_start_count());
MakeWebContentsAssociatedDownloadRequest(
@@ -3471,7 +3730,7 @@ TEST_F(ResourceDispatcherHostTest, TransferResponseStartedDownload) {
// Confirm that request redirected notifications for downloads are not
// transmitted to the WebContents.
-TEST_F(ResourceDispatcherHostTest, TransferRequestRedirectedDownload) {
+TEST_P(ResourceDispatcherHostTest, TransferRequestRedirectedDownload) {
int initial_count(web_contents_observer_->resource_request_redirect_count());
MakeWebContentsAssociatedDownloadRequest(
@@ -3481,6 +3740,28 @@ TEST_F(ResourceDispatcherHostTest, TransferRequestRedirectedDownload) {
web_contents_observer_->resource_request_redirect_count());
}
+// A URLRequestTestJob that sets a test certificate on the |ssl_info|
+// field of the response.
+class TestHTTPSURLRequestJob : public net::URLRequestTestJob {
+ public:
+ TestHTTPSURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const std::string& response_headers,
+ const std::string& response_data,
+ bool auto_advance)
+ : net::URLRequestTestJob(request,
+ network_delegate,
+ response_headers,
+ response_data,
+ auto_advance) {}
+
+ void GetResponseInfo(net::HttpResponseInfo* info) override {
+ net::URLRequestTestJob::GetResponseInfo(info);
+ info->ssl_info.cert =
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+ }
+};
+
net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
@@ -3490,7 +3771,7 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
test_fixture_->wait_for_request_create_loop_->Quit();
if (test_fixture_->loader_test_request_info_) {
DCHECK_EQ(test_fixture_->loader_test_request_info_->url, request->url());
- scoped_ptr<LoadInfoTestRequestInfo> info =
+ std::unique_ptr<LoadInfoTestRequestInfo> info =
std::move(test_fixture_->loader_test_request_info_);
return new URLRequestLoadInfoJob(request, network_delegate,
info->load_state, info->upload_progress);
@@ -3523,6 +3804,10 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
request, network_delegate,
test_fixture_->response_headers_, test_fixture_->response_data_,
false);
+ } else if (test_fixture_->use_test_ssl_certificate_) {
+ return new TestHTTPSURLRequestJob(request, network_delegate,
+ test_fixture_->response_headers_,
+ test_fixture_->response_data_, false);
} else {
return new net::URLRequestTestJob(
request, network_delegate,
@@ -3545,4 +3830,10 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptResponse(
return nullptr;
}
+INSTANTIATE_TEST_CASE_P(
+ ResourceDispatcherHostTests,
+ ResourceDispatcherHostTest,
+ testing::Values(TestConfig::kDefault,
+ TestConfig::kOptimizeIPCForSmallResourceEnabled));
+
} // namespace content
diff --git a/chromium/content/browser/loader/resource_loader.cc b/chromium/content/browser/loader/resource_loader.cc
index eee044c6aaf..40e1f2a6074 100644
--- a/chromium/content/browser/loader/resource_loader.cc
+++ b/chromium/content/browser/loader/resource_loader.cc
@@ -13,6 +13,7 @@
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/loader/cross_site_resource_handler.h"
@@ -65,11 +66,10 @@ void StoreSignedCertificateTimestamps(
void GetSSLStatusForRequest(const GURL& url,
const net::SSLInfo& ssl_info,
int child_id,
+ CertStore* cert_store,
SSLStatus* ssl_status) {
DCHECK(ssl_info.cert);
-
- int cert_id =
- CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
+ int cert_id = cert_store->StoreCert(ssl_info.cert.get(), child_id);
SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
@@ -82,6 +82,7 @@ void GetSSLStatusForRequest(const GURL& url,
void PopulateResourceResponse(ResourceRequestInfoImpl* info,
net::URLRequest* request,
+ CertStore* cert_store,
ResourceResponse* response) {
response->head.request_time = request->request_time();
response->head.response_time = request->response_time();
@@ -115,7 +116,7 @@ void PopulateResourceResponse(ResourceRequestInfoImpl* info,
if (request->ssl_info().cert.get()) {
SSLStatus ssl_status;
GetSSLStatusForRequest(request->url(), request->ssl_info(),
- info->GetChildID(), &ssl_status);
+ info->GetChildID(), cert_store, &ssl_status);
response->head.security_info = SerializeSecurityInfo(ssl_status);
response->head.has_major_certificate_errors =
net::IsCertStatusError(ssl_status.cert_status) &&
@@ -131,8 +132,9 @@ void PopulateResourceResponse(ResourceRequestInfoImpl* info,
} // namespace
-ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceHandler> handler,
+ResourceLoader::ResourceLoader(std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceHandler> handler,
+ CertStore* cert_store,
ResourceLoaderDelegate* delegate)
: deferred_stage_(DEFERRED_NONE),
request_(std::move(request)),
@@ -142,6 +144,7 @@ ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
times_cancelled_before_request_start_(0),
started_request_(false),
times_cancelled_after_request_start_(0),
+ cert_store_(cert_store),
weak_ptr_factory_(this) {
request_->set_delegate(this);
handler_->SetController(this);
@@ -170,6 +173,8 @@ void ResourceLoader::StartRequest() {
return;
}
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::StartRequest", this,
+ TRACE_EVENT_FLAG_FLOW_OUT);
if (defer_start) {
deferred_stage_ = DEFERRED_START;
} else {
@@ -178,6 +183,8 @@ void ResourceLoader::StartRequest() {
}
void ResourceLoader::CancelRequest(bool from_renderer) {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelRequest", this,
+ TRACE_EVENT_FLAG_FLOW_IN);
CancelRequestInternal(net::ERR_ABORTED, from_renderer);
}
@@ -188,13 +195,17 @@ void ResourceLoader::CancelAndIgnore() {
}
void ResourceLoader::CancelWithError(int error_code) {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CancelWithError", this,
+ TRACE_EVENT_FLAG_FLOW_IN);
CancelRequestInternal(error_code, false);
}
-void ResourceLoader::MarkAsTransferring() {
+void ResourceLoader::MarkAsTransferring(
+ const scoped_refptr<ResourceResponse>& response) {
CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
<< "Can only transfer for navigations";
is_transferring_ = true;
+ transferring_response_ = response;
int child_id = GetRequestInfo()->GetChildID();
AppCacheInterceptor::PrepareForCrossSiteTransfer(request(), child_id);
@@ -212,6 +223,7 @@ void ResourceLoader::CompleteTransfer() {
DCHECK(DEFERRED_READ == deferred_stage_ ||
DEFERRED_RESPONSE_COMPLETE == deferred_stage_);
DCHECK(is_transferring_);
+ DCHECK(transferring_response_);
// In some cases, a process transfer doesn't really happen and the
// request is resumed in the original process. Real transfers to a new process
@@ -225,6 +237,7 @@ void ResourceLoader::CompleteTransfer() {
handler->MaybeCompleteCrossSiteTransferInOldProcess(child_id);
is_transferring_ = false;
+ transferring_response_ = nullptr;
GetRequestInfo()->cross_site_handler()->ResumeResponse();
}
@@ -239,6 +252,8 @@ void ResourceLoader::ClearLoginDelegate() {
void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
const net::RedirectInfo& redirect_info,
bool* defer) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "ResourceLoader::OnReceivedRedirect");
DCHECK_EQ(request_.get(), unused);
DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
@@ -246,9 +261,8 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
ResourceRequestInfoImpl* info = GetRequestInfo();
- if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
- !ChildProcessSecurityPolicyImpl::GetInstance()->
- CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+ info->GetChildID(), redirect_info.new_url)) {
DVLOG(1) << "Denied unauthorized request for "
<< redirect_info.new_url.possibly_invalid_spec();
@@ -265,8 +279,8 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
return;
}
- scoped_refptr<ResourceResponse> response(new ResourceResponse());
- PopulateResourceResponse(info, request_.get(), response.get());
+ scoped_refptr<ResourceResponse> response = new ResourceResponse();
+ PopulateResourceResponse(info, request_.get(), cert_store_, response.get());
if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
Cancel();
} else if (*defer) {
@@ -324,6 +338,8 @@ void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
bool* defer) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "ResourceLoader::OnBeforeNetworkStart");
DCHECK_EQ(request_.get(), unused);
// Give the handler a chance to delay the URLRequest from using the network.
@@ -336,6 +352,8 @@ void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
}
void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "ResourceLoader::OnResponseStarted");
DCHECK_EQ(request_.get(), unused);
DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
@@ -357,6 +375,8 @@ void ResourceLoader::OnResponseStarted(net::URLRequest* unused) {
}
void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "ResourceLoader::OnReadCompleted");
DCHECK_EQ(request_.get(), unused);
DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
<< " bytes_read = " << bytes_read;
@@ -537,8 +557,8 @@ void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
void ResourceLoader::CompleteResponseStarted() {
ResourceRequestInfoImpl* info = GetRequestInfo();
- scoped_refptr<ResourceResponse> response(new ResourceResponse());
- PopulateResourceResponse(info, request_.get(), response.get());
+ scoped_refptr<ResourceResponse> response = new ResourceResponse();
+ PopulateResourceResponse(info, request_.get(), cert_store_, response.get());
delegate_->DidReceiveResponse(this);
@@ -591,6 +611,8 @@ void ResourceLoader::ResumeReading() {
}
void ResourceLoader::ReadMore(int* bytes_read) {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ReadMore", this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
DCHECK(!is_deferred());
// Make sure we track the buffer in at least one place. This ensures it gets
@@ -619,6 +641,9 @@ void ResourceLoader::ReadMore(int* bytes_read) {
}
void ResourceLoader::CompleteRead(int bytes_read) {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CompleteRead", this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+
DCHECK(bytes_read >= 0);
DCHECK(request_->status().is_success());
@@ -641,6 +666,9 @@ void ResourceLoader::CompleteRead(int bytes_read) {
}
void ResourceLoader::ResponseCompleted() {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ResponseCompleted", this,
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+
DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
RecordHistograms();
ResourceRequestInfoImpl* info = GetRequestInfo();
@@ -650,7 +678,7 @@ void ResourceLoader::ResponseCompleted() {
if (ssl_info.cert.get() != NULL) {
SSLStatus ssl_status;
GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
- &ssl_status);
+ cert_store_, &ssl_status);
security_info = SerializeSecurityInfo(ssl_status);
}
@@ -674,6 +702,8 @@ void ResourceLoader::ResponseCompleted() {
}
void ResourceLoader::CallDidFinishLoading() {
+ TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::CallDidFinishLoading",
+ this, TRACE_EVENT_FLAG_FLOW_IN);
delegate_->DidFinishLoading(this);
}
diff --git a/chromium/content/browser/loader/resource_loader.h b/chromium/content/browser/loader/resource_loader.h
index 5b5ecdb500e..976111a7408 100644
--- a/chromium/content/browser/loader/resource_loader.h
+++ b/chromium/content/browser/loader/resource_loader.h
@@ -5,8 +5,9 @@
#ifndef CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
#define CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "content/browser/loader/resource_handler.h"
@@ -22,6 +23,7 @@ class X509Certificate;
}
namespace content {
+class CertStore;
class ResourceDispatcherHostLoginDelegate;
class ResourceLoaderDelegate;
class ResourceRequestInfoImpl;
@@ -34,8 +36,9 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
public SSLClientAuthHandler::Delegate,
public ResourceController {
public:
- ResourceLoader(scoped_ptr<net::URLRequest> request,
- scoped_ptr<ResourceHandler> handler,
+ ResourceLoader(std::unique_ptr<net::URLRequest> request,
+ std::unique_ptr<ResourceHandler> handler,
+ CertStore* cert_store,
ResourceLoaderDelegate* delegate);
~ResourceLoader() override;
@@ -43,7 +46,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void CancelRequest(bool from_renderer);
bool is_transferring() const { return is_transferring_; }
- void MarkAsTransferring();
+ void MarkAsTransferring(const scoped_refptr<ResourceResponse>& response);
void CompleteTransfer();
net::URLRequest* request() { return request_.get(); }
@@ -51,6 +54,15 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void ClearLoginDelegate();
+ // Returns a pointer to the ResourceResponse for a request that is
+ // being transferred to a new consumer. The response is valid between
+ // the time that the request is marked as transferring via
+ // MarkAsTransferring() and the time that the transfer is completed
+ // via CompleteTransfer().
+ ResourceResponse* transferring_response() {
+ return transferring_response_.get();
+ }
+
private:
// net::URLRequest::Delegate implementation:
void OnReceivedRedirect(net::URLRequest* request,
@@ -125,12 +137,12 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
};
DeferredStage deferred_stage_;
- scoped_ptr<net::URLRequest> request_;
- scoped_ptr<ResourceHandler> handler_;
+ std::unique_ptr<net::URLRequest> request_;
+ std::unique_ptr<ResourceHandler> handler_;
ResourceLoaderDelegate* delegate_;
scoped_refptr<ResourceDispatcherHostLoginDelegate> login_delegate_;
- scoped_ptr<SSLClientAuthHandler> ssl_client_auth_handler_;
+ std::unique_ptr<SSLClientAuthHandler> ssl_client_auth_handler_;
base::TimeTicks read_deferral_start_time_;
@@ -139,12 +151,22 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
// which point we'll receive a new ResourceHandler.
bool is_transferring_;
+ // Holds the ResourceResponse for a request that is being transferred
+ // to a new consumer. This member is populated when the request is
+ // marked as transferring via MarkAsTransferring(), and it is cleared
+ // when the transfer is completed via CompleteTransfer().
+ scoped_refptr<ResourceResponse> transferring_response_;
+
// Instrumentation add to investigate http://crbug.com/503306.
// TODO(mmenke): Remove once bug is fixed.
int times_cancelled_before_request_start_;
bool started_request_;
int times_cancelled_after_request_start_;
+ // Allows tests to use a mock CertStore. The CertStore must outlive
+ // the ResourceLoader.
+ CertStore* cert_store_;
+
base::WeakPtrFactory<ResourceLoader> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ResourceLoader);
diff --git a/chromium/content/browser/loader/resource_loader_unittest.cc b/chromium/content/browser/loader/resource_loader_unittest.cc
index 05ed7fc4efb..32197c7bc1e 100644
--- a/chromium/content/browser/loader/resource_loader_unittest.cc
+++ b/chromium/content/browser/loader/resource_loader_unittest.cc
@@ -6,13 +6,15 @@
#include <stddef.h>
#include <stdint.h>
+
+#include <memory>
#include <utility>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -111,11 +113,10 @@ class LoaderDestroyingCertStore : public net::ClientCertStore {
// Creates a client certificate store which, when looked up, posts a task to
// reset |loader| and then call the callback. The caller is responsible for
// ensuring the pointers remain valid until the process is complete.
- LoaderDestroyingCertStore(scoped_ptr<ResourceLoader>* loader,
+ LoaderDestroyingCertStore(std::unique_ptr<ResourceLoader>* loader,
const base::Closure& on_loader_deleted_callback)
: loader_(loader),
- on_loader_deleted_callback_(on_loader_deleted_callback) {
- }
+ on_loader_deleted_callback_(on_loader_deleted_callback) {}
// net::ClientCertStore:
void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
@@ -133,7 +134,7 @@ class LoaderDestroyingCertStore : public net::ClientCertStore {
// This needs to be static because |loader| owns the
// LoaderDestroyingCertStore (ClientCertStores are actually handles, and not
// global cert stores).
- static void DoCallback(scoped_ptr<ResourceLoader>* loader,
+ static void DoCallback(std::unique_ptr<ResourceLoader>* loader,
const base::Closure& cert_selected_callback,
const base::Closure& on_loader_deleted_callback) {
loader->reset();
@@ -141,7 +142,7 @@ class LoaderDestroyingCertStore : public net::ClientCertStore {
on_loader_deleted_callback.Run();
}
- scoped_ptr<ResourceLoader>* loader_;
+ std::unique_ptr<ResourceLoader>* loader_;
base::Closure on_loader_deleted_callback_;
DISALLOW_COPY_AND_ASSIGN(LoaderDestroyingCertStore);
@@ -167,7 +168,8 @@ class MockClientCertURLRequestJob : public net::URLRequestTestJob {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
- weak_factory_.GetWeakPtr(), cert_request_info));
+ weak_factory_.GetWeakPtr(),
+ base::RetainedRef(cert_request_info)));
}
void ContinueWithCertificate(net::X509Certificate* cert,
@@ -426,7 +428,7 @@ class ResourceHandlerStub : public ResourceHandler {
int total_bytes_downloaded_;
base::RunLoop deferred_run_loop_;
base::RunLoop response_completed_run_loop_;
- scoped_ptr<base::RunLoop> wait_for_progress_run_loop_;
+ std::unique_ptr<base::RunLoop> wait_for_progress_run_loop_;
};
// Test browser client that captures calls to SelectClientCertificates and
@@ -446,7 +448,7 @@ class SelectCertificateBrowserClient : public TestContentBrowserClient {
void SelectClientCertificate(
WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
- scoped_ptr<ClientCertificateDelegate> delegate) override {
+ std::unique_ptr<ClientCertificateDelegate> delegate) override {
EXPECT_FALSE(delegate_.get());
++call_count_;
@@ -468,7 +470,7 @@ class SelectCertificateBrowserClient : public TestContentBrowserClient {
private:
net::CertificateList passed_certs_;
int call_count_;
- scoped_ptr<ClientCertificateDelegate> delegate_;
+ std::unique_ptr<ClientCertificateDelegate> delegate_;
base::RunLoop select_certificate_run_loop_;
@@ -480,16 +482,16 @@ class ResourceContextStub : public MockResourceContext {
explicit ResourceContextStub(net::URLRequestContext* test_request_context)
: MockResourceContext(test_request_context) {}
- scoped_ptr<net::ClientCertStore> CreateClientCertStore() override {
+ std::unique_ptr<net::ClientCertStore> CreateClientCertStore() override {
return std::move(dummy_cert_store_);
}
- void SetClientCertStore(scoped_ptr<net::ClientCertStore> store) {
+ void SetClientCertStore(std::unique_ptr<net::ClientCertStore> store) {
dummy_cert_store_ = std::move(store);
}
private:
- scoped_ptr<net::ClientCertStore> dummy_cert_store_;
+ std::unique_ptr<net::ClientCertStore> dummy_cert_store_;
};
// Wraps a ChunkedUploadDataStream to behave as non-chunked to enable upload
@@ -531,8 +533,8 @@ void CreateTemporaryError(
const CreateTemporaryFileStreamCallback& callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(callback, error, base::Passed(scoped_ptr<net::FileStream>()),
- scoped_refptr<ShareableFileReference>()));
+ base::Bind(callback, error,
+ base::Passed(std::unique_ptr<net::FileStream>()), nullptr));
}
} // namespace
@@ -554,19 +556,19 @@ class ResourceLoaderTest : public testing::Test,
return net::URLRequestTestJob::test_data_1();
}
- virtual scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
+ virtual std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
CreateProtocolHandler() {
return net::URLRequestTestJob::CreateProtocolHandler();
}
- virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
- scoped_ptr<ResourceHandlerStub> leaf_handler,
+ virtual std::unique_ptr<ResourceHandler> WrapResourceHandler(
+ std::unique_ptr<ResourceHandlerStub> leaf_handler,
net::URLRequest* request) {
return std::move(leaf_handler);
}
// Replaces loader_ with a new one for |request|.
- void SetUpResourceLoader(scoped_ptr<net::URLRequest> request) {
+ void SetUpResourceLoader(std::unique_ptr<net::URLRequest> request) {
raw_ptr_to_request_ = request.get();
RenderFrameHost* rfh = web_contents_->GetMainFrame();
@@ -576,13 +578,13 @@ class ResourceLoaderTest : public testing::Test,
rfh->GetRoutingID(), true /* is_main_frame */,
false /* parent_is_main_frame */, true /* allow_download */,
false /* is_async */, false /* is_using_lofi_ */);
- scoped_ptr<ResourceHandlerStub> resource_handler(
+ std::unique_ptr<ResourceHandlerStub> resource_handler(
new ResourceHandlerStub(request.get()));
raw_ptr_resource_handler_ = resource_handler.get();
loader_.reset(new ResourceLoader(
std::move(request),
WrapResourceHandler(std::move(resource_handler), raw_ptr_to_request_),
- this));
+ CertStore::GetInstance(), this));
}
void SetUp() override {
@@ -594,11 +596,9 @@ class ResourceLoaderTest : public testing::Test,
web_contents_.reset(
TestWebContents::Create(browser_context_.get(), site_instance.get()));
- scoped_ptr<net::URLRequest> request(
+ std::unique_ptr<net::URLRequest> request(
resource_context_.GetRequestContext()->CreateRequest(
- test_url(),
- net::DEFAULT_PRIORITY,
- nullptr /* delegate */));
+ test_url(), net::DEFAULT_PRIORITY, nullptr /* delegate */));
SetUpResourceLoader(std::move(request));
}
@@ -632,20 +632,20 @@ class ResourceLoaderTest : public testing::Test,
net::URLRequestJobFactoryImpl job_factory_;
net::TestURLRequestContext test_url_request_context_;
ResourceContextStub resource_context_;
- scoped_ptr<TestBrowserContext> browser_context_;
- scoped_ptr<TestWebContents> web_contents_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
+ std::unique_ptr<TestWebContents> web_contents_;
// The ResourceLoader owns the URLRequest and the ResourceHandler.
ResourceHandlerStub* raw_ptr_resource_handler_;
net::URLRequest* raw_ptr_to_request_;
- scoped_ptr<ResourceLoader> loader_;
+ std::unique_ptr<ResourceLoader> loader_;
};
class ClientCertResourceLoaderTest : public ResourceLoaderTest {
protected:
- scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> CreateProtocolHandler()
- override {
- return make_scoped_ptr(new MockClientCertJobProtocolHandler);
+ std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
+ CreateProtocolHandler() override {
+ return base::WrapUnique(new MockClientCertJobProtocolHandler);
}
};
@@ -672,11 +672,11 @@ class HTTPSSecurityInfoResourceLoaderTest : public ResourceLoaderTest {
net::URLRequestFilter::GetInstance()->ClearHandlers();
net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
"https", "example.test",
- scoped_ptr<net::URLRequestInterceptor>(
+ std::unique_ptr<net::URLRequestInterceptor>(
new MockHTTPSJobURLRequestInterceptor(false /* redirect */)));
net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
"https", "example-redirect.test",
- scoped_ptr<net::URLRequestInterceptor>(
+ std::unique_ptr<net::URLRequestInterceptor>(
new MockHTTPSJobURLRequestInterceptor(true /* redirect */)));
}
@@ -692,7 +692,7 @@ TEST_F(ClientCertResourceLoaderTest, WithStoreLookup) {
std::vector<std::string> store_requested_authorities;
net::CertificateList dummy_certs(1, scoped_refptr<net::X509Certificate>(
new net::X509Certificate("test", "test", base::Time(), base::Time())));
- scoped_ptr<ClientCertStoreStub> test_store(new ClientCertStoreStub(
+ std::unique_ptr<ClientCertStoreStub> test_store(new ClientCertStoreStub(
dummy_certs, &store_request_count, &store_requested_authorities));
resource_context_.SetClientCertStore(std::move(test_store));
@@ -804,8 +804,7 @@ TEST_F(ClientCertResourceLoaderTest, StoreAsyncCancel) {
LoaderDestroyingCertStore* test_store =
new LoaderDestroyingCertStore(&loader_,
loader_destroyed_run_loop.QuitClosure());
- resource_context_.SetClientCertStore(
- make_scoped_ptr(test_store));
+ resource_context_.SetClientCertStore(base::WrapUnique(test_store));
loader_->StartRequest();
loader_destroyed_run_loop.Run();
@@ -880,8 +879,8 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
return redirect_to_file_resource_handler_;
}
- scoped_ptr<ResourceHandler> WrapResourceHandler(
- scoped_ptr<ResourceHandlerStub> leaf_handler,
+ std::unique_ptr<ResourceHandler> WrapResourceHandler(
+ std::unique_ptr<ResourceHandlerStub> leaf_handler,
net::URLRequest* request) override {
leaf_handler->set_expect_reads(false);
@@ -893,7 +892,7 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
CHECK(file.IsValid());
// Create mock file streams and a ShareableFileReference.
- scoped_ptr<net::testing::MockFileStream> file_stream(
+ std::unique_ptr<net::testing::MockFileStream> file_stream(
new net::testing::MockFileStream(std::move(file),
base::ThreadTaskRunnerHandle::Get()));
file_stream_ = file_stream.get();
@@ -904,7 +903,7 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
BrowserThread::FILE).get());
// Inject them into the handler.
- scoped_ptr<RedirectToFileResourceHandler> handler(
+ std::unique_ptr<RedirectToFileResourceHandler> handler(
new RedirectToFileResourceHandler(std::move(leaf_handler), request));
redirect_to_file_resource_handler_ = handler.get();
handler->SetCreateTemporaryFileStreamFunctionForTesting(
@@ -915,12 +914,12 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
}
private:
- void PostCallback(
- scoped_ptr<net::FileStream> file_stream,
- const CreateTemporaryFileStreamCallback& callback) {
+ void PostCallback(std::unique_ptr<net::FileStream> file_stream,
+ const CreateTemporaryFileStreamCallback& callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, base::File::FILE_OK,
- base::Passed(&file_stream), deletable_file_));
+ FROM_HERE,
+ base::Bind(callback, base::File::FILE_OK, base::Passed(&file_stream),
+ base::RetainedRef(deletable_file_)));
}
base::FilePath temp_path_;
@@ -1079,7 +1078,7 @@ TEST_F(ResourceLoaderRedirectToFileTest, DownstreamDeferStart) {
// to it.
TEST_F(HTTPSSecurityInfoResourceLoaderTest, SecurityInfoOnHTTPSResource) {
// Start the request and wait for it to finish.
- scoped_ptr<net::URLRequest> request(
+ std::unique_ptr<net::URLRequest> request(
resource_context_.GetRequestContext()->CreateRequest(
test_https_url(), net::DEFAULT_PRIORITY, nullptr /* delegate */));
SetUpResourceLoader(std::move(request));
@@ -1117,7 +1116,7 @@ TEST_F(HTTPSSecurityInfoResourceLoaderTest, SecurityInfoOnHTTPSResource) {
TEST_F(HTTPSSecurityInfoResourceLoaderTest,
SecurityInfoOnHTTPSRedirectResource) {
// Start the request and wait for it to finish.
- scoped_ptr<net::URLRequest> request(
+ std::unique_ptr<net::URLRequest> request(
resource_context_.GetRequestContext()->CreateRequest(
test_https_redirect_url(), net::DEFAULT_PRIORITY,
nullptr /* delegate */));
diff --git a/chromium/content/browser/loader/resource_message_filter.h b/chromium/content/browser/loader/resource_message_filter.h
index 9bac4198f60..7047aa64735 100644
--- a/chromium/content/browser/loader/resource_message_filter.h
+++ b/chromium/content/browser/loader/resource_message_filter.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_FILTER_H_
+#include <memory>
+
#include "base/callback_forward.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
diff --git a/chromium/content/browser/loader/resource_request_info_impl.cc b/chromium/content/browser/loader/resource_request_info_impl.cc
index 8511653ee50..37f4e992fb1 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.cc
+++ b/chromium/content/browser/loader/resource_request_info_impl.cc
@@ -8,6 +8,7 @@
#include "content/browser/loader/global_routing_id.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/net/url_request_service_worker_data.h"
#include "content/common/net/url_request_user_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_request_id.h"
@@ -106,6 +107,13 @@ bool ResourceRequestInfo::GetRenderFrameForRequest(
return true;
}
+// static
+bool ResourceRequestInfo::OriginatedFromServiceWorker(
+ const net::URLRequest* request) {
+ return !!request->GetUserData(
+ content::URLRequestServiceWorkerData::kUserDataKey);
+}
+
// ----------------------------------------------------------------------------
// ResourceRequestInfoImpl
@@ -269,13 +277,8 @@ bool ResourceRequestInfoImpl::WasIgnoredByHandler() const {
bool ResourceRequestInfoImpl::GetAssociatedRenderFrame(
int* render_process_id,
int* render_frame_id) const {
- if (process_type_ == PROCESS_TYPE_PLUGIN) {
- *render_process_id = origin_pid_;
- *render_frame_id = render_frame_id_;
- } else {
- *render_process_id = child_id_;
- *render_frame_id = render_frame_id_;
- }
+ *render_process_id = child_id_;
+ *render_frame_id = render_frame_id_;
return true;
}
diff --git a/chromium/content/browser/loader/resource_request_info_impl.h b/chromium/content/browser/loader/resource_request_info_impl.h
index 625e58ca890..1e383504c0b 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.h
+++ b/chromium/content/browser/loader/resource_request_info_impl.h
@@ -5,12 +5,12 @@
#ifndef CONTENT_BROWSER_LOADER_RESOURCE_REQUEST_INFO_IMPL_H_
#define CONTENT_BROWSER_LOADER_RESOURCE_REQUEST_INFO_IMPL_H_
+#include <memory>
#include <string>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "content/public/browser/resource_request_info.h"
diff --git a/chromium/content/browser/loader/resource_scheduler.cc b/chromium/content/browser/loader/resource_scheduler.cc
index 690f20f0a03..ea4c6df775d 100644
--- a/chromium/content/browser/loader/resource_scheduler.cc
+++ b/chromium/content/browser/loader/resource_scheduler.cc
@@ -17,7 +17,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/supports_user_data.h"
-#include "base/time/time.h"
#include "content/common/resource_messages.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_request_info.h"
@@ -39,10 +38,6 @@ enum StartMode {
};
// Field trial constants
-const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing";
-const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle";
-const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce";
-
const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting";
const char kRequestLimitFieldTrialGroupPrefix[] = "Limit";
@@ -56,46 +51,10 @@ const RequestAttributes kAttributeInFlight = 0x01;
const RequestAttributes kAttributeDelayable = 0x02;
const RequestAttributes kAttributeLayoutBlocking = 0x04;
-// Post ResourceScheduler histograms of the following forms:
-// If |histogram_suffix| is NULL or the empty string:
-// ResourceScheduler.base_name.histogram_name
-// Else:
-// ResourceScheduler.base_name.histogram_name.histogram_suffix
-void PostHistogram(const char* base_name,
- const char* histogram_name,
- const char* histogram_suffix,
- base::TimeDelta time) {
- std::string histogram =
- base::StringPrintf("ResourceScheduler.%s.%s", base_name, histogram_name);
- if (histogram_suffix && histogram_suffix[0] != '\0')
- histogram = histogram + "." + histogram_suffix;
- base::HistogramBase* histogram_counter = base::Histogram::FactoryTimeGet(
- histogram, base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(5), 50,
- base::Histogram::kUmaTargetedHistogramFlag);
- histogram_counter->AddTime(time);
-}
-
-// For use with PostHistogram to specify the correct string for histogram
-// suffixes based on number of Clients.
-const char* GetNumClientsString(size_t num_clients) {
- if (num_clients == 1)
- return "1Client";
- else if (num_clients <= 5)
- return "Max5Clients";
- else if (num_clients <= 15)
- return "Max15Clients";
- else if (num_clients <= 30)
- return "Max30Clients";
- return "Over30Clients";
-}
-
} // namespace
-static const size_t kCoalescedTimerPeriod = 5000;
static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
static const size_t kMaxNumDelayableRequestsPerHost = 6;
-static const size_t kMaxNumThrottledRequestsPerClient = 1;
static const size_t kDefaultMaxNumDelayableWhileLayoutBlocking = 1;
static const net::RequestPriority
kDefaultLayoutBlockingPriorityThreshold = net::LOW;
@@ -191,7 +150,6 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
const RequestPriorityParams& priority,
bool is_async)
: client_id_(client_id),
- client_state_on_creation_(scheduler->GetClientState(client_id_)),
request_(request),
ready_(false),
deferred_(false),
@@ -224,8 +182,6 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
if (!request_->status().is_success())
return;
- bool was_deferred = deferred_;
-
// If the request was deferred, need to start it. Otherwise, will just not
// defer starting it in the first place, and the value of |start_mode|
// makes no difference.
@@ -245,32 +201,6 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
}
ready_ = true;
-
- // The rest of this method is just collecting histograms.
-
- base::TimeTicks time = base::TimeTicks::Now();
- ClientState current_state = scheduler_->GetClientState(client_id_);
- // Note: the client state isn't perfectly accurate since it won't capture
- // tabs which have switched between active and background multiple times.
- // Ex: A tab with the following transitions Active -> Background -> Active
- // will be recorded as Active.
- const char* client_state = "Other";
- if (current_state == client_state_on_creation_ && current_state == ACTIVE) {
- client_state = "Active";
- } else if (current_state == client_state_on_creation_ &&
- current_state == BACKGROUND) {
- client_state = "Background";
- }
-
- base::TimeDelta time_was_deferred = base::TimeDelta::FromMicroseconds(0);
- if (was_deferred)
- time_was_deferred = time - time_deferred_;
- PostHistogram("RequestTimeDeferred", client_state, NULL, time_was_deferred);
- PostHistogram("RequestTimeThrottled", client_state, NULL,
- time - request_->creation_time());
- // TODO(aiolos): Remove one of the above histograms after gaining an
- // understanding of the difference between them and which one is more
- // interesting.
}
void set_request_priority_params(const RequestPriorityParams& priority) {
@@ -313,13 +243,11 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
// ResourceThrottle interface:
void WillStartRequest(bool* defer) override {
deferred_ = *defer = !ready_;
- time_deferred_ = base::TimeTicks::Now();
}
const char* GetNameForLogging() const override { return "ResourceScheduler"; }
const ClientId client_id_;
- const ResourceScheduler::ClientState client_state_on_creation_;
net::URLRequest* request_;
bool ready_;
bool deferred_;
@@ -328,7 +256,6 @@ class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
ResourceScheduler* scheduler_;
RequestPriorityParams priority_;
uint32_t fifo_ordering_;
- base::TimeTicks time_deferred_;
base::WeakPtrFactory<ResourceScheduler::ScheduledResourceRequest>
weak_ptr_factory_;
@@ -365,29 +292,15 @@ void ResourceScheduler::RequestQueue::Insert(
// Each client represents a tab.
class ResourceScheduler::Client {
public:
- explicit Client(ResourceScheduler* scheduler,
- bool is_visible,
- bool is_audible)
- : is_audible_(is_audible),
- is_visible_(is_visible),
- is_loaded_(false),
- is_paused_(false),
+ explicit Client(ResourceScheduler* scheduler)
+ : is_loaded_(false),
has_html_body_(false),
using_spdy_proxy_(false),
- load_started_time_(base::TimeTicks::Now()),
scheduler_(scheduler),
in_flight_delayable_count_(0),
- total_layout_blocking_count_(0),
- throttle_state_(ResourceScheduler::THROTTLED) {}
-
- ~Client() {
- // Update to default state and pause to ensure the scheduler has a
- // correct count of relevant types of clients.
- is_visible_ = false;
- is_audible_ = false;
- is_paused_ = true;
- UpdateThrottleState();
- }
+ total_layout_blocking_count_(0) {}
+
+ ~Client() {}
void ScheduleRequest(net::URLRequest* url_request,
ScheduledResourceRequest* request) {
@@ -415,10 +328,9 @@ class ResourceScheduler::Client {
RequestSet StartAndRemoveAllRequests() {
// First start any pending requests so that they will be moved into
// in_flight_requests_. This may exceed the limits
- // kDefaultMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost
- // and kMaxNumThrottledRequestsPerClient, so this method must not do
- // anything that depends on those limits before calling
- // ClearInFlightRequests() below.
+ // kDefaultMaxNumDelayableRequestsPerClient and
+ // kMaxNumDelayableRequestsPerHost, so this method must not do anything that
+ // depends on those limits before calling ClearInFlightRequests() below.
while (!pending_requests_.IsEmpty()) {
ScheduledResourceRequest* request =
*pending_requests_.GetNextHighestIterator();
@@ -437,102 +349,10 @@ class ResourceScheduler::Client {
return unowned_requests;
}
- bool is_active() const { return is_visible_ || is_audible_; }
-
bool is_loaded() const { return is_loaded_; }
- bool is_visible() const { return is_visible_; }
-
- void OnAudibilityChanged(bool is_audible) {
- UpdateState(is_audible, &is_audible_);
- }
-
- void OnVisibilityChanged(bool is_visible) {
- UpdateState(is_visible, &is_visible_);
- }
-
- // Function to update any client state variable used to determine whether a
- // Client is active or background. Used for is_visible_ and is_audible_.
- void UpdateState(bool new_state, bool* current_state) {
- bool was_active = is_active();
- *current_state = new_state;
- if (was_active == is_active())
- return;
- last_active_switch_time_ = base::TimeTicks::Now();
- UpdateThrottleState();
- }
-
void OnLoadingStateChanged(bool is_loaded) {
- if (is_loaded == is_loaded_) {
- return;
- }
is_loaded_ = is_loaded;
- UpdateThrottleState();
- if (!is_loaded_) {
- load_started_time_ = base::TimeTicks::Now();
- last_active_switch_time_ = base::TimeTicks();
- return;
- }
- base::TimeTicks cur_time = base::TimeTicks::Now();
- const char* num_clients =
- GetNumClientsString(scheduler_->client_map_.size());
- const char* client_catagory = "Other";
- if (last_active_switch_time_.is_null()) {
- client_catagory = is_active() ? "Active" : "Background";
- } else if (is_active()) {
- base::TimeDelta time_since_active = cur_time - last_active_switch_time_;
- PostHistogram("ClientLoadedTime", "Other.SwitchedToActive", NULL,
- time_since_active);
- PostHistogram("ClientLoadedTime", "Other.SwitchedToActive", num_clients,
- time_since_active);
- }
- base::TimeDelta time_since_load_started = cur_time - load_started_time_;
- PostHistogram("ClientLoadedTime", client_catagory, NULL,
- time_since_load_started);
- PostHistogram("ClientLoadedTime", client_catagory, num_clients,
- time_since_load_started);
- // TODO(aiolos): The above histograms will not take main resource load time
- // into account with PlzNavigate into account. The ResourceScheduler also
- // will load the main resources without a clients with the current logic.
- // Find a way to fix both of these issues.
- }
-
- void SetPaused() {
- is_paused_ = true;
- UpdateThrottleState();
- }
-
- void UpdateThrottleState() {
- ClientThrottleState old_throttle_state = throttle_state_;
- if (!scheduler_->should_throttle()) {
- SetThrottleState(UNTHROTTLED);
- } else if (is_active() && !is_loaded_) {
- SetThrottleState(ACTIVE_AND_LOADING);
- } else if (is_active()) {
- SetThrottleState(UNTHROTTLED);
- } else if (is_paused_) {
- SetThrottleState(PAUSED);
- } else if (!scheduler_->active_clients_loaded()) {
- SetThrottleState(THROTTLED);
- } else if (is_loaded_ && scheduler_->should_coalesce()) {
- SetThrottleState(COALESCED);
- } else if (!is_active()) {
- SetThrottleState(UNTHROTTLED);
- }
-
- if (throttle_state_ == old_throttle_state) {
- return;
- }
- if (throttle_state_ == ACTIVE_AND_LOADING) {
- scheduler_->IncrementActiveClientsLoading();
- } else if (old_throttle_state == ACTIVE_AND_LOADING) {
- scheduler_->DecrementActiveClientsLoading();
- }
- if (throttle_state_ == COALESCED) {
- scheduler_->IncrementCoalescedClients();
- } else if (old_throttle_state == COALESCED) {
- scheduler_->DecrementCoalescedClients();
- }
}
void OnNavigate() {
@@ -573,50 +393,6 @@ class ResourceScheduler::Client {
}
}
- // Called on Client creation, when a Client changes user observability,
- // possibly when all observable Clients have finished loading, and
- // possibly when this Client has finished loading.
- // State changes:
- // Client became observable.
- // any state -> UNTHROTTLED
- // Client is unobservable, but all observable clients finished loading.
- // THROTTLED -> UNTHROTTLED
- // Non-observable client finished loading.
- // THROTTLED || UNTHROTTLED -> COALESCED
- // Non-observable client, an observable client starts loading.
- // COALESCED -> THROTTLED
- // A COALESCED client will transition into UNTHROTTLED when the network is
- // woken up by a heartbeat and then transition back into COALESCED.
- void SetThrottleState(ResourceScheduler::ClientThrottleState throttle_state) {
- if (throttle_state == throttle_state_) {
- return;
- }
- throttle_state_ = throttle_state;
- if (throttle_state_ != PAUSED) {
- is_paused_ = false;
- }
- LoadAnyStartablePendingRequests();
- // TODO(aiolos): Stop any started but not inflght requests when
- // switching to stricter throttle state?
- }
-
- ResourceScheduler::ClientThrottleState throttle_state() const {
- return throttle_state_;
- }
-
- void LoadCoalescedRequests() {
- if (throttle_state_ != COALESCED) {
- return;
- }
- if (scheduler_->active_clients_loaded()) {
- SetThrottleState(UNTHROTTLED);
- } else {
- SetThrottleState(THROTTLED);
- }
- LoadAnyStartablePendingRequests();
- SetThrottleState(COALESCED);
- }
-
private:
enum ShouldStartReqResult {
DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
@@ -785,8 +561,6 @@ class ResourceScheduler::Client {
// All types of requests:
// * If an outstanding request limit is in place, only that number
// of requests may be in flight for a single client at the same time.
- //
- // ACTIVE_AND_LOADING and UNTHROTTLED Clients follow these rules:
// * Non-delayable, High-priority and request-priority capable requests are
// issued immediately.
// * Low priority requests are delayable.
@@ -798,21 +572,7 @@ class ResourceScheduler::Client {
// loading delayable requests.
// * Never exceed 10 delayable requests in flight per client.
// * Never exceed 6 delayable requests for a given host.
- //
- // THROTTLED Clients follow these rules:
- // * Non-delayable and request-priority-capable requests are issued
- // immediately.
- // * At most one non-request-priority-capable request will be issued per
- // THROTTLED Client
- // * If no high priority requests are in flight, start loading low priority
- // requests.
- //
- // COALESCED Clients never load requests, with the following exceptions:
- // * Non-delayable requests are issued imediately.
- // * On a (currently 5 second) heart beat, they load all requests as an
- // UNTHROTTLED Client, and then return to the COALESCED state.
- // * When an active Client makes a request, they are THROTTLED until the
- // active Client finishes loading.
+
ShouldStartReqResult ShouldStartRequest(
ScheduledResourceRequest* request) const {
const net::URLRequest& url_request = *request->url_request();
@@ -823,14 +583,9 @@ class ResourceScheduler::Client {
// TODO(simonjam): This may end up causing disk contention. We should
// experiment with throttling if that happens.
- // TODO(aiolos): We probably want to Coalesce these as well to avoid
- // waking the disk.
if (!url_request.url().SchemeIsHTTPOrHTTPS())
return START_REQUEST;
- if (throttle_state_ == COALESCED)
- return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
-
if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
return START_REQUEST;
@@ -851,13 +606,6 @@ class ResourceScheduler::Client {
if (http_server_properties.SupportsRequestPriority(host_port_pair))
return START_REQUEST;
- if (throttle_state_ == THROTTLED &&
- in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
- // There may still be request-priority-capable requests that should be
- // issued.
- return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
- }
-
// Non-delayable requests.
if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
return START_REQUEST;
@@ -949,52 +697,29 @@ class ResourceScheduler::Client {
}
}
- bool is_audible_;
- bool is_visible_;
bool is_loaded_;
- bool is_paused_;
// Tracks if the main HTML parser has reached the body which marks the end of
// layout-blocking resources.
bool has_html_body_;
bool using_spdy_proxy_;
RequestQueue pending_requests_;
RequestSet in_flight_requests_;
- base::TimeTicks load_started_time_;
- // The last time the client switched state between active and background.
- base::TimeTicks last_active_switch_time_;
ResourceScheduler* scheduler_;
// The number of delayable in-flight requests.
size_t in_flight_delayable_count_;
// The number of layout-blocking in-flight requests.
size_t total_layout_blocking_count_;
- ResourceScheduler::ClientThrottleState throttle_state_;
};
ResourceScheduler::ResourceScheduler()
- : should_coalesce_(false),
- should_throttle_(false),
- active_clients_loading_(0),
- coalesced_clients_(0),
- limit_outstanding_requests_(false),
+ : limit_outstanding_requests_(false),
outstanding_request_limit_(0),
- non_delayable_threshold_(
- kDefaultLayoutBlockingPriorityThreshold),
+ non_delayable_threshold_(kDefaultLayoutBlockingPriorityThreshold),
enable_in_flight_non_delayable_threshold_(false),
in_flight_non_delayable_threshold_(0),
max_num_delayable_while_layout_blocking_(
kDefaultMaxNumDelayableWhileLayoutBlocking),
- max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient),
- coalescing_timer_(new base::Timer(true /* retain_user_task */,
- true /* is_repeating */)) {
- std::string throttling_trial_group =
- base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial);
- if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) {
- should_throttle_ = true;
- } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) {
- should_coalesce_ = true;
- should_throttle_ = true;
- }
-
+ max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient) {
std::string outstanding_limit_trial_group =
base::FieldTrialList::FindFullName(kRequestLimitFieldTrial);
std::vector<std::string> split_group(
@@ -1051,30 +776,17 @@ ResourceScheduler::~ResourceScheduler() {
DCHECK(client_map_.empty());
}
-void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
- bool should_coalesce) {
- should_coalesce_ = should_coalesce;
- should_throttle_ = should_throttle;
- OnLoadingActiveClientsStateChangedForAllClients();
-}
-
-ResourceScheduler::ClientThrottleState
-ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) {
- Client* client = GetClient(child_id, route_id);
- DCHECK(client);
- return client->throttle_state();
-}
-
-scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
+std::unique_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
int child_id,
int route_id,
bool is_async,
net::URLRequest* url_request) {
DCHECK(CalledOnValidThread());
ClientId client_id = MakeClientId(child_id, route_id);
- scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest(
- client_id, url_request, this,
- RequestPriorityParams(url_request->priority(), 0), is_async));
+ std::unique_ptr<ScheduledResourceRequest> request(
+ new ScheduledResourceRequest(
+ client_id, url_request, this,
+ RequestPriorityParams(url_request->priority(), 0), is_async));
ClientMap::iterator it = client_map_.find(client_id);
if (it == client_map_.end()) {
@@ -1109,17 +821,13 @@ void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
}
void ResourceScheduler::OnClientCreated(int child_id,
- int route_id,
- bool is_visible,
- bool is_audible) {
+ int route_id) {
DCHECK(CalledOnValidThread());
ClientId client_id = MakeClientId(child_id, route_id);
DCHECK(!ContainsKey(client_map_, client_id));
- Client* client = new Client(this, is_visible, is_audible);
+ Client* client = new Client(this);
client_map_[client_id] = client;
-
- client->UpdateThrottleState();
}
void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
@@ -1150,23 +858,6 @@ void ResourceScheduler::OnLoadingStateChanged(int child_id,
client->OnLoadingStateChanged(is_loaded);
}
-void ResourceScheduler::OnVisibilityChanged(int child_id,
- int route_id,
- bool is_visible) {
- Client* client = GetClient(child_id, route_id);
- DCHECK(client);
- client->OnVisibilityChanged(is_visible);
-}
-
-void ResourceScheduler::OnAudibilityChanged(int child_id,
- int route_id,
- bool is_audible) {
- Client* client = GetClient(child_id, route_id);
- // We might get this call after the client has been deleted.
- if (client)
- client->OnAudibilityChanged(is_audible);
-}
-
void ResourceScheduler::OnNavigate(int child_id, int route_id) {
DCHECK(CalledOnValidThread());
ClientId client_id = MakeClientId(child_id, route_id);
@@ -1210,12 +901,6 @@ void ResourceScheduler::OnReceivedSpdyProxiedHttpResponse(
client->OnReceivedSpdyProxiedHttpResponse();
}
-bool ResourceScheduler::IsClientVisibleForTesting(int child_id, int route_id) {
- Client* client = GetClient(child_id, route_id);
- DCHECK(client);
- return client->is_visible();
-}
-
bool ResourceScheduler::HasLoadingClients() const {
for (const auto& client : client_map_) {
if (!client.second->is_loaded())
@@ -1234,100 +919,6 @@ ResourceScheduler::Client* ResourceScheduler::GetClient(int child_id,
return client_it->second;
}
-void ResourceScheduler::DecrementActiveClientsLoading() {
- DCHECK_NE(0u, active_clients_loading_);
- --active_clients_loading_;
- DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
- if (active_clients_loading_ == 0) {
- OnLoadingActiveClientsStateChangedForAllClients();
- }
-}
-
-void ResourceScheduler::IncrementActiveClientsLoading() {
- ++active_clients_loading_;
- DCHECK_EQ(active_clients_loading_, CountActiveClientsLoading());
- if (active_clients_loading_ == 1) {
- OnLoadingActiveClientsStateChangedForAllClients();
- }
-}
-
-void ResourceScheduler::OnLoadingActiveClientsStateChangedForAllClients() {
- ClientMap::iterator client_it = client_map_.begin();
- while (client_it != client_map_.end()) {
- Client* client = client_it->second;
- client->UpdateThrottleState();
- ++client_it;
- }
-}
-
-size_t ResourceScheduler::CountActiveClientsLoading() const {
- size_t active_and_loading = 0;
- ClientMap::const_iterator client_it = client_map_.begin();
- while (client_it != client_map_.end()) {
- Client* client = client_it->second;
- if (client->throttle_state() == ACTIVE_AND_LOADING) {
- ++active_and_loading;
- }
- ++client_it;
- }
- return active_and_loading;
-}
-
-void ResourceScheduler::IncrementCoalescedClients() {
- ++coalesced_clients_;
- DCHECK(should_coalesce_);
- DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
- if (coalesced_clients_ == 1) {
- coalescing_timer_->Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kCoalescedTimerPeriod),
- base::Bind(&ResourceScheduler::LoadCoalescedRequests,
- base::Unretained(this)));
- }
-}
-
-void ResourceScheduler::DecrementCoalescedClients() {
- DCHECK(should_coalesce_);
- DCHECK_NE(0U, coalesced_clients_);
- --coalesced_clients_;
- DCHECK_EQ(coalesced_clients_, CountCoalescedClients());
- if (coalesced_clients_ == 0) {
- coalescing_timer_->Stop();
- }
-}
-
-size_t ResourceScheduler::CountCoalescedClients() const {
- DCHECK(should_coalesce_);
- size_t coalesced_clients = 0;
- ClientMap::const_iterator client_it = client_map_.begin();
- while (client_it != client_map_.end()) {
- Client* client = client_it->second;
- if (client->throttle_state() == COALESCED) {
- ++coalesced_clients;
- }
- ++client_it;
- }
- return coalesced_clients_;
-}
-
-void ResourceScheduler::LoadCoalescedRequests() {
- DCHECK(should_coalesce_);
- ClientMap::iterator client_it = client_map_.begin();
- while (client_it != client_map_.end()) {
- Client* client = client_it->second;
- client->LoadCoalescedRequests();
- ++client_it;
- }
-}
-
-ResourceScheduler::ClientState ResourceScheduler::GetClientState(
- ClientId client_id) const {
- ClientMap::const_iterator client_it = client_map_.find(client_id);
- if (client_it == client_map_.end())
- return UNKNOWN;
- return client_it->second->is_active() ? ACTIVE : BACKGROUND;
-}
-
void ResourceScheduler::ReprioritizeRequest(net::URLRequest* request,
net::RequestPriority new_priority,
int new_intra_priority_value) {
diff --git a/chromium/content/browser/loader/resource_scheduler.h b/chromium/content/browser/loader/resource_scheduler.h
index 444d97d1693..a2f114a1a0e 100644
--- a/chromium/content/browser/loader/resource_scheduler.h
+++ b/chromium/content/browser/loader/resource_scheduler.h
@@ -9,13 +9,12 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <set>
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
-#include "base/timer/timer.h"
#include "content/common/content_export.h"
#include "net/base/priority_queue.h"
#include "net/base/request_priority.h"
@@ -56,62 +55,22 @@ class ResourceThrottle;
// the URLRequest.
class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
public:
- enum ClientThrottleState {
- // TODO(aiolos): Add logic to ShouldStartRequest for PAUSED Clients to only
- // issue synchronous requests.
- // TODO(aiolos): Add max number of THROTTLED Clients, and logic to set
- // subsquent Clients to PAUSED instead. Also add logic to unpause a Client
- // when a background Client becomes COALESCED (ie, finishes loading.)
- // TODO(aiolos): Add tests for the above mentioned logic.
-
- // Currently being deleted client.
- // This state currently follows the same logic for loading requests as
- // UNTHROTTLED/ACTIVE_AND_LOADING Clients. See above TODO's.
- PAUSED,
- // Loaded background client, all observable clients loaded.
- COALESCED,
- // Background client, an observable client is loading.
- THROTTLED,
- // Observable (active) loaded client or
- // Loading background client, all observable clients loaded.
- // Note that clients which would be COALESCED are UNTHROTTLED until
- // coalescing is turned on.
- UNTHROTTLED,
- // Observable (active) loading client.
- ACTIVE_AND_LOADING,
- };
-
ResourceScheduler();
~ResourceScheduler();
- // Use a mock timer when testing.
- void set_timer_for_testing(scoped_ptr<base::Timer> timer) {
- coalescing_timer_.reset(timer.release());
- }
-
- // TODO(aiolos): Remove when throttling and coalescing have landed
- void SetThrottleOptionsForTesting(bool should_throttle, bool should_coalesce);
-
- bool should_coalesce() const { return should_coalesce_; }
- bool should_throttle() const { return should_throttle_; }
-
- ClientThrottleState GetClientStateForTesting(int child_id, int route_id);
-
// Requests that this ResourceScheduler schedule, and eventually loads, the
// specified |url_request|. Caller should delete the returned ResourceThrottle
// when the load completes or is canceled, before |url_request| is deleted.
- scoped_ptr<ResourceThrottle> ScheduleRequest(int child_id,
- int route_id,
- bool is_async,
- net::URLRequest* url_request);
+ std::unique_ptr<ResourceThrottle> ScheduleRequest(
+ int child_id,
+ int route_id,
+ bool is_async,
+ net::URLRequest* url_request);
// Signals from the UI thread, posted as tasks on the IO thread:
// Called when a renderer is created.
- void OnClientCreated(int child_id,
- int route_id,
- bool is_visible,
- bool is_audible);
+ void OnClientCreated(int child_id, int route_id);
// Called when a renderer is destroyed.
void OnClientDeleted(int child_id, int route_id);
@@ -119,12 +78,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// Called when a renderer stops or restarts loading.
void OnLoadingStateChanged(int child_id, int route_id, bool is_loaded);
- // Called when a Client is shown or hidden.
- void OnVisibilityChanged(int child_id, int route_id, bool is_visible);
-
- // Called when a Client starts or stops playing audio.
- void OnAudibilityChanged(int child_id, int route_id, bool is_audible);
-
// Signals from IPC messages directly from the renderers:
// Called when a client navigates to a new main document.
@@ -142,11 +95,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// Client functions:
- // Called to check if all user observable tabs have completed loading.
- bool active_clients_loaded() const { return active_clients_loading_ == 0; }
-
- bool IsClientVisibleForTesting(int child_id, int route_id);
-
// Returns true if at least one client is currently loading.
bool HasLoadingClients() const;
@@ -203,15 +151,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
return max_num_delayable_requests_;
}
- enum ClientState {
- // Observable client.
- ACTIVE,
- // Non-observable client.
- BACKGROUND,
- // No client found.
- UNKNOWN,
- };
-
class RequestQueue;
class ScheduledResourceRequest;
struct RequestPriorityParams;
@@ -228,42 +167,13 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// Called when a ScheduledResourceRequest is destroyed.
void RemoveRequest(ScheduledResourceRequest* request);
- // These calls may update the ThrottleState of all clients, and have the
- // potential to be re-entrant.
- // Called when a Client newly becomes active loading.
- void IncrementActiveClientsLoading();
- // Called when an active and loading Client either completes loading or
- // becomes inactive.
- void DecrementActiveClientsLoading();
-
- void OnLoadingActiveClientsStateChangedForAllClients();
-
- size_t CountActiveClientsLoading() const;
-
- // Called when a Client becomes coalesced.
- void IncrementCoalescedClients();
- // Called when a client stops being coalesced.
- void DecrementCoalescedClients();
-
- void LoadCoalescedRequests();
-
- size_t CountCoalescedClients() const;
-
- // Returns UNKNOWN if the corresponding client is not found, else returns
- // whether the client is ACTIVE (user-observable) or BACKGROUND.
- ClientState GetClientState(ClientId client_id) const;
-
// Returns the client ID for the given |child_id| and |route_id| combo.
ClientId MakeClientId(int child_id, int route_id);
// Returns the client for the given |child_id| and |route_id| combo.
Client* GetClient(int child_id, int route_id);
- bool should_coalesce_;
- bool should_throttle_;
ClientMap client_map_;
- size_t active_clients_loading_;
- size_t coalesced_clients_;
bool limit_outstanding_requests_;
size_t outstanding_request_limit_;
net::RequestPriority non_delayable_threshold_;
@@ -271,8 +181,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
size_t in_flight_non_delayable_threshold_;
size_t max_num_delayable_while_layout_blocking_;
size_t max_num_delayable_requests_;
- // This is a repeating timer to initiate requests on COALESCED Clients.
- scoped_ptr<base::Timer> coalescing_timer_;
RequestSet unowned_requests_;
DISALLOW_COPY_AND_ASSIGN(ResourceScheduler);
diff --git a/chromium/content/browser/loader/resource_scheduler_unittest.cc b/chromium/content/browser/loader/resource_scheduler_unittest.cc
index 1399b52dde3..59b6d0055b9 100644
--- a/chromium/content/browser/loader/resource_scheduler_unittest.cc
+++ b/chromium/content/browser/loader/resource_scheduler_unittest.cc
@@ -46,13 +46,11 @@ const int kChildId2 = 43;
const int kRouteId2 = 67;
const int kBackgroundChildId = 35;
const int kBackgroundRouteId = 43;
-const int kBackgroundChildId2 = 54;
-const int kBackgroundRouteId2 = 82;
class TestRequest : public ResourceController {
public:
- TestRequest(scoped_ptr<net::URLRequest> url_request,
- scoped_ptr<ResourceThrottle> throttle,
+ TestRequest(std::unique_ptr<net::URLRequest> url_request,
+ std::unique_ptr<ResourceThrottle> throttle,
ResourceScheduler* scheduler)
: started_(false),
url_request_(std::move(url_request)),
@@ -94,19 +92,19 @@ class TestRequest : public ResourceController {
private:
bool started_;
- scoped_ptr<net::URLRequest> url_request_;
- scoped_ptr<ResourceThrottle> throttle_;
+ std::unique_ptr<net::URLRequest> url_request_;
+ std::unique_ptr<ResourceThrottle> throttle_;
ResourceScheduler* scheduler_;
};
class CancelingTestRequest : public TestRequest {
public:
- CancelingTestRequest(scoped_ptr<net::URLRequest> url_request,
- scoped_ptr<ResourceThrottle> throttle,
+ CancelingTestRequest(std::unique_ptr<net::URLRequest> url_request,
+ std::unique_ptr<ResourceThrottle> throttle,
ResourceScheduler* scheduler)
: TestRequest(std::move(url_request), std::move(throttle), scheduler) {}
- void set_request_to_cancel(scoped_ptr<TestRequest> request_to_cancel) {
+ void set_request_to_cancel(std::unique_ptr<TestRequest> request_to_cancel) {
request_to_cancel_ = std::move(request_to_cancel);
}
@@ -116,7 +114,7 @@ class CancelingTestRequest : public TestRequest {
request_to_cancel_.reset();
}
- scoped_ptr<TestRequest> request_to_cancel_;
+ std::unique_ptr<TestRequest> request_to_cancel_;
};
class FakeResourceContext : public ResourceContext {
@@ -148,16 +146,9 @@ class ResourceSchedulerTest : public testing::Test {
// mock_timer_.
scheduler_.reset(new ResourceScheduler());
- mock_timer_ = new base::MockTimer(true, true);
- scheduler_->set_timer_for_testing(scoped_ptr<base::Timer>(mock_timer_));
-
- // TODO(aiolos): Remove when throttling and coalescing have both landed.
- scheduler_->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
-
- scheduler_->OnClientCreated(kChildId, kRouteId, true, false);
+ scheduler_->OnClientCreated(kChildId, kRouteId);
scheduler_->OnClientCreated(
- kBackgroundChildId, kBackgroundRouteId, false, false);
+ kBackgroundChildId, kBackgroundRouteId);
}
void CleanupScheduler() {
@@ -171,23 +162,22 @@ class ResourceSchedulerTest : public testing::Test {
// as the argument to kForceFieldTrials.
bool InitializeFieldTrials(const std::string& force_field_trial_argument) {
return base::FieldTrialList::CreateTrialsFromString(
- force_field_trial_argument,
- base::FieldTrialList::DONT_ACTIVATE_TRIALS,
- std::set<std::string>());
+ force_field_trial_argument, std::set<std::string>());
}
- scoped_ptr<net::URLRequest> NewURLRequestWithChildAndRoute(
+ std::unique_ptr<net::URLRequest> NewURLRequestWithChildAndRoute(
const char* url,
net::RequestPriority priority,
int child_id,
int route_id) {
- scoped_ptr<net::URLRequest> url_request(
+ std::unique_ptr<net::URLRequest> url_request(
context_.CreateRequest(GURL(url), priority, NULL));
return url_request;
}
- scoped_ptr<net::URLRequest> NewURLRequest(const char* url,
- net::RequestPriority priority) {
+ std::unique_ptr<net::URLRequest> NewURLRequest(
+ const char* url,
+ net::RequestPriority priority) {
return NewURLRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
}
@@ -236,9 +226,9 @@ class ResourceSchedulerTest : public testing::Test {
int child_id,
int route_id,
bool is_async) {
- scoped_ptr<net::URLRequest> url_request(
+ std::unique_ptr<net::URLRequest> url_request(
NewURLRequestWithChildAndRoute(url, priority, child_id, route_id));
- scoped_ptr<ResourceThrottle> throttle(scheduler_->ScheduleRequest(
+ std::unique_ptr<ResourceThrottle> throttle(scheduler_->ScheduleRequest(
child_id, route_id, is_async, url_request.get()));
TestRequest* request = new TestRequest(std::move(url_request),
std::move(throttle), scheduler());
@@ -265,7 +255,7 @@ class ResourceSchedulerTest : public testing::Test {
BrowserThreadImpl ui_thread_;
BrowserThreadImpl io_thread_;
ResourceDispatcherHostImpl rdh_;
- scoped_ptr<ResourceScheduler> scheduler_;
+ std::unique_ptr<ResourceScheduler> scheduler_;
base::FieldTrialList field_trial_list_;
base::MockTimer* mock_timer_;
net::HttpServerPropertiesImpl http_server_properties_;
@@ -273,14 +263,16 @@ class ResourceSchedulerTest : public testing::Test {
};
TEST_F(ResourceSchedulerTest, OneIsolatedLowRequest) {
- scoped_ptr<TestRequest> request(NewRequest("http://host/1", net::LOWEST));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/1", net::LOWEST));
EXPECT_TRUE(request->started());
}
TEST_F(ResourceSchedulerTest, OneLowLoadsUntilIdle) {
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
@@ -291,9 +283,10 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilIdle) {
}
TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInserted) {
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
@@ -310,9 +303,10 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInserted) {
}
TEST_F(ResourceSchedulerTest, OneLowLoadsUntilCriticalComplete) {
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
@@ -327,9 +321,10 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilCriticalComplete) {
}
TEST_F(ResourceSchedulerTest, LowDoesNotBlockCriticalComplete) {
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOW));
- scoped_ptr<TestRequest> lowest(NewRequest("http://host/lowest", net::LOWEST));
- scoped_ptr<TestRequest> lowest2(
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOW));
+ std::unique_ptr<TestRequest> lowest(
+ NewRequest("http://host/lowest", net::LOWEST));
+ std::unique_ptr<TestRequest> lowest2(
NewRequest("http://host/lowest", net::LOWEST));
EXPECT_TRUE(low->started());
EXPECT_TRUE(lowest->started());
@@ -343,11 +338,12 @@ TEST_F(ResourceSchedulerTest, LowDoesNotBlockCriticalComplete) {
TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
http_server_properties_.SetSupportsSpdy(
net::HostPortPair("spdyhost", 443), true);
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low_spdy(
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low_spdy(
NewRequest("https://spdyhost/low", net::LOWEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low_spdy->started());
EXPECT_TRUE(low->started());
@@ -362,9 +358,10 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
TEST_F(ResourceSchedulerTest, NavigationResetsState) {
scheduler()->OnWillInsertBody(kChildId, kRouteId);
scheduler()->OnNavigate(kChildId, kRouteId);
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
@@ -372,16 +369,18 @@ TEST_F(ResourceSchedulerTest, NavigationResetsState) {
TEST_F(ResourceSchedulerTest, BackgroundRequestStartsImmediately) {
const int route_id = 0; // Indicates a background request.
- scoped_ptr<TestRequest> request(NewRequestWithRoute("http://host/1",
- net::LOWEST, route_id));
+ std::unique_ptr<TestRequest> request(
+ NewRequestWithRoute("http://host/1", net::LOWEST, route_id));
EXPECT_TRUE(request->started());
}
TEST_F(ResourceSchedulerTest, StartMultipleLowRequestsWhenIdle) {
- scoped_ptr<TestRequest> high1(NewRequest("http://host/high1", net::HIGHEST));
- scoped_ptr<TestRequest> high2(NewRequest("http://host/high2", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high1(
+ NewRequest("http://host/high1", net::HIGHEST));
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high2", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high1->started());
EXPECT_TRUE(high2->started());
EXPECT_TRUE(low->started());
@@ -397,20 +396,24 @@ TEST_F(ResourceSchedulerTest, StartMultipleLowRequestsWhenIdle) {
}
TEST_F(ResourceSchedulerTest, CancelOtherRequestsWhileResuming) {
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low1(NewRequest("http://host/low1", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low1(
+ NewRequest("http://host/low1", net::LOWEST));
- scoped_ptr<net::URLRequest> url_request(
+ std::unique_ptr<net::URLRequest> url_request(
NewURLRequest("http://host/low2", net::LOWEST));
- scoped_ptr<ResourceThrottle> throttle(scheduler()->ScheduleRequest(
+ std::unique_ptr<ResourceThrottle> throttle(scheduler()->ScheduleRequest(
kChildId, kRouteId, true, url_request.get()));
- scoped_ptr<CancelingTestRequest> low2(new CancelingTestRequest(
+ std::unique_ptr<CancelingTestRequest> low2(new CancelingTestRequest(
std::move(url_request), std::move(throttle), scheduler()));
low2->Start();
- scoped_ptr<TestRequest> low3(NewRequest("http://host/low3", net::LOWEST));
+ std::unique_ptr<TestRequest> low3(
+ NewRequest("http://host/low3", net::LOWEST));
low2->set_request_to_cancel(std::move(low3));
- scoped_ptr<TestRequest> low4(NewRequest("http://host/low4", net::LOWEST));
+ std::unique_ptr<TestRequest> low4(
+ NewRequest("http://host/low4", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_FALSE(low2->started());
@@ -427,7 +430,8 @@ TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
scheduler()->OnWillInsertBody(kChildId, kRouteId);
// Throw in one high priority request to make sure that's not a factor.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
EXPECT_TRUE(high->started());
const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
@@ -440,10 +444,10 @@ TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
EXPECT_TRUE(lows_singlehost[i]->started());
}
- scoped_ptr<TestRequest> second_last_singlehost(NewRequest("http://host/last",
- net::LOWEST));
- scoped_ptr<TestRequest> last_singlehost(NewRequest("http://host/s_last",
- net::LOWEST));
+ std::unique_ptr<TestRequest> second_last_singlehost(
+ NewRequest("http://host/last", net::LOWEST));
+ std::unique_ptr<TestRequest> last_singlehost(
+ NewRequest("http://host/s_last", net::LOWEST));
EXPECT_FALSE(second_last_singlehost->started());
@@ -468,17 +472,19 @@ TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
EXPECT_TRUE(lows_different_host[i]->started());
}
- scoped_ptr<TestRequest> last_different_host(NewRequest("http://host_new/last",
- net::LOWEST));
+ std::unique_ptr<TestRequest> last_different_host(
+ NewRequest("http://host_new/last", net::LOWEST));
EXPECT_FALSE(last_different_host->started());
}
TEST_F(ResourceSchedulerTest, RaisePriorityAndStart) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
EXPECT_FALSE(request->started());
ChangeRequestPriority(request.get(), net::HIGHEST);
@@ -488,11 +494,13 @@ TEST_F(ResourceSchedulerTest, RaisePriorityAndStart) {
TEST_F(ResourceSchedulerTest, RaisePriorityInQueue) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
- scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
EXPECT_FALSE(request->started());
EXPECT_FALSE(idle->started());
@@ -518,11 +526,13 @@ TEST_F(ResourceSchedulerTest, RaisePriorityInQueue) {
TEST_F(ResourceSchedulerTest, LowerPriority) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
- scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
EXPECT_FALSE(request->started());
EXPECT_FALSE(idle->started());
@@ -551,11 +561,13 @@ TEST_F(ResourceSchedulerTest, LowerPriority) {
TEST_F(ResourceSchedulerTest, ReprioritizedRequestGoesToBackOfQueue) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
- scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
EXPECT_FALSE(request->started());
EXPECT_FALSE(idle->started());
@@ -584,8 +596,9 @@ TEST_F(ResourceSchedulerTest, ReprioritizedRequestGoesToBackOfQueue) {
TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
ScopedVector<TestRequest> lows;
@@ -594,7 +607,8 @@ TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
lows.push_back(NewRequest(url.c_str(), net::IDLE));
}
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
EXPECT_FALSE(request->started());
ChangeRequestPriority(request.get(), net::IDLE, 1);
@@ -609,58 +623,30 @@ TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
TEST_F(ResourceSchedulerTest, NonHTTPSchedulesImmediately) {
// Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> request(
+ std::unique_ptr<TestRequest> request(
NewRequest("chrome-extension://req", net::LOWEST));
EXPECT_TRUE(request->started());
}
-TEST_F(ResourceSchedulerTest, ActiveLoadingSyncSchedulesImmediately) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewSyncRequest("http://host/req", net::LOWEST));
- EXPECT_TRUE(request->started());
-}
-
-TEST_F(ResourceSchedulerTest, UnthrottledSyncSchedulesImmediately) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewBackgroundSyncRequest("http://host/req", net::LOWEST));
- EXPECT_TRUE(request->started());
-}
-
TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
EXPECT_FALSE(request->started());
scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(request->started());
- scoped_ptr<TestRequest> after(NewRequest("http://host/after", net::IDLE));
+ std::unique_ptr<TestRequest> after(
+ NewRequest("http://host/after", net::IDLE));
EXPECT_TRUE(after->started());
}
@@ -668,7 +654,7 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
scheduler()->OnWillInsertBody(kChildId, kRouteId);
const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
- scoped_ptr<TestRequest> low1_spdy(
+ std::unique_ptr<TestRequest> low1_spdy(
NewRequest("http://spdyhost1:8080/low", net::LOWEST));
// Cancel a request after we learn the server supports SPDY.
ScopedVector<TestRequest> lows;
@@ -676,7 +662,7 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
string url = "http://host" + base::IntToString(i) + "/low";
lows.push_back(NewRequest(url.c_str(), net::LOWEST));
}
- scoped_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
EXPECT_FALSE(low1->started());
http_server_properties_.SetSupportsSpdy(
net::HostPortPair("spdyhost1", 8080), true);
@@ -686,7 +672,7 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
low1.reset();
base::RunLoop().RunUntilIdle();
- scoped_ptr<TestRequest> low2_spdy(
+ std::unique_ptr<TestRequest> low2_spdy(
NewRequest("http://spdyhost2:8080/low", net::IDLE));
// Reprioritize a request after we learn the server supports SPDY.
EXPECT_TRUE(low2_spdy->started());
@@ -694,1565 +680,10 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
net::HostPortPair("spdyhost2", 8080), true);
ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
base::RunLoop().RunUntilIdle();
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(low2->started());
}
-TEST_F(ResourceSchedulerTest, ThrottledClientCreation) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_TRUE(scheduler()->should_throttle());
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
-
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, ActiveClientThrottleUpdateOnLoadingChange) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-}
-
-TEST_F(ResourceSchedulerTest, CoalesceBackgroundClientOnLoadCompletion) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-}
-
-TEST_F(ResourceSchedulerTest, UnthrottleBackgroundClientOnLoadingStarted) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, false);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-}
-
-TEST_F(ResourceSchedulerTest, OneRequestPerThrottledClient) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
-
- EXPECT_TRUE(high->started());
- EXPECT_FALSE(request->started());
-}
-
-TEST_F(ResourceSchedulerTest, UnthrottleNewlyVisibleClient) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
- EXPECT_FALSE(request->started());
-
- scheduler()->OnVisibilityChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(request->started());
-}
-
-TEST_F(ResourceSchedulerTest, UnthrottleNewlyAudibleClient) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
- EXPECT_FALSE(request->started());
-
- scheduler()->OnAudibilityChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(request->started());
-}
-
-TEST_F(ResourceSchedulerTest, VisibleClientStillUnthrottledOnAudabilityChange) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-}
-
-TEST_F(ResourceSchedulerTest, AudibleClientStillUnthrottledOnVisabilityChange) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-}
-
-TEST_F(ResourceSchedulerTest, ThrottledClientStartsNextHighestPriorityRequest) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
- // Lower priority request started first to test request prioritizaton.
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/high", net::IDLE));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
-
- EXPECT_FALSE(low->started());
- EXPECT_FALSE(high->started());
-
- request->Cancel();
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(high->started());
- EXPECT_FALSE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, ThrottledSpdyProxySchedulesImmediately) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
-
- EXPECT_FALSE(request->started());
-
- scheduler()->OnReceivedSpdyProxiedHttpResponse(kBackgroundChildId,
- kBackgroundRouteId);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->started());
-
- scoped_ptr<TestRequest> after(
- NewBackgroundRequest("http://host/after", net::IDLE));
- EXPECT_TRUE(after->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedClientIssuesNoRequests) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
-
- EXPECT_FALSE(high->started());
- EXPECT_FALSE(request->started());
-
- scheduler()->OnReceivedSpdyProxiedHttpResponse(kBackgroundChildId,
- kBackgroundRouteId);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(high->started());
-
- scoped_ptr<TestRequest> after(
- NewBackgroundRequest("http://host/after", net::HIGHEST));
- EXPECT_FALSE(after->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedSpdyProxyWaits) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("http://host/req", net::IDLE));
-
- EXPECT_FALSE(request->started());
-
- scheduler()->OnReceivedSpdyProxiedHttpResponse(kBackgroundChildId,
- kBackgroundRouteId);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(request->started());
-
- scoped_ptr<TestRequest> after(
- NewBackgroundRequest("http://host/after", net::IDLE));
- EXPECT_FALSE(after->started());
-}
-
-TEST_F(ResourceSchedulerTest, ThrottledNonHTTPSchedulesImmediately) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("chrome-extension://req", net::LOWEST));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedNonHTTPSchedulesImmediately) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewBackgroundRequest("chrome-extension://req", net::LOWEST));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, ThrottledSyncSchedulesImmediately) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewBackgroundSyncRequest("http://host/req", net::LOWEST));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedSyncSchedulesImmediately) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- // Dummies to enforce scheduling.
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- scoped_ptr<TestRequest> request(
- NewBackgroundSyncRequest("http://host/req", net::LOWEST));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(low->started());
- EXPECT_FALSE(high->started());
-}
-
-TEST_F(ResourceSchedulerTest, AllBackgroundClientsUnthrottle) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_FALSE(scheduler()->active_clients_loaded());
-
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
-}
-
-TEST_F(ResourceSchedulerTest,
- UnloadedClientVisibilityChangedCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
-
- // 1 visible, 3 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 2 visible, 2 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest,
- UnloadedClientAudibilityChangedCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
-
- // 1 audible, 3 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 2 audible, 2 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest,
- LoadedClientVisibilityChangedCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- // 1 visible, 3 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 2 visible, 2 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest,
- LoadedClientAudibilityChangedCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- // 1 audible, 3 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 2 audible, 2 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, UnloadedClientBecomesHiddenCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
-
- // 2 visible, 2 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 0 visible, 4 hidden
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, UnloadedClientBecomesSilentCorrectlyUnthrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, true);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- // 2 audible, 2 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 0 audible, 4 hidden
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, false);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, LoadedClientBecomesHiddenCorrectlyThrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- // 2 visible, 2 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 0 visible, 4 hidden
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible, 3 hidden
- scheduler()->OnVisibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, LoadedClientBecomesSilentCorrectlyThrottles) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, false, true);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, true);
- // 2 audible, 2 hidden
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 0 audible, 4 hidden
- scheduler()->OnAudibilityChanged(kChildId, kRouteId, false);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 audible, 3 hidden
- scheduler()->OnAudibilityChanged(kChildId2, kRouteId2, true);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, HiddenLoadedChangesCorrectlyStayThrottled) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
-
- // 1 visible and 2 hidden loading, 1 visible loaded
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible and 1 hidden loading, 1 visible and 1 hidden loaded
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible loading, 1 visible and 2 hidden loaded
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible and 1 hidden loading, 1 visible and 1 hidden loaded
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, PartialVisibleClientLoadedDoesNotUnthrottle) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
-
- // 2 visible loading, 1 hidden loading, 1 hidden loaded
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible and 1 hidden loaded, 1 visible and 1 hidden loading
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 2 visible loading, 1 hidden loading, 1 hidden loaded
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, FullVisibleLoadedCorrectlyUnthrottle) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
-
- // 1 visible and 1 hidden loaded, 1 visible and 1 hidden loading
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnLoadingStateChanged(kChildId2, kRouteId2, true);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- EXPECT_TRUE(high->started());
- EXPECT_FALSE(low->started());
-
- // 2 visible loaded, 1 hidden loading, 1 hidden loaded
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- // kBackgroundClientId unthrottling should unthrottle it's request.
- EXPECT_TRUE(low->started());
-
- // 1 visible and 1 hidden loaded, 1 visible and 1 hidden loading
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, false);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest,
- ActiveAndLoadingClientDeletedCorrectlyUnthrottle) {
- // TODO(aiolos): remove when throttling and coalescing have both landed
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- false /* should_coalesce */);
- scheduler()->OnClientCreated(kChildId2, kRouteId2, true, false);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
-
- // 1 visible and 1 hidden loaded, 1 visible and 1 hidden loading
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId2, kRouteId2));
-
- // 1 visible loaded, 1 hidden loading, 1 hidden loaded
- scheduler()->OnClientDeleted(kChildId2, kRouteId2);
- EXPECT_TRUE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- // 1 visible and 1 hidden loaded, 1 visible and 1 hidden loading
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, false);
- EXPECT_FALSE(scheduler()->active_clients_loaded());
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
-
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedClientCreationStartsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(mock_timer_->IsRunning());
-}
-
-TEST_F(ResourceSchedulerTest, ActiveLoadingClientLoadedAndHiddenStartsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- EXPECT_FALSE(mock_timer_->IsRunning());
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(mock_timer_->IsRunning());
-}
-
-TEST_F(ResourceSchedulerTest, ActiveLoadingClientHiddenAndLoadedStartsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::THROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- scheduler()->OnVisibilityChanged(kChildId, kRouteId, false);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kChildId, kRouteId));
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(mock_timer_->IsRunning());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedClientBecomesAudibleStopsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnAudibilityChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-}
-
-TEST_F(ResourceSchedulerTest, LastCoalescedClientDeletionStopsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnClientDeleted(kBackgroundChildId, kBackgroundRouteId);
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- // To avoid errors on test tear down.
- scheduler()->OnClientCreated(
- kBackgroundChildId, kBackgroundRouteId, false, false);
-}
-
-TEST_F(ResourceSchedulerTest, LastCoalescedClientStartsLoadingStopsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, false);
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, false);
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- // This is needed to avoid errors on test tear down.
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest, LastCoalescedClientBecomesVisibleStopsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnClientCreated(
- kBackgroundChildId2, kBackgroundRouteId2, false, false);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId2,
- kBackgroundRouteId2));
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnVisibilityChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnVisibilityChanged(
- kBackgroundChildId2, kBackgroundRouteId2, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- // To avoid errors on test tear down.
- scheduler()->OnClientDeleted(kBackgroundChildId2, kBackgroundRouteId2);
-}
-
-TEST_F(ResourceSchedulerTest,
- CoalescedClientBecomesLoadingAndVisibleStopsTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- EXPECT_FALSE(mock_timer_->IsRunning());
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(mock_timer_->IsRunning());
-
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, false);
- EXPECT_EQ(ResourceScheduler::UNTHROTTLED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-
- scheduler()->OnVisibilityChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::ACTIVE_AND_LOADING,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_FALSE(mock_timer_->IsRunning());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedRequestsIssueOnTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(scheduler()->active_clients_loaded());
-
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
- EXPECT_FALSE(high->started());
- EXPECT_FALSE(low->started());
-
- FireCoalescingTimer();
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(high->started());
- EXPECT_TRUE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedRequestsUnthrottleCorrectlyOnTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(scheduler()->active_clients_loaded());
-
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high3(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high4(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(
- NewBackgroundRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low3(
- NewBackgroundRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low4(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- http_server_properties_.SetSupportsSpdy(net::HostPortPair("spdyhost", 443),
- true);
- scoped_ptr<TestRequest> low_spdy(
- NewBackgroundRequest("https://spdyhost/low", net::LOW));
- scoped_ptr<TestRequest> sync_request(
- NewBackgroundSyncRequest("http://host/req", net::LOW));
- scoped_ptr<TestRequest> non_http_request(
- NewBackgroundRequest("chrome-extension://req", net::LOW));
-
- // Sync requests should issue immediately.
- EXPECT_TRUE(sync_request->started());
- // Non-http(s) requests should issue immediately.
- EXPECT_TRUE(non_http_request->started());
- // Nothing else should issue without a timer fire.
- EXPECT_FALSE(high->started());
- EXPECT_FALSE(high2->started());
- EXPECT_FALSE(high3->started());
- EXPECT_FALSE(high4->started());
- EXPECT_FALSE(low->started());
- EXPECT_FALSE(low2->started());
- EXPECT_FALSE(low3->started());
- EXPECT_FALSE(low4->started());
- EXPECT_FALSE(low_spdy->started());
-
- FireCoalescingTimer();
- base::RunLoop().RunUntilIdle();
-
- // All high priority requests should issue.
- EXPECT_TRUE(high->started());
- EXPECT_TRUE(high2->started());
- EXPECT_TRUE(high3->started());
- EXPECT_TRUE(high4->started());
- // There should only be one net::LOWEST priority request issued with
- // non-delayable requests in flight.
- EXPECT_TRUE(low->started());
- EXPECT_FALSE(low2->started());
- EXPECT_FALSE(low3->started());
- EXPECT_FALSE(low4->started());
- // Spdy-Enable requests should issue regardless of priority.
- EXPECT_TRUE(low_spdy->started());
-}
-
-TEST_F(ResourceSchedulerTest, CoalescedRequestsWaitForNextTimer) {
- scheduler()->SetThrottleOptionsForTesting(true /* should_throttle */,
- true /* should_coalesce */);
- scheduler()->OnLoadingStateChanged(kChildId, kRouteId, true);
- scheduler()->OnLoadingStateChanged(
- kBackgroundChildId, kBackgroundRouteId, true);
-
- EXPECT_EQ(ResourceScheduler::COALESCED,
- scheduler()->GetClientStateForTesting(kBackgroundChildId,
- kBackgroundRouteId));
- EXPECT_TRUE(scheduler()->active_clients_loaded());
-
- scoped_ptr<TestRequest> high(
- NewBackgroundRequest("http://host/high", net::HIGHEST));
- EXPECT_FALSE(high->started());
-
- FireCoalescingTimer();
- base::RunLoop().RunUntilIdle();
-
- scoped_ptr<TestRequest> high2(
- NewBackgroundRequest("http://host/high2", net::HIGHEST));
- scoped_ptr<TestRequest> low(
- NewBackgroundRequest("http://host/low", net::LOWEST));
-
- EXPECT_TRUE(high->started());
- EXPECT_FALSE(high2->started());
- EXPECT_FALSE(low->started());
-
- FireCoalescingTimer();
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(high->started());
- EXPECT_TRUE(high2->started());
- EXPECT_TRUE(low->started());
-}
-
-TEST_F(ResourceSchedulerTest, GetVisualSignalFromRenderViewHost) {
- scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory;
- scoped_ptr<TestRenderViewHostFactory> render_view_host_factory;
- scoped_ptr<TestBrowserContext> browser_context;
- scoped_ptr<TestWebContents> web_contents_1;
- scoped_ptr<TestWebContents> web_contents_2;
- render_process_host_factory.reset(new MockRenderProcessHostFactory());
- render_view_host_factory.reset(
- new TestRenderViewHostFactory(render_process_host_factory.get()));
-
- browser_context.reset(new TestBrowserContext());
- scoped_refptr<SiteInstance> site_instance_1 =
- SiteInstance::Create(browser_context.get());
- scoped_refptr<SiteInstance> site_instance_2 =
- SiteInstance::Create(browser_context.get());
- SiteInstanceImpl::set_render_process_host_factory(
- render_process_host_factory.get());
-
- web_contents_1.reset(
- TestWebContents::Create(browser_context.get(), site_instance_1.get()));
- web_contents_2.reset(
- TestWebContents::Create(browser_context.get(), site_instance_2.get()));
- base::RunLoop().RunUntilIdle();
-
- RenderViewHostImpl* rvh1 = web_contents_1->GetRenderViewHost();
- RenderViewHostImpl* rvh2 = web_contents_2->GetRenderViewHost();
- ResourceScheduler* scheduler = ResourceDispatcherHostImpl::Get()->scheduler();
-
- // Check initial visibility is set correctly.
- EXPECT_EQ(scheduler->IsClientVisibleForTesting(rvh1->GetProcess()->GetID(),
- rvh1->GetRoutingID()),
- !rvh1->GetWidget()->is_hidden());
- EXPECT_EQ(scheduler->IsClientVisibleForTesting(rvh2->GetProcess()->GetID(),
- rvh1->GetRoutingID()),
- !rvh2->GetWidget()->is_hidden());
-
- // 1 visible, 1 hidden.
- rvh1->GetWidget()->WasShown(ui::LatencyInfo());
- rvh2->GetWidget()->WasHidden();
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(scheduler->IsClientVisibleForTesting(rvh1->GetProcess()->GetID(),
- rvh1->GetRoutingID()));
- EXPECT_FALSE(scheduler->IsClientVisibleForTesting(rvh2->GetProcess()->GetID(),
- rvh2->GetRoutingID()));
-
- // Flip the visibility and check again.
- rvh1->GetWidget()->WasHidden();
- rvh2->GetWidget()->WasShown(ui::LatencyInfo());
- base::RunLoop().RunUntilIdle();
-
- EXPECT_FALSE(scheduler->IsClientVisibleForTesting(rvh1->GetProcess()->GetID(),
- rvh1->GetRoutingID()));
- EXPECT_TRUE(scheduler->IsClientVisibleForTesting(rvh2->GetProcess()->GetID(),
- rvh2->GetRoutingID()));
- // Clean up.
- web_contents_1.reset();
- web_contents_2.reset();
- base::RunLoop().RunUntilIdle();
-
- browser_context.reset();
- render_process_host_factory.reset();
-}
-
TEST_F(ResourceSchedulerTest, OustandingRequestLimitEnforced) {
const int kRequestLimit = 3;
ASSERT_TRUE(InitializeFieldTrials(
@@ -2308,9 +739,10 @@ TEST_F(ResourceSchedulerTest, OutstandingRequestLimitDelays) {
kRequestLimit)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_FALSE(low->started());
EXPECT_FALSE(low2->started());
@@ -2325,12 +757,12 @@ TEST_F(ResourceSchedulerTest, OutstandingRequestLimitDelays) {
// started at some point, or they will hang around forever and prevent other
// async revalidations to the same URL from being issued.
TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeleted) {
- scheduler_->OnClientCreated(kChildId2, kRouteId2, false, false);
- scoped_ptr<TestRequest> high(NewRequestWithChildAndRoute(
+ scheduler_->OnClientCreated(kChildId2, kRouteId2);
+ std::unique_ptr<TestRequest> high(NewRequestWithChildAndRoute(
"http://host/high", net::HIGHEST, kChildId2, kRouteId2));
- scoped_ptr<TestRequest> lowest1(NewRequestWithChildAndRoute(
+ std::unique_ptr<TestRequest> lowest1(NewRequestWithChildAndRoute(
"http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
- scoped_ptr<TestRequest> lowest2(NewRequestWithChildAndRoute(
+ std::unique_ptr<TestRequest> lowest2(NewRequestWithChildAndRoute(
"http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
EXPECT_FALSE(lowest2->started());
@@ -2346,8 +778,8 @@ TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeleted) {
// This test is to verify that requests will be started at some point
// even if they were not started by the destructor.
TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeletedManyDelayable) {
- scheduler_->OnClientCreated(kChildId2, kRouteId2, false, false);
- scoped_ptr<TestRequest> high(NewRequestWithChildAndRoute(
+ scheduler_->OnClientCreated(kChildId2, kRouteId2);
+ std::unique_ptr<TestRequest> high(NewRequestWithChildAndRoute(
"http://host/high", net::HIGHEST, kChildId2, kRouteId2));
const int kMaxNumDelayableRequestsPerClient = 10;
ScopedVector<TestRequest> delayable_requests;
@@ -2355,7 +787,7 @@ TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeletedManyDelayable) {
delayable_requests.push_back(NewRequestWithChildAndRoute(
"http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
}
- scoped_ptr<TestRequest> lowest(NewRequestWithChildAndRoute(
+ std::unique_ptr<TestRequest> lowest(NewRequestWithChildAndRoute(
"http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
EXPECT_FALSE(lowest->started());
@@ -2386,18 +818,19 @@ TEST_F(ResourceSchedulerTest, DefaultLayoutBlockingPriority) {
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(
+ std::unique_ptr<TestRequest> high(
NewRequest("http://hosthigh/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(
+ std::unique_ptr<TestRequest> high2(
NewRequest("http://hosthigh/high", net::HIGHEST));
- scoped_ptr<TestRequest> medium(
+ std::unique_ptr<TestRequest> medium(
NewRequest("http://hostmedium/medium", net::MEDIUM));
- scoped_ptr<TestRequest> medium2(
+ std::unique_ptr<TestRequest> medium2(
NewRequest("http://hostmedium/medium", net::MEDIUM));
- scoped_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW));
- scoped_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW));
- scoped_ptr<TestRequest> lowest(NewRequest("http://hostlowest/lowest", net::LOWEST));
- scoped_ptr<TestRequest> lowest2(
+ std::unique_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW));
+ std::unique_ptr<TestRequest> lowest(
+ NewRequest("http://hostlowest/lowest", net::LOWEST));
+ std::unique_ptr<TestRequest> lowest2(
NewRequest("http://hostlowest/lowest", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(high2->started());
@@ -2435,18 +868,19 @@ TEST_F(ResourceSchedulerTest, IncreaseLayoutBlockingPriority) {
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(
+ std::unique_ptr<TestRequest> high(
NewRequest("http://hosthigh/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(
+ std::unique_ptr<TestRequest> high2(
NewRequest("http://hosthigh/high", net::HIGHEST));
- scoped_ptr<TestRequest> medium(
+ std::unique_ptr<TestRequest> medium(
NewRequest("http://hostmedium/medium", net::MEDIUM));
- scoped_ptr<TestRequest> medium2(
+ std::unique_ptr<TestRequest> medium2(
NewRequest("http://hostmedium/medium", net::MEDIUM));
- scoped_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW));
- scoped_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW));
- scoped_ptr<TestRequest> lowest(NewRequest("http://hostlowest/lowest", net::LOWEST));
- scoped_ptr<TestRequest> lowest2(
+ std::unique_ptr<TestRequest> low(NewRequest("http://hostlow/low", net::LOW));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://hostlow/low", net::LOW));
+ std::unique_ptr<TestRequest> lowest(
+ NewRequest("http://hostlowest/lowest", net::LOWEST));
+ std::unique_ptr<TestRequest> lowest2(
NewRequest("http://hostlowest/lowest", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(high2->started());
@@ -2495,10 +929,12 @@ TEST_F(ResourceSchedulerTest, UseLayoutBlockingThresholdOne) {
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(high2->started());
EXPECT_FALSE(low->started());
@@ -2540,11 +976,14 @@ TEST_F(ResourceSchedulerTest, UseLayoutBlockingThresholdTwo) {
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high3(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> high3(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(high2->started());
EXPECT_TRUE(high3->started());
@@ -2588,10 +1027,11 @@ TEST_F(ResourceSchedulerTest, TwoDelayableLoadsUntilBodyInserted) {
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_TRUE(low2->started());
@@ -2627,11 +1067,13 @@ TEST_F(ResourceSchedulerTest,
kMaxNumDelayableWhileLayoutBlocking,
kMaxNumDelayableRequestsPerClient)));
InitializeScheduler();
- scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> high2(NewRequest("http://host/high", net::HIGHEST));
- scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
- scoped_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low3(NewRequest("http://host/low", net::LOWEST));
EXPECT_TRUE(high->started());
EXPECT_TRUE(high2->started());
EXPECT_FALSE(low->started());
@@ -2684,8 +1126,8 @@ TEST_F(ResourceSchedulerTest, TwentyMaxNumDelayableRequestsPerClient) {
EXPECT_TRUE(lows_different_host[i]->started());
}
- scoped_ptr<TestRequest> last_different_host(NewRequest("http://host_new/last",
- net::LOWEST));
+ std::unique_ptr<TestRequest> last_different_host(
+ NewRequest("http://host_new/last", net::LOWEST));
EXPECT_FALSE(last_different_host->started());
}
@@ -2725,8 +1167,8 @@ TEST_F(ResourceSchedulerTest,
EXPECT_TRUE(lows_different_host[i]->started());
}
- scoped_ptr<TestRequest> last_different_host(NewRequest("http://host_new/last",
- net::LOWEST));
+ std::unique_ptr<TestRequest> last_different_host(
+ NewRequest("http://host_new/last", net::LOWEST));
EXPECT_FALSE(last_different_host->started());
}
diff --git a/chromium/content/browser/loader/stream_resource_handler.h b/chromium/content/browser/loader/stream_resource_handler.h
index 6bc4253a2f3..42c71e8fb4b 100644
--- a/chromium/content/browser/loader/stream_resource_handler.h
+++ b/chromium/content/browser/loader/stream_resource_handler.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_STREAM_RESOURCE_HANDLER_H_
#define CONTENT_BROWSER_LOADER_STREAM_RESOURCE_HANDLER_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_handler.h"
#include "content/browser/loader/stream_writer.h"
diff --git a/chromium/content/browser/loader/temporary_file_stream.cc b/chromium/content/browser/loader/temporary_file_stream.cc
index c8bb3338f5c..bff6ed46268 100644
--- a/chromium/content/browser/loader/temporary_file_stream.cc
+++ b/chromium/content/browser/loader/temporary_file_stream.cc
@@ -20,15 +20,14 @@ namespace content {
namespace {
-void DidCreateTemporaryFile(
- const CreateTemporaryFileStreamCallback& callback,
- scoped_ptr<base::FileProxy> file_proxy,
- base::File::Error error_code,
- const base::FilePath& file_path) {
+void DidCreateTemporaryFile(const CreateTemporaryFileStreamCallback& callback,
+ std::unique_ptr<base::FileProxy> file_proxy,
+ base::File::Error error_code,
+ const base::FilePath& file_path) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!file_proxy->IsValid()) {
- callback.Run(error_code, scoped_ptr<net::FileStream>(), NULL);
+ callback.Run(error_code, std::unique_ptr<net::FileStream>(), NULL);
return;
}
@@ -42,7 +41,7 @@ void DidCreateTemporaryFile(
ShareableFileReference::DELETE_ON_FINAL_RELEASE,
task_runner.get());
- scoped_ptr<net::FileStream> file_stream(
+ std::unique_ptr<net::FileStream> file_stream(
new net::FileStream(file_proxy->TakeFile(), task_runner));
callback.Run(error_code, std::move(file_stream), deletable_file.get());
@@ -54,7 +53,7 @@ void CreateTemporaryFileStream(
const CreateTemporaryFileStreamCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- scoped_ptr<base::FileProxy> file_proxy(new base::FileProxy(
+ std::unique_ptr<base::FileProxy> file_proxy(new base::FileProxy(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get()));
base::FileProxy* proxy = file_proxy.get();
proxy->CreateTemporary(
diff --git a/chromium/content/browser/loader/temporary_file_stream.h b/chromium/content/browser/loader/temporary_file_stream.h
index 280359636d8..406fcc445ee 100644
--- a/chromium/content/browser/loader/temporary_file_stream.h
+++ b/chromium/content/browser/loader/temporary_file_stream.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_LOADER_TEMPORARY_FILE_STREAM_H_
#define CONTENT_BROWSER_LOADER_TEMPORARY_FILE_STREAM_H_
+#include <memory>
+
#include "base/callback_forward.h"
#include "base/files/file.h"
-#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
namespace net {
@@ -21,7 +22,7 @@ class ShareableFileReference;
namespace content {
typedef base::Callback<void(base::File::Error,
- scoped_ptr<net::FileStream>,
+ std::unique_ptr<net::FileStream>,
storage::ShareableFileReference*)>
CreateTemporaryFileStreamCallback;
diff --git a/chromium/content/browser/loader/temporary_file_stream_unittest.cc b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
index a5fe1453312..d492254ee69 100644
--- a/chromium/content/browser/loader/temporary_file_stream_unittest.cc
+++ b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
@@ -39,7 +39,7 @@ class WaitForFileStream {
}
void OnFileStreamCreated(base::File::Error error,
- scoped_ptr<net::FileStream> file_stream,
+ std::unique_ptr<net::FileStream> file_stream,
ShareableFileReference* deletable_file) {
error_ = error;
file_stream_ = std::move(file_stream);
@@ -58,7 +58,7 @@ class WaitForFileStream {
private:
base::RunLoop loop_;
base::File::Error error_;
- scoped_ptr<net::FileStream> file_stream_;
+ std::unique_ptr<net::FileStream> file_stream_;
scoped_refptr<ShareableFileReference> deletable_file_;
};
diff --git a/chromium/content/browser/loader/throttling_resource_handler.cc b/chromium/content/browser/loader/throttling_resource_handler.cc
index 93b9ad74836..99d84e65707 100644
--- a/chromium/content/browser/loader/throttling_resource_handler.cc
+++ b/chromium/content/browser/loader/throttling_resource_handler.cc
@@ -14,7 +14,7 @@
namespace content {
ThrottlingResourceHandler::ThrottlingResourceHandler(
- scoped_ptr<ResourceHandler> next_handler,
+ std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request,
ScopedVector<ResourceThrottle> throttles)
: LayeredResourceHandler(request, std::move(next_handler)),
diff --git a/chromium/content/browser/loader/throttling_resource_handler.h b/chromium/content/browser/loader/throttling_resource_handler.h
index 6abefc46e04..32cc6fa0c49 100644
--- a/chromium/content/browser/loader/throttling_resource_handler.h
+++ b/chromium/content/browser/loader/throttling_resource_handler.h
@@ -28,7 +28,7 @@ class ThrottlingResourceHandler : public LayeredResourceHandler,
public ResourceController {
public:
// Takes ownership of the ResourceThrottle instances.
- ThrottlingResourceHandler(scoped_ptr<ResourceHandler> next_handler,
+ ThrottlingResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
net::URLRequest* request,
ScopedVector<ResourceThrottle> throttles);
~ThrottlingResourceHandler() override;
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.cc b/chromium/content/browser/loader/upload_data_stream_builder.cc
index bcabe99484c..f6d614ae37b 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "content/browser/fileapi/upload_file_system_file_element_reader.h"
#include "content/common/resource_request_body.h"
@@ -75,20 +76,20 @@ class FileElementReader : public net::UploadFileElementReader {
} // namespace
-scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
+std::unique_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
ResourceRequestBody* body,
storage::BlobStorageContext* blob_context,
storage::FileSystemContext* file_system_context,
base::SingleThreadTaskRunner* file_task_runner) {
- std::vector<scoped_ptr<net::UploadElementReader>> element_readers;
+ std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
for (const auto& element : *body->elements()) {
switch (element.type()) {
case ResourceRequestBody::Element::TYPE_BYTES:
element_readers.push_back(
- make_scoped_ptr(new BytesElementReader(body, element)));
+ base::WrapUnique(new BytesElementReader(body, element)));
break;
case ResourceRequestBody::Element::TYPE_FILE:
- element_readers.push_back(make_scoped_ptr(
+ element_readers.push_back(base::WrapUnique(
new FileElementReader(body, file_task_runner, element)));
break;
case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
@@ -96,17 +97,17 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
// supplied a FileSystemContext.
DCHECK(file_system_context);
element_readers.push_back(
- make_scoped_ptr(new content::UploadFileSystemFileElementReader(
+ base::WrapUnique(new content::UploadFileSystemFileElementReader(
file_system_context, element.filesystem_url(), element.offset(),
element.length(), element.expected_modification_time())));
break;
case ResourceRequestBody::Element::TYPE_BLOB: {
DCHECK_EQ(std::numeric_limits<uint64_t>::max(), element.length());
DCHECK_EQ(0ul, element.offset());
- scoped_ptr<storage::BlobDataHandle> handle =
+ std::unique_ptr<storage::BlobDataHandle> handle =
blob_context->GetBlobDataFromUUID(element.blob_uuid());
element_readers.push_back(
- make_scoped_ptr(new storage::UploadBlobElementReader(
+ base::WrapUnique(new storage::UploadBlobElementReader(
std::move(handle), file_system_context, file_task_runner)));
break;
}
@@ -118,7 +119,7 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
}
}
- return make_scoped_ptr(new net::ElementsUploadDataStream(
+ return base::WrapUnique(new net::ElementsUploadDataStream(
std::move(element_readers), body->identifier()));
}
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.h b/chromium/content/browser/loader/upload_data_stream_builder.h
index abbcae822ce..fae5f3a70ca 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.h
+++ b/chromium/content/browser/loader/upload_data_stream_builder.h
@@ -5,7 +5,8 @@
#ifndef CONTENT_BROWSER_LOADER_UPLOAD_DATA_STREAM_BUILDER_H_
#define CONTENT_BROWSER_LOADER_UPLOAD_DATA_STREAM_BUILDER_H_
-#include "base/memory/scoped_ptr.h"
+#include <memory>
+
#include "content/common/content_export.h"
namespace base {
@@ -40,7 +41,7 @@ class CONTENT_EXPORT UploadDataStreamBuilder {
// |file_system_context| is used to create a FileStreamReader for files with
// filesystem URLs. |file_task_runner| is used to perform file operations
// when the data gets uploaded.
- static scoped_ptr<net::UploadDataStream> Build(
+ static std::unique_ptr<net::UploadDataStream> Build(
ResourceRequestBody* body,
storage::BlobStorageContext* blob_context,
storage::FileSystemContext* file_system_context,
diff --git a/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc b/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
index fc92cc185aa..6db17f6cd4d 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
@@ -52,7 +52,7 @@ TEST(UploadDataStreamBuilderTest, CreateUploadDataStream) {
BlobStorageContext context;
BlobDataBuilder builder(kBlob);
builder.AppendData(kBlobData);
- scoped_ptr<BlobDataHandle> handle = context.AddFinishedBlob(&builder);
+ std::unique_ptr<BlobDataHandle> handle = context.AddFinishedBlob(&builder);
request_body->AppendBytes(kData, arraysize(kData) - 1);
request_body->AppendFileRange(base::FilePath(kFilePath), kFileOffset,
@@ -60,9 +60,10 @@ TEST(UploadDataStreamBuilderTest, CreateUploadDataStream) {
request_body->AppendBlob(kBlob);
request_body->set_identifier(kIdentifier);
- scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
- request_body.get(), &context, NULL,
- base::ThreadTaskRunnerHandle::Get().get()));
+ std::unique_ptr<net::UploadDataStream> upload(
+ UploadDataStreamBuilder::Build(
+ request_body.get(), &context, NULL,
+ base::ThreadTaskRunnerHandle::Get().get()));
EXPECT_EQ(kIdentifier, upload->identifier());
ASSERT_TRUE(upload->GetElementReaders());
@@ -108,15 +109,17 @@ TEST(UploadDataStreamBuilderTest,
// A blob created from an empty file added several times.
const std::string blob_id("id-0");
- scoped_ptr<BlobDataBuilder> blob_data_builder(new BlobDataBuilder(blob_id));
+ std::unique_ptr<BlobDataBuilder> blob_data_builder(
+ new BlobDataBuilder(blob_id));
blob_data_builder->AppendFile(test_blob_path, 0, kZeroLength, blob_time);
- scoped_ptr<BlobDataHandle> handle =
+ std::unique_ptr<BlobDataHandle> handle =
blob_storage_context.AddFinishedBlob(blob_data_builder.get());
scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
- scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
- request_body.get(), &blob_storage_context, NULL,
- base::ThreadTaskRunnerHandle::Get().get()));
+ std::unique_ptr<net::UploadDataStream> upload(
+ UploadDataStreamBuilder::Build(
+ request_body.get(), &blob_storage_context, NULL,
+ base::ThreadTaskRunnerHandle::Get().get()));
request_body = new ResourceRequestBody();
request_body->AppendBlob(blob_id);
@@ -139,7 +142,7 @@ TEST(UploadDataStreamBuilderTest,
// Purposely (try to) read more than what is in the stream. If we try to
// read zero bytes then UploadDataStream::Read will fail a DCHECK.
int kBufferLength = kZeroLength + 1;
- scoped_ptr<char[]> buffer(new char[kBufferLength]);
+ std::unique_ptr<char[]> buffer(new char[kBufferLength]);
scoped_refptr<net::IOBuffer> io_buffer =
new net::WrappedIOBuffer(buffer.get());
net::TestCompletionCallback read_callback;
@@ -166,14 +169,15 @@ TEST(UploadDataStreamBuilderTest, ResetUploadStreamWithBlob) {
BlobStorageContext blob_storage_context;
BlobDataBuilder builder(kBlob);
builder.AppendData(kBlobData);
- scoped_ptr<BlobDataHandle> handle =
+ std::unique_ptr<BlobDataHandle> handle =
blob_storage_context.AddFinishedBlob(&builder);
request_body->AppendBlob(kBlob);
request_body->set_identifier(kIdentifier);
- scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
- request_body.get(), &blob_storage_context, nullptr,
- base::ThreadTaskRunnerHandle::Get().get()));
+ std::unique_ptr<net::UploadDataStream> upload(
+ UploadDataStreamBuilder::Build(
+ request_body.get(), &blob_storage_context, nullptr,
+ base::ThreadTaskRunnerHandle::Get().get()));
net::TestCompletionCallback init_callback;
ASSERT_EQ(net::OK, upload->Init(init_callback.callback()));
diff --git a/chromium/content/browser/mach_broker_mac.h b/chromium/content/browser/mach_broker_mac.h
index f5d50addc3e..32ff5d6e548 100644
--- a/chromium/content/browser/mach_broker_mac.h
+++ b/chromium/content/browser/mach_broker_mac.h
@@ -5,15 +5,11 @@
#ifndef CONTENT_BROWSER_MACH_BROKER_MAC_H_
#define CONTENT_BROWSER_MACH_BROKER_MAC_H_
-#include <mach/mach.h>
-
#include <map>
#include <string>
-#include "base/mac/dispatch_source_mach.h"
-#include "base/mac/scoped_mach_port.h"
+#include "base/mac/mach_port_broker.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/process/port_provider_mac.h"
#include "base/process/process_handle.h"
@@ -24,22 +20,12 @@
namespace content {
-// On OS X, the task port of a process is required to collect metrics about the
-// process, and to insert Mach ports into the process. Running |task_for_pid()|
-// is only allowed for privileged code. However, a process has port rights to
-// all its subprocesses, so let the browser's child processes send their Mach
-// port to the browser over IPC.
-//
-// Mach ports can only be sent over Mach IPC, not over the |socketpair()| that
-// the regular IPC system uses. Hence, the child processes open a Mach
-// connection shortly after launching and ipc their mach data to the browser
-// process. This data is kept in a global |MachBroker| object.
-//
-// Since this data arrives over a separate channel, it is not available
-// immediately after a child process has been started.
+// A global |MachBroker| singleton is used by content embedders to provide
+// access to mach task ports for content child processes.
class CONTENT_EXPORT MachBroker : public base::PortProvider,
public BrowserChildProcessObserver,
- public NotificationObserver {
+ public NotificationObserver,
+ public base::PortProvider::Observer {
public:
// For use in child processes. This will send the task port of the current
// process over Mach IPC to the port registered by name (via this class) in
@@ -51,8 +37,7 @@ class CONTENT_EXPORT MachBroker : public base::PortProvider,
static MachBroker* GetInstance();
// The lock that protects this MachBroker object. Clients MUST acquire and
- // release this lock around calls to EnsureRunning(), PlaceholderForPid(),
- // and FinalizePid().
+ // release this lock around calls to EnsureRunning() and PlaceholderForPid().
base::Lock& GetLock();
// Performs any necessary setup that cannot happen in the constructor.
@@ -61,9 +46,8 @@ class CONTENT_EXPORT MachBroker : public base::PortProvider,
void EnsureRunning();
// Adds a placeholder to the map for the given pid with MACH_PORT_NULL.
- // Callers are expected to later update the port with FinalizePid(). Callers
- // MUST acquire the lock given by GetLock() before calling this method (and
- // release the lock afterwards).
+ // Callers MUST acquire the lock given by GetLock() before calling this method
+ // (and release the lock afterwards).
void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id);
// Implement |base::PortProvider|.
@@ -91,18 +75,8 @@ class CONTENT_EXPORT MachBroker : public base::PortProvider,
MachBroker();
~MachBroker() override;
- // Performs any initialization work.
- bool Init();
-
- // Message handler that is invoked on |dispatch_source_| when an
- // incoming message needs to be received.
- void HandleRequest();
-
- // Updates the mapping for |pid| to include the given |mach_info|. Does
- // nothing if PlaceholderForPid() has not already been called for the given
- // |pid|. Callers MUST acquire the lock given by GetLock() before calling
- // this method (and release the lock afterwards).
- void FinalizePid(base::ProcessHandle pid, mach_port_t task_port);
+ // Implement |base::PortProvider::Observer|.
+ void OnReceivedTaskPort(base::ProcessHandle process) override;
// Removes all mappings belonging to |child_process_id| from the broker.
void InvalidateChildProcessId(int child_process_id);
@@ -117,23 +91,13 @@ class CONTENT_EXPORT MachBroker : public base::PortProvider,
// Accessed only on the UI thread.
NotificationRegistrar registrar_;
- // The Mach port on which the server listens.
- base::mac::ScopedMachReceiveRight server_port_;
-
- // The dispatch source and queue on which Mach messages will be received.
- scoped_ptr<base::DispatchSourceMach> dispatch_source_;
-
- // Stores mach info for every process in the broker.
- typedef std::map<base::ProcessHandle, mach_port_t> MachMap;
- MachMap mach_map_;
-
// Stores the Child process unique id (RenderProcessHost ID) for every
- // process.
+ // process. Protected by base::MachPortBroker::GetLock().
typedef std::map<int, base::ProcessHandle> ChildProcessIdMap;
ChildProcessIdMap child_process_id_map_;
- // Mutex that guards |mach_map_| and |child_process_id_map_|.
- mutable base::Lock lock_;
+ // Underlying port broker that receives and manages mach ports.
+ base::MachPortBroker broker_;
DISALLOW_COPY_AND_ASSIGN(MachBroker);
};
diff --git a/chromium/content/browser/mach_broker_mac.mm b/chromium/content/browser/mach_broker_mac.mm
index 4cf3bb6c77c..dfbf71f600b 100644
--- a/chromium/content/browser/mach_broker_mac.mm
+++ b/chromium/content/browser/mach_broker_mac.mm
@@ -4,18 +4,10 @@
#include "content/browser/mach_broker_mac.h"
-#include <bsm/libbsm.h>
-#include <servers/bootstrap.h>
-
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mach_logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
@@ -26,55 +18,12 @@
namespace content {
namespace {
+const char kBootstrapName[] = "rohitfork";
+}
-// Mach message structure used in the child as a sending message.
-struct MachBroker_ChildSendMsg {
- mach_msg_header_t header;
- mach_msg_body_t body;
- mach_msg_port_descriptor_t child_task_port;
-};
-
-// Complement to the ChildSendMsg, this is used in the parent for receiving
-// a message. Contains a message trailer with audit information.
-struct MachBroker_ParentRecvMsg : public MachBroker_ChildSendMsg {
- mach_msg_audit_trailer_t trailer;
-};
-
-} // namespace
-
+// static
bool MachBroker::ChildSendTaskPortToParent() {
- // Look up the named MachBroker port that's been registered with the
- // bootstrap server.
- mach_port_t parent_port;
- kern_return_t kr = bootstrap_look_up(bootstrap_port,
- const_cast<char*>(GetMachPortName().c_str()), &parent_port);
- if (kr != KERN_SUCCESS) {
- BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up";
- return false;
- }
- base::mac::ScopedMachSendRight scoped_right(parent_port);
-
- // Create the check in message. This will copy a send right on this process'
- // (the child's) task port and send it to the parent.
- MachBroker_ChildSendMsg msg;
- bzero(&msg, sizeof(msg));
- msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) |
- MACH_MSGH_BITS_COMPLEX;
- msg.header.msgh_remote_port = parent_port;
- msg.header.msgh_size = sizeof(msg);
- msg.body.msgh_descriptor_count = 1;
- msg.child_task_port.name = mach_task_self();
- msg.child_task_port.disposition = MACH_MSG_TYPE_PORT_SEND;
- msg.child_task_port.type = MACH_MSG_PORT_DESCRIPTOR;
-
- kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(msg),
- 0, MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "mach_msg";
- return false;
- }
-
- return true;
+ return base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapName);
}
MachBroker* MachBroker::GetInstance() {
@@ -83,11 +32,11 @@ MachBroker* MachBroker::GetInstance() {
}
base::Lock& MachBroker::GetLock() {
- return lock_;
+ return broker_.GetLock();
}
void MachBroker::EnsureRunning() {
- lock_.AssertAcquired();
+ GetLock().AssertAcquired();
if (initialized_)
return;
@@ -99,26 +48,21 @@ void MachBroker::EnsureRunning() {
BrowserThread::UI, FROM_HERE,
base::Bind(&MachBroker::RegisterNotifications, base::Unretained(this)));
- if (!Init()) {
+ if (!broker_.Init()) {
LOG(ERROR) << "Failed to initialize the MachListenerThreadDelegate";
}
}
void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid,
int child_process_id) {
- lock_.AssertAcquired();
+ GetLock().AssertAcquired();
- DCHECK_EQ(0u, mach_map_.count(pid));
- mach_map_[pid] = MACH_PORT_NULL;
+ broker_.AddPlaceholderForPid(pid);
child_process_id_map_[child_process_id] = pid;
}
mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
- base::AutoLock lock(lock_);
- MachBroker::MachMap::const_iterator it = mach_map_.find(pid);
- if (it == mach_map_.end())
- return MACH_PORT_NULL;
- return it->second;
+ return broker_.TaskForPid(pid);
}
void MachBroker::BrowserChildProcessHostDisconnected(
@@ -152,108 +96,29 @@ std::string MachBroker::GetMachPortName() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const bool is_child = command_line->HasSwitch(switches::kProcessType);
-
- // In non-browser (child) processes, use the parent's pid.
- const pid_t pid = is_child ? getppid() : getpid();
- return base::StringPrintf("%s.rohitfork.%d", base::mac::BaseBundleID(), pid);
+ return base::MachPortBroker::GetMachPortName(kBootstrapName, is_child);
}
-MachBroker::MachBroker() : initialized_(false) {
+MachBroker::MachBroker() : initialized_(false), broker_(kBootstrapName) {
+ broker_.AddObserver(this);
}
-MachBroker::~MachBroker() {}
-
-bool MachBroker::Init() {
- DCHECK(server_port_.get() == MACH_PORT_NULL);
-
- // Check in with launchd and publish the service name.
- mach_port_t port;
- kern_return_t kr =
- bootstrap_check_in(bootstrap_port, GetMachPortName().c_str(), &port);
- if (kr != KERN_SUCCESS) {
- BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in";
- return false;
- }
- server_port_.reset(port);
-
- // Start the dispatch source.
- std::string queue_name =
- base::StringPrintf("%s.MachBroker", base::mac::BaseBundleID());
- dispatch_source_.reset(new base::DispatchSourceMach(
- queue_name.c_str(), server_port_.get(), ^{ HandleRequest(); }));
- dispatch_source_->Resume();
-
- return true;
+MachBroker::~MachBroker() {
+ broker_.RemoveObserver(this);
}
-void MachBroker::HandleRequest() {
- MachBroker_ParentRecvMsg msg;
- bzero(&msg, sizeof(msg));
- msg.header.msgh_size = sizeof(msg);
- msg.header.msgh_local_port = server_port_.get();
-
- const mach_msg_option_t options = MACH_RCV_MSG |
- MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) |
- MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
-
- kern_return_t kr = mach_msg(&msg.header,
- options,
- 0,
- sizeof(msg),
- server_port_.get(),
- MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "mach_msg";
- return;
- }
-
- // Use the kernel audit information to make sure this message is from
- // a task that this process spawned. The kernel audit token contains the
- // unspoofable pid of the task that sent the message.
- //
- // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
- pid_t child_pid;
- audit_token_to_au32(msg.trailer.msgh_audit,
- NULL, NULL, NULL, NULL, NULL, &child_pid, NULL, NULL);
-
- mach_port_t child_task_port = msg.child_task_port.name;
-
- // Take the lock and update the broker information.
- base::AutoLock lock(GetLock());
- FinalizePid(child_pid, child_task_port);
-}
-
-void MachBroker::FinalizePid(base::ProcessHandle pid,
- mach_port_t task_port) {
- lock_.AssertAcquired();
-
- MachMap::iterator it = mach_map_.find(pid);
- if (it == mach_map_.end()) {
- // Do nothing for unknown pids.
- LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!";
- return;
- }
-
- DCHECK(it->second == MACH_PORT_NULL);
- if (it->second == MACH_PORT_NULL)
- it->second = task_port;
+void MachBroker::OnReceivedTaskPort(base::ProcessHandle process) {
+ NotifyObservers(process);
}
void MachBroker::InvalidateChildProcessId(int child_process_id) {
- base::AutoLock lock(lock_);
+ base::AutoLock lock(GetLock());
MachBroker::ChildProcessIdMap::iterator it =
child_process_id_map_.find(child_process_id);
if (it == child_process_id_map_.end())
return;
- MachMap::iterator mach_it = mach_map_.find(it->second);
- if (mach_it != mach_map_.end()) {
- kern_return_t kr = mach_port_deallocate(mach_task_self(),
- mach_it->second);
- MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
- mach_map_.erase(mach_it);
- }
+ broker_.InvalidatePid(it->second);
child_process_id_map_.erase(it);
}
diff --git a/chromium/content/browser/mach_broker_mac_unittest.cc b/chromium/content/browser/mach_broker_mac_unittest.cc
index 9ba50c31090..65eaa91a7c3 100644
--- a/chromium/content/browser/mach_broker_mac_unittest.cc
+++ b/chromium/content/browser/mach_broker_mac_unittest.cc
@@ -4,13 +4,28 @@
#include "content/browser/mach_broker_mac.h"
+#include "base/command_line.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
namespace content {
-class MachBrokerTest : public testing::Test {
+class MachBrokerTest : public testing::Test,
+ public base::PortProvider::Observer {
public:
+ MachBrokerTest()
+ : event_(true, false), received_process_(base::kNullProcessHandle) {
+ broker_.AddObserver(this);
+ }
+ ~MachBrokerTest() override {
+ broker_.RemoveObserver(this);
+ }
+
// Helper function to acquire/release locks and call |PlaceholderForPid()|.
void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id) {
base::AutoLock lock(broker_.GetLock());
@@ -25,59 +40,72 @@ class MachBrokerTest : public testing::Test {
return broker_.child_process_id_map_.count(child_process_id);
}
- // Helper function to acquire/release locks and call |FinalizePid()|.
- void FinalizePid(base::ProcessHandle pid,
- mach_port_t task_port) {
+ base::Process LaunchTestChild(const std::string& function,
+ int child_process_id) {
base::AutoLock lock(broker_.GetLock());
- broker_.FinalizePid(pid, task_port);
+ base::Process test_child_process = base::SpawnMultiProcessTestChild(
+ function, base::GetMultiProcessTestChildBaseCommandLine(),
+ base::LaunchOptions());
+ broker_.AddPlaceholderForPid(test_child_process.Handle(), child_process_id);
+ return test_child_process;
+ }
+
+ void WaitForChildExit(base::Process& process) {
+ int rv = -1;
+ ASSERT_TRUE(process.WaitForExitWithTimeout(
+ TestTimeouts::action_timeout(), &rv));
+ EXPECT_EQ(0, rv);
+ }
+
+ void WaitForTaskPort() {
+ event_.Wait();
+ }
+
+ // base::PortProvider::Observer:
+ void OnReceivedTaskPort(base::ProcessHandle process) override {
+ received_process_ = process;
+ event_.Signal();
}
protected:
MachBroker broker_;
+ base::WaitableEvent event_;
+ base::ProcessHandle received_process_;
+ TestBrowserThreadBundle thread_bundle_;
};
+MULTIPROCESS_TEST_MAIN(MachBrokerTestChild) {
+ CHECK(MachBroker::ChildSendTaskPortToParent());
+ return 0;
+}
+
TEST_F(MachBrokerTest, Locks) {
// Acquire and release the locks. Nothing bad should happen.
base::AutoLock lock(broker_.GetLock());
}
-TEST_F(MachBrokerTest, AddPlaceholderAndFinalize) {
- // Add a placeholder for PID 1.
- AddPlaceholderForPid(1, 1);
- EXPECT_EQ(0u, broker_.TaskForPid(1));
-
- // Finalize PID 1.
- FinalizePid(1, 100u);
- EXPECT_EQ(100u, broker_.TaskForPid(1));
-
- // Should be no entry for PID 2.
- EXPECT_EQ(0u, broker_.TaskForPid(2));
-}
-
-TEST_F(MachBrokerTest, InvalidateChildProcessId) {
- // Add a placeholder for PID 1 and child process id 50.
- AddPlaceholderForPid(1, 50);
- FinalizePid(1, 100u);
-
- EXPECT_EQ(100u, broker_.TaskForPid(1));
- InvalidateChildProcessId(50);
- EXPECT_EQ(0u, broker_.TaskForPid(1));
-}
-
-TEST_F(MachBrokerTest, ValidateChildProcessIdMap) {
- // Add a placeholder for PID 1 and child process id 50.
- AddPlaceholderForPid(1, 50);
- FinalizePid(1, 100u);
-
- EXPECT_EQ(1, GetChildProcessCount(50));
- InvalidateChildProcessId(50);
- EXPECT_EQ(0, GetChildProcessCount(50));
-}
-
-TEST_F(MachBrokerTest, FinalizeUnknownPid) {
- // Finalizing an entry for an unknown pid should not add it to the map.
- FinalizePid(1u, 100u);
- EXPECT_EQ(0u, broker_.TaskForPid(1u));
+TEST_F(MachBrokerTest, AddChildProcess) {
+ {
+ base::AutoLock lock(broker_.GetLock());
+ broker_.EnsureRunning();
+ }
+ base::Process child_process = LaunchTestChild("MachBrokerTestChild", 7);
+ WaitForTaskPort();
+ EXPECT_EQ(child_process.Handle(), received_process_);
+ WaitForChildExit(child_process);
+
+ EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
+ broker_.TaskForPid(child_process.Handle()));
+ EXPECT_EQ(1, GetChildProcessCount(7));
+
+ // Should be no entry for any other PID.
+ EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
+ broker_.TaskForPid(child_process.Handle() + 1));
+
+ InvalidateChildProcessId(7);
+ EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
+ broker_.TaskForPid(child_process.Handle()));
+ EXPECT_EQ(0, GetChildProcessCount(7));
}
} // namespace content
diff --git a/chromium/content/browser/media/OWNERS b/chromium/content/browser/media/OWNERS
index ea102ff5871..5d85067ee22 100644
--- a/chromium/content/browser/media/OWNERS
+++ b/chromium/content/browser/media/OWNERS
@@ -1,15 +1,6 @@
-dalecurtis@chromium.org
-ddorwin@chromium.org
-xhwang@chromium.org
-
-# WebRTC OWNERS.
-perkj@chromium.org
-tommi@chromium.org
+file://media/OWNERS
per-file midi_*=toyoshim@chromium.org
# For changes related to the tab media indicators.
per-file audio_stream_monitor*=miu@chromium.org
-
-# For WebRTC browser tests, etc.
-per-file *webrtc*browsertest*=phoglund@chromium.org
diff --git a/chromium/content/browser/media/android/OWNERS b/chromium/content/browser/media/android/OWNERS
index 99dc93e5d02..5abf5a186b9 100644
--- a/chromium/content/browser/media/android/OWNERS
+++ b/chromium/content/browser/media/android/OWNERS
@@ -1,4 +1 @@
qinmin@chromium.org
-
-per-file media_session*.*=avayvod@chromium.org
-per-file media_session*.*=mlamouri@chromium.org
diff --git a/chromium/content/browser/media/android/browser_demuxer_android.cc b/chromium/content/browser/media/android/browser_demuxer_android.cc
index 9da7170b36f..ed56bf7cea4 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.cc
+++ b/chromium/content/browser/media/android/browser_demuxer_android.cc
@@ -97,9 +97,9 @@ bool BrowserDemuxerAndroid::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-scoped_ptr<media::DemuxerAndroid> BrowserDemuxerAndroid::CreateDemuxer(
+std::unique_ptr<media::DemuxerAndroid> BrowserDemuxerAndroid::CreateDemuxer(
int demuxer_client_id) {
- return scoped_ptr<media::DemuxerAndroid>(
+ return std::unique_ptr<media::DemuxerAndroid>(
new Internal(this, demuxer_client_id));
}
diff --git a/chromium/content/browser/media/android/browser_demuxer_android.h b/chromium/content/browser/media/android/browser_demuxer_android.h
index f1b28d313e6..5ff37f0a3c3 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.h
+++ b/chromium/content/browser/media/android/browser_demuxer_android.h
@@ -32,7 +32,7 @@ class CONTENT_EXPORT BrowserDemuxerAndroid : public BrowserMessageFilter {
// Returns an uninitialized demuxer implementation associated with
// |demuxer_client_id|, which can be used to communicate with the real demuxer
// in the renderer process.
- scoped_ptr<media::DemuxerAndroid> CreateDemuxer(int demuxer_client_id);
+ std::unique_ptr<media::DemuxerAndroid> CreateDemuxer(int demuxer_client_id);
protected:
friend class base::RefCountedThreadSafe<BrowserDemuxerAndroid>;
diff --git a/chromium/content/browser/media/android/browser_media_player_manager.cc b/chromium/content/browser/media/android/browser_media_player_manager.cc
index 0622043448b..96f6fcde97c 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.cc
+++ b/chromium/content/browser/media/android/browser_media_player_manager.cc
@@ -10,7 +10,6 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/android/browser_demuxer_android.h"
#include "content/browser/media/android/media_resource_getter_impl.h"
-#include "content/browser/media/android/media_session.h"
#include "content/browser/media/android/media_throttler.h"
#include "content/browser/media/android/media_web_contents_observer_android.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -52,9 +51,6 @@ namespace content {
const int kMediaPlayerThreshold = 1;
const int kInvalidMediaPlayerId = -1;
-// Minimal duration of a media player in order to be considered as Content type.
-const int kMinimumDurationForContentInSeconds = 5;
-
static BrowserMediaPlayerManager::Factory g_factory = NULL;
static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
@@ -147,16 +143,13 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
case MEDIA_PLAYER_TYPE_URL: {
const std::string user_agent = GetContentClient()->GetUserAgent();
MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
- media_player_params.player_id,
- media_player_params.url,
- media_player_params.first_party_for_cookies,
- user_agent,
- hide_url_log,
+ media_player_params.player_id, media_player_params.url,
+ media_player_params.first_party_for_cookies, user_agent, hide_url_log,
this,
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
- media_player_params.frame_url,
- media_player_params.allow_credentials);
+ media_player_params.frame_url, media_player_params.allow_credentials,
+ media_player_params.media_session_id);
if (media_player_params.type == MEDIA_PLAYER_TYPE_REMOTE_ONLY)
return media_player_bridge;
@@ -193,20 +186,20 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
if (media::UseMediaThreadForMediaPlayback()) {
return new MediaCodecPlayer(
- media_player_params.player_id,
- weak_ptr_factory_.GetWeakPtr(),
+ media_player_params.player_id, weak_ptr_factory_.GetWeakPtr(),
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
- media_player_params.frame_url);
+ media_player_params.frame_url,
+ media_player_params.media_session_id);
} else {
return new MediaSourcePlayer(
- media_player_params.player_id,
- this,
+ media_player_params.player_id, this,
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
- media_player_params.frame_url);
+ media_player_params.frame_url,
+ media_player_params.media_session_id);
}
}
}
@@ -233,11 +226,10 @@ BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
for (MediaPlayerAndroid* player : players_)
player->DeleteOnCorrectThread();
- MediaSession::Get(web_contents())->RemovePlayers(this);
players_.weak_clear();
}
-void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
+void BrowserMediaPlayerManager::DidExitFullscreen(bool release_media_player) {
#if defined(USE_AURA)
// TODO(crbug.com/548024)
NOTIMPLEMENTED();
@@ -289,6 +281,13 @@ void BrowserMediaPlayerManager::SetVideoSurface(
if (empty_surface)
return;
+ // If we already know the size, set it now. Otherwise it will be set when the
+ // player gets it.
+ if (player->IsPlayerReady()) {
+ video_view_->OnVideoSizeChanged(player->GetVideoWidth(),
+ player->GetVideoHeight());
+ }
+
#if !defined(USE_AURA)
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
@@ -304,21 +303,16 @@ void BrowserMediaPlayerManager::OnMediaMetadataChanged(
Send(new MediaPlayerMsg_MediaMetadataChanged(
RoutingID(), player_id, duration, width, height, success));
if (fullscreen_player_id_ == player_id)
- video_view_->UpdateMediaMetadata();
+ video_view_->OnVideoSizeChanged(width, height);
}
void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
- MediaSession::Get(web_contents())->RemovePlayer(this, player_id);
-
- if (fullscreen_player_id_ == player_id)
- video_view_->OnPlaybackComplete();
}
void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
// Tell WebKit that the audio should be paused, then release all resources
Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
- MediaSession::Get(web_contents())->RemovePlayer(this, player_id);
ReleaseResources(player_id);
}
@@ -334,15 +328,6 @@ void BrowserMediaPlayerManager::OnSeekRequest(
Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
}
-void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() {
- for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
- it != players_.end(); ++it) {
- if ((*it)->player_id() == fullscreen_player_id_)
- fullscreen_player_is_released_ = true;
- (*it)->Release();
- }
-}
-
void BrowserMediaPlayerManager::OnSeekComplete(
int player_id,
const base::TimeDelta& current_time) {
@@ -409,36 +394,12 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
bool BrowserMediaPlayerManager::RequestPlay(int player_id,
base::TimeDelta duration,
bool has_audio) {
- if (!has_audio)
- return true;
-
- MediaSession::Type media_session_type =
- duration == base::TimeDelta() ||
- duration.InSeconds() > kMinimumDurationForContentInSeconds
- ? MediaSession::Type::Content
- : MediaSession::Type::Transient;
-
- bool succeeded = MediaSession::Get(web_contents())->AddPlayer(
- this, player_id, media_session_type);
- if (!succeeded)
- Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
- return succeeded;
-}
-
-void BrowserMediaPlayerManager::OnSuspend(int player_id) {
- MediaPlayerAndroid* player = GetPlayer(player_id);
- DCHECK(player);
-
- player->Pause(true);
- Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
-}
-
-void BrowserMediaPlayerManager::OnResume(int player_id) {
- MediaPlayerAndroid* player = GetPlayer(player_id);
- DCHECK(player);
-
- player->Start();
- Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), player_id));
+ DCHECK(player_id_to_delegate_id_map_.find(player_id) !=
+ player_id_to_delegate_id_map_.end());
+ return MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
+ ->RequestPlay(render_frame_host_,
+ player_id_to_delegate_id_map_[player_id], has_audio,
+ IsPlayingRemotely(player_id), duration);
}
#if defined(VIDEO_HOLE)
@@ -533,25 +494,29 @@ void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
if (external_video_surface_container_)
external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
#endif // defined(VIDEO_HOLE)
- if (video_view_.get()) {
+ if (video_view_) {
fullscreen_player_id_ = player_id;
video_view_->OpenVideo();
return;
- } else if (!ContentVideoView::GetInstance()) {
+ }
+
+ if (ContentVideoView::GetInstance()) {
// In Android WebView, two ContentViewCores could both try to enter
// fullscreen video, we just ignore the second one.
- video_view_.reset(new ContentVideoView(this));
- base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
- video_view_->GetJavaObject(base::android::AttachCurrentThread());
- if (!j_content_video_view.is_null()) {
- fullscreen_player_id_ = player_id;
- return;
- }
+ Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
+ return;
}
- // Force the second video to exit fullscreen.
- Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
- video_view_.reset();
+ // There's no ContentVideoView instance so create one.
+ video_view_.reset(new ContentVideoView(this, GetContentViewCore()));
+ base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
+ video_view_->GetJavaObject(base::android::AttachCurrentThread());
+ if (!j_content_video_view.is_null()) {
+ fullscreen_player_id_ = player_id;
+ } else {
+ Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
+ video_view_.reset();
+ }
#endif // defined(USE_AURA)
}
@@ -574,7 +539,7 @@ void BrowserMediaPlayerManager::OnInitialize(
if (!player)
return;
- AddPlayer(player);
+ AddPlayer(player, media_player_params.delegate_id);
}
void BrowserMediaPlayerManager::OnStart(int player_id) {
@@ -606,9 +571,6 @@ void BrowserMediaPlayerManager::OnPause(
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
player->Pause(is_media_related_action);
-
- if (is_media_related_action && !IsPlayingRemotely(player_id))
- MediaSession::Get(web_contents())->OnPlayerPaused(this, player_id);
}
void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
@@ -622,7 +584,6 @@ void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
}
void BrowserMediaPlayerManager::OnSuspendAndReleaseResources(int player_id) {
- MediaSession::Get(web_contents())->RemovePlayer(this, player_id);
ReleaseResources(player_id);
}
@@ -645,9 +606,12 @@ bool BrowserMediaPlayerManager::IsPlayingRemotely(int player_id) {
return false;
}
-void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
+void BrowserMediaPlayerManager::AddPlayer(
+ MediaPlayerAndroid* player, int delegate_id) {
DCHECK(!GetPlayer(player->player_id()));
players_.push_back(player);
+ player_id_to_delegate_id_map_[player->player_id()] =
+ delegate_id;
}
void BrowserMediaPlayerManager::DestroyPlayer(int player_id) {
@@ -659,11 +623,11 @@ void BrowserMediaPlayerManager::DestroyPlayer(int player_id) {
#endif
(*it)->DeleteOnCorrectThread();
players_.weak_erase(it);
- MediaSession::Get(web_contents())->RemovePlayer(this, player_id);
break;
}
}
active_players_.erase(player_id);
+ player_id_to_delegate_id_map_.erase(player_id);
}
void BrowserMediaPlayerManager::ReleaseResources(int player_id) {
@@ -674,8 +638,9 @@ void BrowserMediaPlayerManager::ReleaseResources(int player_id) {
fullscreen_player_is_released_ = true;
}
-scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
- int player_id, media::MediaPlayerAndroid* player) {
+std::unique_ptr<media::MediaPlayerAndroid>
+BrowserMediaPlayerManager::SwapPlayer(int player_id,
+ media::MediaPlayerAndroid* player) {
media::MediaPlayerAndroid* previous_player = NULL;
for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
it != players_.end(); ++it) {
@@ -684,12 +649,15 @@ scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
#if defined(VIDEO_HOLE)
ReleaseExternalSurface(player_id);
#endif
+ MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
+ ->DisconnectMediaSession(render_frame_host_,
+ player_id_to_delegate_id_map_[player_id]);
players_.weak_erase(it);
players_.push_back(player);
break;
}
}
- return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
+ return std::unique_ptr<media::MediaPlayerAndroid>(previous_player);
}
bool BrowserMediaPlayerManager::RequestDecoderResources(
diff --git a/chromium/content/browser/media/android/browser_media_player_manager.h b/chromium/content/browser/media/android/browser_media_player_manager.h
index 990d5e1f3c4..8bacb71b9d0 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.h
+++ b/chromium/content/browser/media/android/browser_media_player_manager.h
@@ -6,20 +6,20 @@
#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_PLAYER_MANAGER_H_
#include <map>
+#include <memory>
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/time/time.h"
#include "content/browser/android/content_video_view.h"
-#include "content/browser/media/android/media_session_observer.h"
#include "content/common/content_export.h"
#include "ipc/ipc_message.h"
#include "media/base/android/media_player_android.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_url_interceptor.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gl/android/scoped_java_surface.h"
#include "url/gurl.h"
namespace media {
@@ -44,7 +44,7 @@ class WebContents;
// process.
class CONTENT_EXPORT BrowserMediaPlayerManager
: public media::MediaPlayerManager,
- public MediaSessionObserver {
+ public ContentVideoView::Client {
public:
// Permits embedders to provide an extended version of the class.
typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*);
@@ -70,17 +70,14 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
~BrowserMediaPlayerManager() override;
- // Fullscreen video playback controls.
- virtual void ExitFullscreen(bool release_media_player);
- virtual void SetVideoSurface(gfx::ScopedJavaSurface surface);
+ // ContentVideoView::Client implementation.
+ void DidExitFullscreen(bool release_media_player) override;
+ void SetVideoSurface(gfx::ScopedJavaSurface surface) override;
// Called when browser player wants the renderer media element to seek.
// Any actual seek started by renderer will be handled by browser in OnSeek().
void OnSeekRequest(int player_id, const base::TimeDelta& time_to_seek);
- // Stops and releases every media managed by this class.
- void ReleaseAllMediaPlayers();
-
// media::MediaPlayerManager overrides.
void OnTimeUpdate(int player_id,
base::TimeDelta current_timestamp,
@@ -111,10 +108,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
void OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE)
- // MediaSessionObserver overrides.
- void OnSuspend(int player_id) override;
- void OnResume(int player_id) override;
-
// Message handlers.
virtual void OnEnterFullscreen(int player_id);
virtual void OnInitialize(
@@ -142,8 +135,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
WebContents* web_contents() const { return web_contents_; }
- // Adds a given player to the list.
- void AddPlayer(media::MediaPlayerAndroid* player);
+ // Adds a given player to the list. Not private to allow embedders
+ // to extend the manager and still utilize the base player management.
+ void AddPlayer(media::MediaPlayerAndroid* player, int delegate_id);
// Removes the player with the specified id.
void DestroyPlayer(int player_id);
@@ -154,7 +148,7 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// Replaces a player with the specified id with a given MediaPlayerAndroid
// object. This will also return the original MediaPlayerAndroid object that
// was replaced.
- scoped_ptr<media::MediaPlayerAndroid> SwapPlayer(
+ std::unique_ptr<media::MediaPlayerAndroid> SwapPlayer(
int player_id,
media::MediaPlayerAndroid* player);
@@ -214,10 +208,11 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// The fullscreen video view object or NULL if video is not played in
// fullscreen.
- scoped_ptr<ContentVideoView> video_view_;
+ std::unique_ptr<ContentVideoView> video_view_;
#if defined(VIDEO_HOLE)
- scoped_ptr<ExternalVideoSurfaceContainer> external_video_surface_container_;
+ std::unique_ptr<ExternalVideoSurfaceContainer>
+ external_video_surface_container_;
#endif
// Player ID of the fullscreen media player.
@@ -229,7 +224,11 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
WebContents* const web_contents_;
// Object for retrieving resources media players.
- scoped_ptr<media::MediaResourceGetter> media_resource_getter_;
+ std::unique_ptr<media::MediaResourceGetter> media_resource_getter_;
+
+ // Map of player IDs to delegate IDs for use with
+ // MediaWebContentsObserverAndroid.
+ std::map<int, int> player_id_to_delegate_id_map_;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<BrowserMediaPlayerManager> weak_ptr_factory_;
diff --git a/chromium/content/browser/media/android/browser_media_session_manager.cc b/chromium/content/browser/media/android/browser_media_session_manager.cc
index 146a60fe970..a7e5fd5bbfa 100644
--- a/chromium/content/browser/media/android/browser_media_session_manager.cc
+++ b/chromium/content/browser/media/android/browser_media_session_manager.cc
@@ -6,6 +6,8 @@
#include "content/common/media/media_session_messages_android.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/media_metadata.h"
namespace content {
@@ -23,6 +25,27 @@ void BrowserMediaSessionManager::OnDeactivate(int session_id, int request_id) {
Send(new MediaSessionMsg_DidDeactivate(GetRoutingID(), request_id));
}
+void BrowserMediaSessionManager::OnSetMetadata(
+ int session_id,
+ const MediaMetadata& insecure_metadata) {
+ // When receiving a MediaMetadata, the browser process can't trust that it is
+ // coming from a known and secure source. It must be processed accordingly.
+ MediaMetadata metadata;
+ metadata.title =
+ insecure_metadata.title.substr(0, MediaMetadata::kMaxIPCStringLength);
+ metadata.artist =
+ insecure_metadata.artist.substr(0, MediaMetadata::kMaxIPCStringLength);
+ metadata.album =
+ insecure_metadata.album.substr(0, MediaMetadata::kMaxIPCStringLength);
+
+ if (metadata != insecure_metadata) {
+ render_frame_host_->GetProcess()->ShutdownForBadMessage();
+ return;
+ }
+
+ NOTIMPLEMENTED();
+}
+
int BrowserMediaSessionManager::GetRoutingID() const {
return render_frame_host_->GetRoutingID();
}
diff --git a/chromium/content/browser/media/android/browser_media_session_manager.h b/chromium/content/browser/media/android/browser_media_session_manager.h
index 3b07b295816..b936ba03e55 100644
--- a/chromium/content/browser/media/android/browser_media_session_manager.h
+++ b/chromium/content/browser/media/android/browser_media_session_manager.h
@@ -14,6 +14,7 @@ class Message;
namespace content {
class RenderFrameHost;
+struct MediaMetadata;
class BrowserMediaSessionManager {
public:
@@ -22,6 +23,7 @@ class BrowserMediaSessionManager {
// Message handlers.
void OnActivate(int session_id, int request_id);
void OnDeactivate(int session_id, int request_id);
+ void OnSetMetadata(int session_id, const MediaMetadata& metadata);
int GetRoutingID() const;
diff --git a/chromium/content/browser/media/android/browser_surface_view_manager.cc b/chromium/content/browser/media/android/browser_surface_view_manager.cc
new file mode 100644
index 00000000000..f171a169944
--- /dev/null
+++ b/chromium/content/browser/media/android/browser_surface_view_manager.cc
@@ -0,0 +1,86 @@
+// 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 "content/browser/media/android/browser_surface_view_manager.h"
+
+#include "content/browser/android/child_process_launcher_android.h"
+#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/gpu/gpu_surface_tracker.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/media/surface_view_manager_messages_android.h"
+#include "content/public/browser/render_frame_host.h"
+#include "media/base/surface_manager.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+BrowserSurfaceViewManager::BrowserSurfaceViewManager(
+ RenderFrameHost* render_frame_host)
+ : render_frame_host_(render_frame_host),
+ surface_id_(media::SurfaceManager::kNoSurfaceID) {}
+
+BrowserSurfaceViewManager::~BrowserSurfaceViewManager() {}
+
+void BrowserSurfaceViewManager::SetVideoSurface(
+ gfx::ScopedJavaSurface surface) {
+ if (surface.IsEmpty()) {
+ DCHECK_NE(surface_id_, media::SurfaceManager::kNoSurfaceID);
+ GpuSurfaceTracker::Get()->RemoveSurface(surface_id_);
+ UnregisterViewSurface(surface_id_);
+ surface_id_ = media::SurfaceManager::kNoSurfaceID;
+ } else {
+ // We mainly use the surface tracker to allocate a surface id for us. The
+ // lookup will go through the Android specific path and get the java
+ // surface directly, so there's no need to add a valid native widget here.
+ surface_id_ = GpuSurfaceTracker::Get()->AddSurfaceForNativeWidget(
+ gfx::kNullAcceleratedWidget);
+ RegisterViewSurface(surface_id_, surface.j_surface().obj());
+ SendSurfaceID(surface_id_);
+ }
+}
+
+void BrowserSurfaceViewManager::DidExitFullscreen(bool release_media_player) {
+ DVLOG(3) << __FUNCTION__;
+ content_video_view_.reset();
+}
+
+void BrowserSurfaceViewManager::OnCreateFullscreenSurface(
+ const gfx::Size& video_natural_size) {
+ // It's valid to get this call if we already own the fullscreen view. We just
+ // return the existing surface id.
+ if (content_video_view_) {
+ // Send the surface now if we have it. Otherwise it will be returned by
+ // |SetVideoSurface|.
+ if (surface_id_ != media::SurfaceManager::kNoSurfaceID) {
+ SendSurfaceID(surface_id_);
+ OnNaturalSizeChanged(video_natural_size);
+ return;
+ }
+ }
+
+ // If we don't own the fullscreen view, but one exists, it means another
+ // WebContents has it. Ignore this request and return a null surface id.
+ if (ContentVideoView::GetInstance()) {
+ SendSurfaceID(media::SurfaceManager::kNoSurfaceID);
+ return;
+ }
+
+ ContentViewCore* cvc = ContentViewCore::FromWebContents(
+ WebContents::FromRenderFrameHost(render_frame_host_));
+ content_video_view_.reset(new ContentVideoView(this, cvc));
+ OnNaturalSizeChanged(video_natural_size);
+}
+
+void BrowserSurfaceViewManager::OnNaturalSizeChanged(const gfx::Size& size) {
+ if (content_video_view_)
+ content_video_view_->OnVideoSizeChanged(size.width(), size.height());
+}
+
+bool BrowserSurfaceViewManager::SendSurfaceID(int surface_id) {
+ return render_frame_host_->Send(
+ new SurfaceViewManagerMsg_FullscreenSurfaceCreated(
+ render_frame_host_->GetRoutingID(), surface_id));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/android/browser_surface_view_manager.h b/chromium/content/browser/media/android/browser_surface_view_manager.h
new file mode 100644
index 00000000000..2bff709c034
--- /dev/null
+++ b/chromium/content/browser/media/android/browser_surface_view_manager.h
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_
+#define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/browser/android/content_video_view.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// BrowserSurfaceViewManager creates and owns a ContentVideoView on behalf of
+// a fullscreen media player. Its SurfaceView is registered so that a decoder
+// in the GPU process can look it up and render to it.
+class CONTENT_EXPORT BrowserSurfaceViewManager
+ : public ContentVideoView::Client {
+ public:
+ explicit BrowserSurfaceViewManager(RenderFrameHost* render_frame_host);
+ ~BrowserSurfaceViewManager();
+
+ // ContentVideoView::Client overrides.
+ void SetVideoSurface(gfx::ScopedJavaSurface surface) override;
+ void DidExitFullscreen(bool release_media_player) override;
+
+ void OnCreateFullscreenSurface(const gfx::Size& video_natural_size);
+ void OnNaturalSizeChanged(const gfx::Size& size);
+
+ private:
+ // Send a message to return the surface id to the caller.
+ bool SendSurfaceID(int surface_id);
+
+ RenderFrameHost* const render_frame_host_;
+
+ // The surface id of the ContentVideoView surface.
+ int surface_id_;
+
+ // The fullscreen view that contains a SurfaceView.
+ std::unique_ptr<ContentVideoView> content_video_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserSurfaceViewManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_SURFACE_VIEW_MANAGER_H_
diff --git a/chromium/content/browser/media/android/media_resource_getter_impl.cc b/chromium/content/browser/media/android/media_resource_getter_impl.cc
index e0d6aff5129..473c5327ff2 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.cc
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.cc
@@ -54,7 +54,7 @@ static void RequestPlatformPathFromBlobURL(
ChromeBlobStorageContext* blob_storage_context =
GetChromeBlobStorageContextForResourceContext(resource_context);
- scoped_ptr<storage::BlobDataHandle> handle =
+ std::unique_ptr<storage::BlobDataHandle> handle =
blob_storage_context->context()->GetBlobDataFromPublicURL(url);
if (!handle) {
// There are plenty of cases where handle can be empty. The most trivial is
@@ -62,7 +62,7 @@ static void RequestPlatformPathFromBlobURL(
ReturnResultOnUIThread(callback, std::string());
return;
}
- scoped_ptr<storage::BlobDataSnapshot> data = handle->CreateSnapshot();
+ std::unique_ptr<storage::BlobDataSnapshot> data = handle->CreateSnapshot();
if (!data) {
ReturnResultOnUIThread(callback, std::string());
NOTREACHED();
diff --git a/chromium/content/browser/media/android/media_session.h b/chromium/content/browser/media/android/media_session.h
deleted file mode 100644
index fa727b0b049..00000000000
--- a/chromium/content/browser/media/android/media_session.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_H_
-#define CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_H_
-
-#include <jni.h>
-#include <stddef.h>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/id_map.h"
-#include "base/macros.h"
-#include "content/browser/media/android/media_session_uma_helper.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-class MediaSessionBrowserTest;
-
-namespace content {
-
-class MediaSessionObserver;
-
-// MediaSession manages the Android AudioFocus for a given WebContents. It is
-// requesting the audio focus, pausing when requested by the system and dropping
-// it on demand.
-// The audio focus can be of two types: Transient or Content. A Transient audio
-// focus will allow other players to duck instead of pausing and will be
-// declared as temporary to the system. A Content audio focus will not be
-// declared as temporary and will not allow other players to duck. If a given
-// WebContents can only have one audio focus at a time, it will be Content in
-// case of Transient and Content audio focus are both requested.
-// Android system interaction occurs in the Java counterpart to this class.
-class CONTENT_EXPORT MediaSession
- : public WebContentsObserver,
- protected WebContentsUserData<MediaSession> {
- public:
- enum class Type {
- Content,
- Transient
- };
-
- static bool RegisterMediaSession(JNIEnv* env);
-
- // Returns the MediaSession associated to this WebContents. Creates one if
- // none is currently available.
- static MediaSession* Get(WebContents* web_contents);
-
- ~MediaSession() override;
-
- // Adds the given player to the current media session. Returns whether the
- // player was successfully added. If it returns false, AddPlayer() should be
- // called again later.
- bool AddPlayer(MediaSessionObserver* observer, int player_id, Type type);
-
- // Removes the given player from the current media session. Abandons audio
- // focus if that was the last player in the session.
- void RemovePlayer(MediaSessionObserver* observer, int player_id);
-
- // Removes all the players associated with |observer|. Abandons audio focus if
- // these were the last players in the session.
- void RemovePlayers(MediaSessionObserver* observer);
-
- // Called when the Android system requests the MediaSession to be suspended.
- // Called by Java through JNI.
- void OnSuspend(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jboolean temporary);
-
- // Called when the Android system requests the MediaSession to be resumed.
- // Called by Java through JNI.
- void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-
- // Called when a player is paused in the content.
- // If the paused player is the last player, we suspend the MediaSession.
- // Otherwise, the paused player will be removed from the MediaSession.
- void OnPlayerPaused(MediaSessionObserver* observer, int player_id);
-
- // Called when the user requests resuming the session. No-op if the session is
- // not controllable.
- void Resume();
-
- // Called when the user requests suspending the session. No-op if the session
- // is not controllable.
- void Suspend();
-
- // Called when the user requests stopping the session.
- void Stop();
-
- // Returns if the session can be controlled by Resume() and Suspend calls
- // above.
- bool IsControllable() const;
-
- // Returns if the session is currently suspended.
- bool IsSuspended() const;
-
- private:
- friend class content::WebContentsUserData<MediaSession>;
- friend class ::MediaSessionBrowserTest;
-
- // Resets the |j_media_session_| ref to prevent calling the Java backend
- // during content_browsertests.
- void ResetJavaRefForTest();
- bool IsActiveForTest() const;
- Type audio_focus_type_for_test() const;
- void RemoveAllPlayersForTest();
- MediaSessionUmaHelper* uma_helper_for_test();
-
- enum class State {
- ACTIVE,
- SUSPENDED,
- INACTIVE
- };
-
- enum class SuspendType {
- // Suspended by the system because a transient sound needs to be played.
- SYSTEM,
- // Suspended by the UI.
- UI,
- // Suspended by the page via script or user interaction.
- CONTENT,
- };
-
- // Representation of a player for the MediaSession.
- struct PlayerIdentifier {
- PlayerIdentifier(MediaSessionObserver* observer, int player_id);
- PlayerIdentifier(const PlayerIdentifier&) = default;
-
- void operator=(const PlayerIdentifier&) = delete;
- bool operator==(const PlayerIdentifier& player_identifier) const;
-
- // Hash operator for base::hash_map<>.
- struct Hash {
- size_t operator()(const PlayerIdentifier& player_identifier) const;
- };
-
- MediaSessionObserver* observer;
- int player_id;
- };
- using PlayersMap = base::hash_set<PlayerIdentifier, PlayerIdentifier::Hash>;
-
- explicit MediaSession(WebContents* web_contents);
-
- // Setup the JNI.
- void Initialize();
-
- void OnSuspendInternal(SuspendType type, State new_state);
- void OnResumeInternal(SuspendType type);
-
- // Requests audio focus to Android using |j_media_session_|.
- // Returns whether the request was granted. If |j_media_session_| is null, it
- // will always return true.
- bool RequestSystemAudioFocus(Type type);
-
- // To be called after a call to AbandonAudioFocus() in order to call the Java
- // MediaSession if the audio focus really need to be abandoned.
- void AbandonSystemAudioFocusIfNeeded();
-
- // Notifies WebContents about the state change of the media session.
- void UpdateWebContents();
-
- // Internal method that should be used instead of setting audio_focus_state_.
- // It sets audio_focus_state_ and notifies observers about the state change.
- void SetAudioFocusState(State audio_focus_state);
-
- base::android::ScopedJavaGlobalRef<jobject> j_media_session_;
- PlayersMap players_;
-
- State audio_focus_state_;
- SuspendType suspend_type_;
- Type audio_focus_type_;
-
- MediaSessionUmaHelper uma_helper_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaSession);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_H_
diff --git a/chromium/content/browser/media/android/media_web_contents_observer_android.cc b/chromium/content/browser/media/android/media_web_contents_observer_android.cc
index 1b48959e9ba..5a6c451f13a 100644
--- a/chromium/content/browser/media/android/media_web_contents_observer_android.cc
+++ b/chromium/content/browser/media/android/media_web_contents_observer_android.cc
@@ -4,13 +4,16 @@
#include "content/browser/media/android/media_web_contents_observer_android.h"
+#include "base/memory/ptr_util.h"
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/media/android/browser_media_session_manager.h"
-#include "content/browser/media/android/media_session_observer.h"
+#include "content/browser/media/android/browser_surface_view_manager.h"
#include "content/browser/media/cdm/browser_cdm_manager.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/media/media_player_delegate_messages.h"
#include "content/common/media/media_player_messages_android.h"
#include "content/common/media/media_session_messages_android.h"
+#include "content/common/media/surface_view_manager_messages_android.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h"
@@ -18,6 +21,12 @@
namespace content {
+static void SuspendAllMediaPlayersInRenderFrame(
+ RenderFrameHost* render_frame_host) {
+ render_frame_host->Send(new MediaPlayerDelegateMsg_SuspendAllMediaPlayers(
+ render_frame_host->GetRoutingID()));
+}
+
MediaWebContentsObserverAndroid::MediaWebContentsObserverAndroid(
WebContents* web_contents)
: MediaWebContentsObserver(web_contents) {}
@@ -41,7 +50,7 @@ MediaWebContentsObserverAndroid::GetMediaPlayerManager(
BrowserMediaPlayerManager* manager =
BrowserMediaPlayerManager::Create(render_frame_host);
- media_player_managers_.set(render_frame_host, make_scoped_ptr(manager));
+ media_player_managers_.set(render_frame_host, base::WrapUnique(manager));
return manager;
}
@@ -54,10 +63,46 @@ MediaWebContentsObserverAndroid::GetMediaSessionManager(
BrowserMediaSessionManager* manager =
new BrowserMediaSessionManager(render_frame_host);
- media_session_managers_.set(render_frame_host, make_scoped_ptr(manager));
+ media_session_managers_.set(render_frame_host, base::WrapUnique(manager));
return manager;
}
+BrowserSurfaceViewManager*
+MediaWebContentsObserverAndroid::GetSurfaceViewManager(
+ RenderFrameHost* render_frame_host) {
+ auto it = surface_view_managers_.find(render_frame_host);
+ if (it != surface_view_managers_.end())
+ return it->second;
+
+ BrowserSurfaceViewManager* manager =
+ new BrowserSurfaceViewManager(render_frame_host);
+ surface_view_managers_.set(render_frame_host, base::WrapUnique(manager));
+ return manager;
+}
+
+void MediaWebContentsObserverAndroid::SuspendAllMediaPlayers() {
+ web_contents()->ForEachFrame(
+ base::Bind(&SuspendAllMediaPlayersInRenderFrame));
+}
+
+bool MediaWebContentsObserverAndroid::RequestPlay(
+ RenderFrameHost* render_frame_host,
+ int delegate_id,
+ bool has_audio,
+ bool is_remote,
+ base::TimeDelta duration) {
+ return session_controllers_manager()->RequestPlay(
+ MediaPlayerId(render_frame_host, delegate_id),
+ has_audio, is_remote, duration);
+}
+
+void MediaWebContentsObserverAndroid::DisconnectMediaSession(
+ RenderFrameHost* render_frame_host,
+ int delegate_id) {
+ session_controllers_manager()->OnEnd(
+ MediaPlayerId(render_frame_host, delegate_id));
+}
+
#if defined(VIDEO_HOLE)
void MediaWebContentsObserverAndroid::OnFrameInfoUpdated() {
for (auto it = media_player_managers_.begin();
@@ -75,6 +120,7 @@ void MediaWebContentsObserverAndroid::RenderFrameDeleted(
// detaching CDMs from media players yet. See http://crbug.com/330324
media_player_managers_.erase(render_frame_host);
media_session_managers_.erase(render_frame_host);
+ surface_view_managers_.erase(render_frame_host);
// TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
// and BrowserCdmManager all run on browser UI thread. So this call is okay.
@@ -96,7 +142,16 @@ bool MediaWebContentsObserverAndroid::OnMessageReceived(
if (OnMediaPlayerMessageReceived(msg, render_frame_host))
return true;
- return OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host);
+ if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host))
+ return true;
+
+ if (OnMediaSessionMessageReceived(msg, render_frame_host))
+ return true;
+
+ if (OnSurfaceViewManagerMessageReceived(msg, render_frame_host))
+ return true;
+
+ return false;
}
bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived(
@@ -143,24 +198,55 @@ bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived(
GetMediaPlayerManager(render_frame_host),
BrowserMediaPlayerManager::OnNotifyExternalSurface)
#endif // defined(VIDEO_HOLE)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+bool MediaWebContentsObserverAndroid::OnMediaPlayerSetCdmMessageReceived(
+ const IPC::Message& msg,
+ RenderFrameHost* render_frame_host) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserverAndroid, msg,
+ render_frame_host)
+ IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetCdm, OnSetCdm)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+bool MediaWebContentsObserverAndroid::OnMediaSessionMessageReceived(
+ const IPC::Message& msg,
+ RenderFrameHost* render_frame_host) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver, msg)
IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Activate,
GetMediaSessionManager(render_frame_host),
BrowserMediaSessionManager::OnActivate)
IPC_MESSAGE_FORWARD(MediaSessionHostMsg_Deactivate,
GetMediaSessionManager(render_frame_host),
BrowserMediaSessionManager::OnDeactivate)
+ IPC_MESSAGE_FORWARD(MediaSessionHostMsg_SetMetadata,
+ GetMediaSessionManager(render_frame_host),
+ BrowserMediaSessionManager::OnSetMetadata)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+
return handled;
}
-bool MediaWebContentsObserverAndroid::OnMediaPlayerSetCdmMessageReceived(
+bool MediaWebContentsObserverAndroid::OnSurfaceViewManagerMessageReceived(
const IPC::Message& msg,
RenderFrameHost* render_frame_host) {
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserverAndroid, msg,
- render_frame_host)
- IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetCdm, OnSetCdm)
+ IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg)
+ IPC_MESSAGE_FORWARD(SurfaceViewManagerHostMsg_CreateFullscreenSurface,
+ GetSurfaceViewManager(render_frame_host),
+ BrowserSurfaceViewManager::OnCreateFullscreenSurface)
+ IPC_MESSAGE_FORWARD(SurfaceViewManagerHostMsg_NaturalSizeChanged,
+ GetSurfaceViewManager(render_frame_host),
+ BrowserSurfaceViewManager::OnNaturalSizeChanged)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
diff --git a/chromium/content/browser/media/android/media_web_contents_observer_android.h b/chromium/content/browser/media/android/media_web_contents_observer_android.h
index a95e1615fb6..0f3a2a9bd14 100644
--- a/chromium/content/browser/media/android/media_web_contents_observer_android.h
+++ b/chromium/content/browser/media/android/media_web_contents_observer_android.h
@@ -7,9 +7,10 @@
#include <stdint.h>
+#include <memory>
+
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/common/content_export.h"
@@ -18,6 +19,7 @@ namespace content {
class BrowserCdmManager;
class BrowserMediaPlayerManager;
class BrowserMediaSessionManager;
+class BrowserSurfaceViewManager;
// This class adds Android specific extensions to the MediaWebContentsObserver.
class CONTENT_EXPORT MediaWebContentsObserverAndroid
@@ -30,19 +32,40 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid
static MediaWebContentsObserverAndroid* FromWebContents(
WebContents* web_contents);
- // Gets the media player or media session manager associated with the given
- // |render_frame_host| respectively. Creates a new one if it doesn't exist.
- // The caller doesn't own the returned pointer.
+ // Gets one of the managers associated with the given |render_frame_host|.
+ // Creates a new one if it doesn't exist. The caller doesn't own the
+ // returned pointer.
BrowserMediaPlayerManager* GetMediaPlayerManager(
RenderFrameHost* render_frame_host);
BrowserMediaSessionManager* GetMediaSessionManager(
RenderFrameHost* render_frame_host);
+ BrowserSurfaceViewManager* GetSurfaceViewManager(
+ RenderFrameHost* render_frame_host);
+
+ // Called by the WebContents when a tab has been closed but may still be
+ // available for "undo" -- indicates that all media players (even audio only
+ // players typically allowed background audio) bound to this WebContents must
+ // be suspended.
+ void SuspendAllMediaPlayers();
+
+ // Initiates a synchronous MediaSession request for browser side players.
+ //
+ // TODO(dalecurtis): Delete this method once we're no longer using WMPA and
+ // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626
+ bool RequestPlay(RenderFrameHost* render_frame_host,
+ int delegate_id,
+ bool has_audio,
+ bool is_remote,
+ base::TimeDelta duration);
+
+ void DisconnectMediaSession(RenderFrameHost* render_frame_host,
+ int delegate_id);
#if defined(VIDEO_HOLE)
void OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE)
- // MediaWebContentsObserverAndroid overrides.
+ // MediaWebContentsObserver overrides.
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
bool OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host) override;
@@ -56,20 +79,31 @@ class CONTENT_EXPORT MediaWebContentsObserverAndroid
bool OnMediaPlayerSetCdmMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host);
+ bool OnMediaSessionMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host);
+
+ bool OnSurfaceViewManagerMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host);
+
void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
// Map from RenderFrameHost* to BrowserMediaPlayerManager.
using MediaPlayerManagerMap =
base::ScopedPtrHashMap<RenderFrameHost*,
- scoped_ptr<BrowserMediaPlayerManager>>;
+ std::unique_ptr<BrowserMediaPlayerManager>>;
MediaPlayerManagerMap media_player_managers_;
// Map from RenderFrameHost* to BrowserMediaSessionManager.
using MediaSessionManagerMap =
base::ScopedPtrHashMap<RenderFrameHost*,
- scoped_ptr<BrowserMediaSessionManager>>;
+ std::unique_ptr<BrowserMediaSessionManager>>;
MediaSessionManagerMap media_session_managers_;
+ using SurfaceViewManagerMap =
+ base::ScopedPtrHashMap<RenderFrameHost*,
+ std::unique_ptr<BrowserSurfaceViewManager>>;
+ SurfaceViewManagerMap surface_view_managers_;
+
DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverAndroid);
};
diff --git a/chromium/content/browser/media/android/provision_fetcher_impl.cc b/chromium/content/browser/media/android/provision_fetcher_impl.cc
index 8e9f689d5e2..6ca51d7c417 100644
--- a/chromium/content/browser/media/android/provision_fetcher_impl.cc
+++ b/chromium/content/browser/media/android/provision_fetcher_impl.cc
@@ -26,7 +26,7 @@ void ProvisionFetcherImpl::Create(
}
ProvisionFetcherImpl::ProvisionFetcherImpl(
- scoped_ptr<media::ProvisionFetcher> provision_fetcher,
+ std::unique_ptr<media::ProvisionFetcher> provision_fetcher,
mojo::InterfaceRequest<ProvisionFetcher> request)
: binding_(this, std::move(request)),
provision_fetcher_(std::move(provision_fetcher)),
diff --git a/chromium/content/browser/media/android/provision_fetcher_impl.h b/chromium/content/browser/media/android/provision_fetcher_impl.h
index 3f009fb89d6..38ae9cb27bd 100644
--- a/chromium/content/browser/media/android/provision_fetcher_impl.h
+++ b/chromium/content/browser/media/android/provision_fetcher_impl.h
@@ -5,8 +5,9 @@
#ifndef CONTENT_BROWSER_MEDIA_ANDROID_PROVISION_FETCHER_IMPL_H_
#define CONTENT_BROWSER_MEDIA_ANDROID_PROVISION_FETCHER_IMPL_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/android/provision_fetcher_factory.h"
#include "media/base/android/provision_fetcher.h"
@@ -25,8 +26,9 @@ class ProvisionFetcherImpl : public media::interfaces::ProvisionFetcher {
RenderFrameHost* render_frame_host,
mojo::InterfaceRequest<media::interfaces::ProvisionFetcher> request);
- ProvisionFetcherImpl(scoped_ptr<media::ProvisionFetcher> provision_fetcher,
- mojo::InterfaceRequest<ProvisionFetcher> request);
+ ProvisionFetcherImpl(
+ std::unique_ptr<media::ProvisionFetcher> provision_fetcher,
+ mojo::InterfaceRequest<ProvisionFetcher> request);
~ProvisionFetcherImpl() override;
// media::interfaces::ProvisionFetcher implementation.
@@ -41,7 +43,7 @@ class ProvisionFetcherImpl : public media::interfaces::ProvisionFetcher {
const std::string& response);
mojo::StrongBinding<media::interfaces::ProvisionFetcher> binding_;
- scoped_ptr<media::ProvisionFetcher> provision_fetcher_;
+ std::unique_ptr<media::ProvisionFetcher> provision_fetcher_;
base::WeakPtrFactory<ProvisionFetcherImpl> weak_factory_;
diff --git a/chromium/content/browser/media/android/url_provision_fetcher.cc b/chromium/content/browser/media/android/url_provision_fetcher.cc
index 7607480c933..83a34b7ba82 100644
--- a/chromium/content/browser/media/android/url_provision_fetcher.cc
+++ b/chromium/content/browser/media/android/url_provision_fetcher.cc
@@ -4,6 +4,7 @@
#include "content/browser/media/android/url_provision_fetcher.h"
+#include "base/memory/ptr_util.h"
#include "content/public/browser/android/provision_fetcher_factory.h"
#include "media/base/bind_to_current_loop.h"
#include "net/url_request/url_fetcher.h"
@@ -68,10 +69,10 @@ void URLProvisionFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
// Implementation of content public method CreateProvisionFetcher().
-scoped_ptr<media::ProvisionFetcher> CreateProvisionFetcher(
+std::unique_ptr<media::ProvisionFetcher> CreateProvisionFetcher(
net::URLRequestContextGetter* context_getter) {
DCHECK(context_getter);
- return make_scoped_ptr(new URLProvisionFetcher(context_getter));
+ return base::WrapUnique(new URLProvisionFetcher(context_getter));
}
} // namespace content
diff --git a/chromium/content/browser/media/android/url_provision_fetcher.h b/chromium/content/browser/media/android/url_provision_fetcher.h
index 7e3d1397e65..b551c3b0345 100644
--- a/chromium/content/browser/media/android/url_provision_fetcher.h
+++ b/chromium/content/browser/media/android/url_provision_fetcher.h
@@ -30,7 +30,7 @@ class URLProvisionFetcher : public media::ProvisionFetcher,
void OnURLFetchComplete(const net::URLFetcher* source) override;
net::URLRequestContextGetter* context_getter_;
- scoped_ptr<net::URLFetcher> request_;
+ std::unique_ptr<net::URLFetcher> request_;
media::ProvisionFetcher::ResponseCB response_cb_;
DISALLOW_COPY_AND_ASSIGN(URLProvisionFetcher);
diff --git a/chromium/content/browser/media/audible_metrics.cc b/chromium/content/browser/media/audible_metrics.cc
index 4a740288e79..3c17cccfd4c 100644
--- a/chromium/content/browser/media/audible_metrics.cc
+++ b/chromium/content/browser/media/audible_metrics.cc
@@ -31,7 +31,8 @@ void AudibleMetrics::UpdateAudibleWebContentsState(
RemoveAudibleWebContents(web_contents);
}
-void AudibleMetrics::SetClockForTest(scoped_ptr<base::TickClock> test_clock) {
+void AudibleMetrics::SetClockForTest(
+ std::unique_ptr<base::TickClock> test_clock) {
clock_ = std::move(test_clock);
}
diff --git a/chromium/content/browser/media/audible_metrics.h b/chromium/content/browser/media/audible_metrics.h
index 408bc8cba27..6ff9351747e 100644
--- a/chromium/content/browser/media/audible_metrics.h
+++ b/chromium/content/browser/media/audible_metrics.h
@@ -5,9 +5,9 @@
#ifndef CONTENT_BROWSER_MEDIA_AUDIBLE_METRICS_H_
#define CONTENT_BROWSER_MEDIA_AUDIBLE_METRICS_H_
+#include <memory>
#include <set>
-#include "base/memory/scoped_ptr.h"
#include "base/time/tick_clock.h"
#include "content/common/content_export.h"
@@ -29,7 +29,7 @@ class CONTENT_EXPORT AudibleMetrics {
void UpdateAudibleWebContentsState(const WebContents* web_contents,
bool audible);
- void SetClockForTest(scoped_ptr<base::TickClock> test_clock);
+ void SetClockForTest(std::unique_ptr<base::TickClock> test_clock);
private:
void AddAudibleWebContents(const WebContents* web_contents);
@@ -37,7 +37,7 @@ class CONTENT_EXPORT AudibleMetrics {
base::TimeTicks concurrent_web_contents_start_time_;
size_t max_concurrent_audible_web_contents_in_session_;
- scoped_ptr<base::TickClock> clock_;
+ std::unique_ptr<base::TickClock> clock_;
std::set<const WebContents*> audible_web_contents_;
diff --git a/chromium/content/browser/media/audible_metrics_unittest.cc b/chromium/content/browser/media/audible_metrics_unittest.cc
index 1a6216b6459..a337bb1ae0c 100644
--- a/chromium/content/browser/media/audible_metrics_unittest.cc
+++ b/chromium/content/browser/media/audible_metrics_unittest.cc
@@ -39,7 +39,7 @@ class AudibleMetricsTest : public testing::Test {
// recognized as initialized.
clock_->Advance(base::TimeDelta::FromMilliseconds(1));
audible_metrics_.SetClockForTest(
- scoped_ptr<base::SimpleTestTickClock>(clock_));
+ std::unique_ptr<base::SimpleTestTickClock>(clock_));
}
void TearDown() override {
@@ -56,7 +56,7 @@ class AudibleMetricsTest : public testing::Test {
return user_action_tester_;
}
- scoped_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart(
+ std::unique_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart(
const std::string& name) {
return histogram_tester_.GetHistogramSamplesSinceCreation(name);
}
@@ -73,26 +73,24 @@ class AudibleMetricsTest : public testing::Test {
} // anonymous namespace
TEST_F(AudibleMetricsTest, CreateAndKillDoesNothing) {
- {
- scoped_ptr<AudibleMetrics> audible_metrics(new AudibleMetrics());
- }
+ { std::unique_ptr<AudibleMetrics> audible_metrics(new AudibleMetrics()); }
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -105,7 +103,7 @@ TEST_F(AudibleMetricsTest, AudibleStart) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -113,7 +111,7 @@ TEST_F(AudibleMetricsTest, AudibleStart) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -121,7 +119,7 @@ TEST_F(AudibleMetricsTest, AudibleStart) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -135,7 +133,7 @@ TEST_F(AudibleMetricsTest, AudibleStartAndStop) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, false);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -143,7 +141,7 @@ TEST_F(AudibleMetricsTest, AudibleStartAndStop) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -151,7 +149,7 @@ TEST_F(AudibleMetricsTest, AudibleStartAndStop) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -168,7 +166,7 @@ TEST_F(AudibleMetricsTest, AddSameTabIsNoOp) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -176,7 +174,7 @@ TEST_F(AudibleMetricsTest, AddSameTabIsNoOp) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
@@ -184,7 +182,7 @@ TEST_F(AudibleMetricsTest, AddSameTabIsNoOp) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -214,8 +212,9 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionIsIncremental) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_2, true);
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_3, true);
- scoped_ptr<base::HistogramSamples> samples(GetHistogramSamplesSinceTestStart(
- MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
+ std::unique_ptr<base::HistogramSamples> samples(
+ GetHistogramSamplesSinceTestStart(
+ MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(4, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1));
EXPECT_EQ(1, samples->GetCount(2));
@@ -235,8 +234,9 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionKeepTrackOfRemovedTabs) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_2, false);
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_3, true);
- scoped_ptr<base::HistogramSamples> samples(GetHistogramSamplesSinceTestStart(
- MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
+ std::unique_ptr<base::HistogramSamples> samples(
+ GetHistogramSamplesSinceTestStart(
+ MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1));
EXPECT_EQ(1, samples->GetCount(2));
@@ -261,8 +261,9 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionIsNotCountedTwice) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_2, true);
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_3, true);
- scoped_ptr<base::HistogramSamples> samples(GetHistogramSamplesSinceTestStart(
- MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
+ std::unique_ptr<base::HistogramSamples> samples(
+ GetHistogramSamplesSinceTestStart(
+ MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM));
EXPECT_EQ(4, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1));
EXPECT_EQ(1, samples->GetCount(2));
@@ -278,7 +279,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsWhenStartingAddedPerTab) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(2, samples->TotalCount());
@@ -294,7 +295,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsWhenStartingAddedPerTab) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(2, samples->TotalCount());
@@ -310,7 +311,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsWhenStartingAddedPerTab) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, false);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(2, samples->TotalCount());
@@ -326,7 +327,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsWhenStartingAddedPerTab) {
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(
CONCURRENT_TAB_WHEN_STARTING_HISTOGRAM));
EXPECT_EQ(4, samples->TotalCount());
@@ -351,7 +352,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsTimeRequiresTwoAudibleTabs) {
// No longer concurrent.
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, false);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -360,7 +361,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsTimeRequiresTwoAudibleTabs) {
// Stopping the second tab is a no-op.
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, false);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -387,7 +388,7 @@ TEST_F(AudibleMetricsTest, ConcurrentTabsTimeRunsAsLongAsTwoAudibleTabs) {
// Mutes the first audible tab.
audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, false);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1500));
diff --git a/chromium/content/browser/media/audio_stream_monitor_unittest.cc b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
index 9ecee0a5aec..f1d5103d1ce 100644
--- a/chromium/content/browser/media/audio_stream_monitor_unittest.cc
+++ b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
@@ -5,12 +5,12 @@
#include "content/browser/media/audio_stream_monitor.h"
#include <map>
+#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/test/simple_test_tick_clock.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/invalidate_type.h"
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.cc b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
index a75eb3c6476..f8b8b3a5b18 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
@@ -209,6 +209,9 @@ AudioMirroringManager::StreamRoutingState::StreamRoutingState(
diverter(stream_diverter),
destination(NULL) {}
+AudioMirroringManager::StreamRoutingState::StreamRoutingState(
+ const StreamRoutingState& other) = default;
+
AudioMirroringManager::StreamRoutingState::~StreamRoutingState() {}
} // namespace content
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.h b/chromium/content/browser/media/capture/audio_mirroring_manager.h
index 4e44699097a..a624a0824be 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.h
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.h
@@ -122,6 +122,7 @@ class CONTENT_EXPORT AudioMirroringManager {
StreamRoutingState(const SourceFrameRef& source_frame,
Diverter* stream_diverter);
+ StreamRoutingState(const StreamRoutingState& other);
~StreamRoutingState();
};
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc b/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
index 0f471c88171..17a46976b4a 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
@@ -120,7 +120,7 @@ class AudioMirroringManagerTest : public testing::Test {
delete diverter;
}
- void StartMirroringTo(const scoped_ptr<MockMirroringDestination>& dest,
+ void StartMirroringTo(const std::unique_ptr<MockMirroringDestination>& dest,
int expected_inputs_added) {
EXPECT_CALL(*dest, QueryForMatches(_, _))
.WillRepeatedly(Invoke(dest.get(),
@@ -136,12 +136,12 @@ class AudioMirroringManagerTest : public testing::Test {
mirroring_manager_.StartMirroring(dest.get());
}
- void StopMirroringTo(const scoped_ptr<MockMirroringDestination>& dest) {
+ void StopMirroringTo(const std::unique_ptr<MockMirroringDestination>& dest) {
mirroring_manager_.StopMirroring(dest.get());
}
int CountStreamsDivertedTo(
- const scoped_ptr<MockMirroringDestination>& dest) const {
+ const std::unique_ptr<MockMirroringDestination>& dest) const {
int count = 0;
for (StreamRoutes::const_iterator it = mirroring_manager_.routes_.begin();
it != mirroring_manager_.routes_.end(); ++it) {
@@ -175,7 +175,7 @@ const int kYetAnotherRenderFrameId = 7890;
}
TEST_F(AudioMirroringManagerTest, MirroringSessionOfNothing) {
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 0);
EXPECT_EQ(0, CountStreamsDivertedTo(destination));
@@ -187,7 +187,7 @@ TEST_F(AudioMirroringManagerTest, MirroringSessionOfNothing) {
}
TEST_F(AudioMirroringManagerTest, TwoMirroringSessionsOfNothing) {
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 0);
EXPECT_EQ(0, CountStreamsDivertedTo(destination));
@@ -195,7 +195,7 @@ TEST_F(AudioMirroringManagerTest, TwoMirroringSessionsOfNothing) {
StopMirroringTo(destination);
EXPECT_EQ(0, destination->query_count());
- const scoped_ptr<MockMirroringDestination> another_destination(
+ const std::unique_ptr<MockMirroringDestination> another_destination(
new MockMirroringDestination(kAnotherRenderProcessId,
kAnotherRenderFrameId));
StartMirroringTo(another_destination, 0);
@@ -212,7 +212,7 @@ TEST_F(AudioMirroringManagerTest, TwoMirroringSessionsOfNothing) {
TEST_F(AudioMirroringManagerTest, StreamLifetimeAroundMirroringSession) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 1);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
@@ -232,7 +232,7 @@ TEST_F(AudioMirroringManagerTest, StreamLifetimeAroundMirroringSession) {
// Tests that a mirroring session starts before, and ends after, a stream that
// will be diverted to it.
TEST_F(AudioMirroringManagerTest, StreamLifetimeWithinMirroringSession) {
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(0, destination->query_count());
@@ -260,7 +260,7 @@ TEST_F(AudioMirroringManagerTest, StreamLifetimeAcrossTwoMirroringSessions) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 2);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
@@ -270,7 +270,7 @@ TEST_F(AudioMirroringManagerTest, StreamLifetimeAcrossTwoMirroringSessions) {
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(0, CountStreamsDivertedTo(destination));
- const scoped_ptr<MockMirroringDestination> second_destination(
+ const std::unique_ptr<MockMirroringDestination> second_destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(second_destination, 1);
EXPECT_EQ(1, destination->query_count());
@@ -299,13 +299,13 @@ TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_1) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 2);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
- const scoped_ptr<MockMirroringDestination> replacement_destination(
+ const std::unique_ptr<MockMirroringDestination> replacement_destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(replacement_destination, 1);
EXPECT_EQ(1, destination->query_count());
@@ -340,13 +340,13 @@ TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_2) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 2);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
- const scoped_ptr<MockMirroringDestination> replacement_destination(
+ const std::unique_ptr<MockMirroringDestination> replacement_destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(replacement_destination, 1);
EXPECT_EQ(1, destination->query_count());
@@ -382,13 +382,13 @@ TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_3) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 1);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
- const scoped_ptr<MockMirroringDestination> replacement_destination(
+ const std::unique_ptr<MockMirroringDestination> replacement_destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(replacement_destination, 0);
EXPECT_EQ(1, destination->query_count());
@@ -422,7 +422,7 @@ TEST_F(AudioMirroringManagerTest, MultipleStreamsInOneMirroringSession) {
MockDiverter* const stream1 =
CreateStream(kRenderProcessId, kRenderFrameId, 1);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 3);
EXPECT_EQ(1, destination->query_count());
@@ -463,13 +463,13 @@ TEST_F(AudioMirroringManagerTest, ThreeSeparateMirroringSessions) {
MockDiverter* const stream =
CreateStream(kRenderProcessId, kRenderFrameId, 1);
- const scoped_ptr<MockMirroringDestination> destination(
+ const std::unique_ptr<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
- const scoped_ptr<MockMirroringDestination> another_destination(
+ const std::unique_ptr<MockMirroringDestination> another_destination(
new MockMirroringDestination(kAnotherRenderProcessId,
kAnotherRenderFrameId));
StartMirroringTo(another_destination, 1);
@@ -498,7 +498,7 @@ TEST_F(AudioMirroringManagerTest, ThreeSeparateMirroringSessions) {
EXPECT_EQ(2, another_destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(another_destination));
- const scoped_ptr<MockMirroringDestination> yet_another_destination(
+ const std::unique_ptr<MockMirroringDestination> yet_another_destination(
new MockMirroringDestination(kYetAnotherRenderProcessId,
kYetAnotherRenderFrameId));
StartMirroringTo(yet_another_destination, 1);
diff --git a/chromium/content/browser/media/capture/aura_window_capture_machine.cc b/chromium/content/browser/media/capture/aura_window_capture_machine.cc
index c3405994e94..864243efee3 100644
--- a/chromium/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/chromium/content/browser/media/capture/aura_window_capture_machine.cc
@@ -9,12 +9,11 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
-#include "base/timer/timer.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/power_save_blocker.h"
#include "media/base/video_capture_types.h"
@@ -39,7 +38,6 @@ namespace content {
AuraWindowCaptureMachine::AuraWindowCaptureMachine()
: desktop_window_(NULL),
- timer_(true, true),
screen_capture_(false),
weak_factory_(this) {}
@@ -74,7 +72,7 @@ bool AuraWindowCaptureMachine::InternalStart(
if (!layer)
return false;
- DCHECK(oracle_proxy.get());
+ DCHECK(oracle_proxy);
oracle_proxy_ = oracle_proxy;
capture_params_ = params;
@@ -82,8 +80,11 @@ bool AuraWindowCaptureMachine::InternalStart(
UpdateCaptureSize();
// Start observing compositor updates.
- if (desktop_window_->GetHost())
- desktop_window_->GetHost()->compositor()->AddObserver(this);
+ aura::WindowTreeHost* const host = desktop_window_->GetHost();
+ ui::Compositor* const compositor = host ? host->compositor() : nullptr;
+ if (!compositor)
+ return false;
+ compositor->AddAnimationObserver(this);
power_save_blocker_.reset(
PowerSaveBlocker::Create(
@@ -91,14 +92,6 @@ bool AuraWindowCaptureMachine::InternalStart(
PowerSaveBlocker::kReasonOther,
"DesktopCaptureDevice is running").release());
- // Starts timer.
- timer_.Start(FROM_HERE,
- std::max(oracle_proxy_->min_capture_period(),
- base::TimeDelta::FromMilliseconds(media::
- VideoCaptureOracle::kMinTimerPollPeriodMillis)),
- base::Bind(&AuraWindowCaptureMachine::Capture,
- base::Unretained(this), false));
-
return true;
}
@@ -121,27 +114,34 @@ void AuraWindowCaptureMachine::InternalStop(const base::Closure& callback) {
// Stop observing compositor and window events.
if (desktop_window_) {
- aura::WindowTreeHost* window_host = desktop_window_->GetHost();
- // In the host destructor the compositor is destroyed before the window.
- if (window_host && window_host->compositor())
- window_host->compositor()->RemoveObserver(this);
+ if (aura::WindowTreeHost* host = desktop_window_->GetHost()) {
+ if (ui::Compositor* compositor = host->compositor())
+ compositor->RemoveAnimationObserver(this);
+ }
desktop_window_->RemoveObserver(this);
desktop_window_ = NULL;
cursor_renderer_.reset();
}
- // Stop timer.
- timer_.Stop();
-
callback.Run();
}
+void AuraWindowCaptureMachine::MaybeCaptureForRefresh() {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&AuraWindowCaptureMachine::Capture,
+ // Use of Unretained() is safe here since this task must run
+ // before InternalStop().
+ base::Unretained(this),
+ base::TimeTicks()));
+}
+
void AuraWindowCaptureMachine::SetWindow(aura::Window* window) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!desktop_window_);
desktop_window_ = window;
- cursor_renderer_.reset(new CursorRendererAura(window));
+ cursor_renderer_.reset(new CursorRendererAura(window, kCursorAlwaysEnabled));
// Start observing window events.
desktop_window_->AddObserver(this);
@@ -155,7 +155,7 @@ void AuraWindowCaptureMachine::SetWindow(aura::Window* window) {
void AuraWindowCaptureMachine::UpdateCaptureSize() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (oracle_proxy_.get() && desktop_window_) {
+ if (oracle_proxy_ && desktop_window_) {
ui::Layer* layer = desktop_window_->layer();
oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
layer, layer->bounds().size()));
@@ -163,7 +163,7 @@ void AuraWindowCaptureMachine::UpdateCaptureSize() {
cursor_renderer_->Clear();
}
-void AuraWindowCaptureMachine::Capture(bool dirty) {
+void AuraWindowCaptureMachine::Capture(base::TimeTicks event_time) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Do not capture if the desktop window is already destroyed.
@@ -177,16 +177,20 @@ void AuraWindowCaptureMachine::Capture(bool dirty) {
// timestamps and damage regions, to leverage the frame timestamp rewriting
// logic. http://crbug.com/492839
const base::TimeTicks start_time = base::TimeTicks::Now();
- const media::VideoCaptureOracle::Event event =
- dirty ? media::VideoCaptureOracle::kCompositorUpdate
- : media::VideoCaptureOracle::kTimerPoll;
+ media::VideoCaptureOracle::Event event;
+ if (event_time.is_null()) {
+ event = media::VideoCaptureOracle::kActiveRefreshRequest;
+ event_time = start_time;
+ } else {
+ event = media::VideoCaptureOracle::kCompositorUpdate;
+ }
if (oracle_proxy_->ObserveEventAndDecideCapture(
- event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
- scoped_ptr<cc::CopyOutputRequest> request =
- cc::CopyOutputRequest::CreateRequest(
- base::Bind(&AuraWindowCaptureMachine::DidCopyOutput,
- weak_factory_.GetWeakPtr(),
- frame, start_time, capture_frame_cb));
+ event, gfx::Rect(), event_time, &frame, &capture_frame_cb)) {
+ std::unique_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateRequest(base::Bind(
+ &AuraWindowCaptureMachine::DidCopyOutput,
+ weak_factory_.GetWeakPtr(), frame, event_time, start_time,
+ capture_frame_cb));
gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(),
desktop_window_->bounds().height());
request->set_area(window_rect);
@@ -196,17 +200,18 @@ void AuraWindowCaptureMachine::Capture(bool dirty) {
void AuraWindowCaptureMachine::DidCopyOutput(
scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks event_time,
base::TimeTicks start_time,
const CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result) {
+ std::unique_ptr<cc::CopyOutputResult> result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
static bool first_call = true;
- bool succeeded = ProcessCopyOutputResponse(
- video_frame, start_time, capture_frame_cb, std::move(result));
+ const bool succeeded = ProcessCopyOutputResponse(
+ video_frame, event_time, capture_frame_cb, std::move(result));
- base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
+ const base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
// The two UMA_ blocks must be put in its own scope since it creates a static
// variable which expected constant histogram name.
@@ -227,18 +232,33 @@ void AuraWindowCaptureMachine::DidCopyOutput(
: FIRST_WINDOW_CAPTURE_FAILED);
}
}
+
+ // If ProcessCopyOutputResponse() failed, it will not run |capture_frame_cb|,
+ // so do that now.
+ if (!succeeded)
+ capture_frame_cb.Run(video_frame, event_time, false);
}
bool AuraWindowCaptureMachine::ProcessCopyOutputResponse(
scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
+ base::TimeTicks event_time,
const CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result) {
+ std::unique_ptr<cc::CopyOutputResult> result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_)
+ if (!desktop_window_) {
+ VLOG(1) << "Ignoring CopyOutputResult: Capture target has gone away.";
+ return false;
+ }
+ if (result->IsEmpty()) {
+ VLOG(1) << "CopyOutputRequest failed: No texture or bitmap in result.";
+ return false;
+ }
+ if (result->size().IsEmpty()) {
+ VLOG(1) << "CopyOutputRequest failed: Zero-area texture/bitmap result.";
return false;
- DCHECK(video_frame.get());
+ }
+ DCHECK(video_frame);
// Compute the dest size we want after the letterboxing resize. Make the
// coordinates and sizes even because we letterbox in YUV space
@@ -252,20 +272,26 @@ bool AuraWindowCaptureMachine::ProcessCopyOutputResponse(
region_in_frame.y() & ~1,
region_in_frame.width() & ~1,
region_in_frame.height() & ~1);
- if (region_in_frame.IsEmpty())
+ if (region_in_frame.IsEmpty()) {
+ VLOG(1) << "Aborting capture: Computed empty letterboxed content region.";
return false;
+ }
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
+ if (!gl_helper) {
+ VLOG(1) << "Aborting capture: No GLHelper available for YUV readback.";
return false;
+ }
cc::TextureMailbox texture_mailbox;
- scoped_ptr<cc::SingleReleaseCallback> release_callback;
+ std::unique_ptr<cc::SingleReleaseCallback> release_callback;
result->TakeTexture(&texture_mailbox, &release_callback);
DCHECK(texture_mailbox.IsTexture());
- if (!texture_mailbox.IsTexture())
+ if (!texture_mailbox.IsTexture()) {
+ VLOG(1) << "Aborting capture: Failed to take texture from mailbox.";
return false;
+ }
gfx::Rect result_rect(result->size());
if (!yuv_readback_pipeline_ ||
@@ -286,7 +312,7 @@ bool AuraWindowCaptureMachine::ProcessCopyOutputResponse(
texture_mailbox.mailbox(), texture_mailbox.sync_token(),
video_frame.get(), region_in_frame.origin(),
base::Bind(&CopyOutputFinishedForVideo, weak_factory_.GetWeakPtr(),
- start_time, capture_frame_cb, video_frame,
+ event_time, capture_frame_cb, video_frame,
base::Passed(&release_callback)));
return true;
}
@@ -296,10 +322,10 @@ using CaptureFrameCallback =
void AuraWindowCaptureMachine::CopyOutputFinishedForVideo(
base::WeakPtr<AuraWindowCaptureMachine> machine,
- base::TimeTicks start_time,
+ base::TimeTicks event_time,
const CaptureFrameCallback& capture_frame_cb,
const scoped_refptr<media::VideoFrame>& target,
- scoped_ptr<cc::SingleReleaseCallback> release_callback,
+ std::unique_ptr<cc::SingleReleaseCallback> release_callback,
bool result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -308,11 +334,15 @@ void AuraWindowCaptureMachine::CopyOutputFinishedForVideo(
// Render the cursor and deliver the captured frame if the
// AuraWindowCaptureMachine has not been stopped (i.e., the WeakPtr is
// still valid).
- if (machine.get()) {
+ if (machine) {
if (machine->cursor_renderer_ && result)
machine->cursor_renderer_->RenderOnVideoFrame(target);
- capture_frame_cb.Run(target, start_time, result);
+ } else {
+ VLOG(1) << "Aborting capture: AuraWindowCaptureMachine has gone away.";
+ result = false;
}
+
+ capture_frame_cb.Run(target, event_time, result);
}
void AuraWindowCaptureMachine::OnWindowBoundsChanged(
@@ -341,7 +371,10 @@ void AuraWindowCaptureMachine::OnWindowAddedToRootWindow(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(window == desktop_window_);
- window->GetHost()->compositor()->AddObserver(this);
+ if (aura::WindowTreeHost* host = window->GetHost()) {
+ if (ui::Compositor* compositor = host->compositor())
+ compositor->AddAnimationObserver(this);
+ }
}
void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow(
@@ -350,20 +383,36 @@ void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(window == desktop_window_);
- window->GetHost()->compositor()->RemoveObserver(this);
+ if (aura::WindowTreeHost* host = window->GetHost()) {
+ if (ui::Compositor* compositor = host->compositor())
+ compositor->RemoveAnimationObserver(this);
+ }
}
-void AuraWindowCaptureMachine::OnCompositingEnded(
- ui::Compositor* compositor) {
+void AuraWindowCaptureMachine::OnAnimationStep(base::TimeTicks timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- // TODO(miu): The CopyOutputRequest should be made earlier, at WillCommit().
+ DCHECK(!timestamp.is_null());
+
+ // HACK: The compositor invokes this observer method to step layer animation
+ // forward. Scheduling frame capture was not the intention, and so invoking
+ // this method does not actually indicate the content has changed. However,
+ // this is the only reliable way to ensure all screen changes are captured, as
+ // of this writing.
+ // http://crbug.com/600031
+ //
+ // TODO(miu): Need a better observer callback interface from the compositor
+ // for this use case. The solution here will always capture frames at the
+ // maximum framerate, which means CPU/GPU is being wasted on redundant
+ // captures and quality/smoothness of animating content will suffer
+ // significantly.
// http://crbug.com/492839
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&AuraWindowCaptureMachine::Capture, weak_factory_.GetWeakPtr(),
- true));
+ Capture(timestamp);
+}
+
+void AuraWindowCaptureMachine::OnCompositingShuttingDown(
+ ui::Compositor* compositor) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ compositor->RemoveAnimationObserver(this);
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/aura_window_capture_machine.h b/chromium/content/browser/media/capture/aura_window_capture_machine.h
index c07c72f8c8c..ca9e09e4463 100644
--- a/chromium/content/browser/media/capture/aura_window_capture_machine.h
+++ b/chromium/content/browser/media/capture/aura_window_capture_machine.h
@@ -5,16 +5,17 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
+#include <memory>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
#include "content/browser/media/capture/cursor_renderer_aura.h"
#include "media/capture/content/screen_capture_device_core.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/cursor/cursors_aura.h"
#include "ui/compositor/compositor.h"
+#include "ui/compositor/compositor_animation_observer.h"
namespace cc {
@@ -30,7 +31,7 @@ class ReadbackYUVInterface;
class AuraWindowCaptureMachine
: public media::VideoCaptureMachine,
public aura::WindowObserver,
- public ui::CompositorObserver {
+ public ui::CompositorAnimationObserver {
public:
AuraWindowCaptureMachine();
~AuraWindowCaptureMachine() override;
@@ -40,6 +41,7 @@ class AuraWindowCaptureMachine
const media::VideoCaptureParams& params,
const base::Callback<void(bool)> callback) override;
void Stop(const base::Closure& callback) override;
+ void MaybeCaptureForRefresh() override;
// Implements aura::WindowObserver.
void OnWindowBoundsChanged(aura::Window* window,
@@ -50,14 +52,9 @@ class AuraWindowCaptureMachine
void OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) override;
- // Implements ui::CompositorObserver.
- void OnCompositingDidCommit(ui::Compositor* compositor) override {}
- void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) override {}
- void OnCompositingEnded(ui::Compositor* compositor) override;
- void OnCompositingAborted(ui::Compositor* compositor) override {}
- void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
- void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+ // ui::CompositorAnimationObserver implementation.
+ void OnAnimationStep(base::TimeTicks timestamp) override;
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override;
// Sets the window to use for capture.
void SetWindow(aura::Window* window);
@@ -68,9 +65,9 @@ class AuraWindowCaptureMachine
const media::VideoCaptureParams& params);
void InternalStop(const base::Closure& callback);
- // Captures a frame.
- // |dirty| is false for timer polls and true for compositor updates.
- void Capture(bool dirty);
+ // Captures a frame. |event_time| is provided by the compositor, or is null
+ // for refresh requests.
+ void Capture(base::TimeTicks event_time);
// Update capture size. Must be called on the UI thread.
void UpdateCaptureSize();
@@ -79,35 +76,33 @@ class AuraWindowCaptureMachine
media::ThreadSafeCaptureOracle::CaptureFrameCallback;
// Response callback for cc::Layer::RequestCopyOfOutput().
- void DidCopyOutput(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result);
+ void DidCopyOutput(scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks event_time,
+ base::TimeTicks start_time,
+ const CaptureFrameCallback& capture_frame_cb,
+ std::unique_ptr<cc::CopyOutputResult> result);
// A helper which does the real work for DidCopyOutput. Returns true if
- // succeeded.
- bool ProcessCopyOutputResponse(
- scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks start_time,
- const CaptureFrameCallback& capture_frame_cb,
- scoped_ptr<cc::CopyOutputResult> result);
+ // succeeded and |capture_frame_cb| will be run at some future point. Returns
+ // false on error, and |capture_frame_cb| should be run by the caller (with
+ // failure status).
+ bool ProcessCopyOutputResponse(scoped_refptr<media::VideoFrame> video_frame,
+ base::TimeTicks event_time,
+ const CaptureFrameCallback& capture_frame_cb,
+ std::unique_ptr<cc::CopyOutputResult> result);
// Renders the cursor if needed and then delivers the captured frame.
static void CopyOutputFinishedForVideo(
base::WeakPtr<AuraWindowCaptureMachine> machine,
- base::TimeTicks start_time,
+ base::TimeTicks event_time,
const CaptureFrameCallback& capture_frame_cb,
const scoped_refptr<media::VideoFrame>& target,
- scoped_ptr<cc::SingleReleaseCallback> release_callback,
+ std::unique_ptr<cc::SingleReleaseCallback> release_callback,
bool result);
// The window associated with the desktop.
aura::Window* desktop_window_;
- // The timer that kicks off period captures.
- base::Timer timer_;
-
// Whether screen capturing or window capture.
bool screen_capture_;
@@ -118,14 +113,14 @@ class AuraWindowCaptureMachine
media::VideoCaptureParams capture_params_;
// YUV readback pipeline.
- scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
+ std::unique_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
// Renders mouse cursor on frame.
- scoped_ptr<content::CursorRendererAura> cursor_renderer_;
+ std::unique_ptr<content::CursorRendererAura> cursor_renderer_;
// TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
// screen from sleeping for the drive-by web.
- scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
// WeakPtrs are used for the asynchronous capture callbacks passed to external
// modules. They are only valid on the UI thread and become invalidated
diff --git a/chromium/content/browser/media/capture/cursor_renderer.h b/chromium/content/browser/media/capture/cursor_renderer.h
index 7416413f421..9ac912e68fe 100644
--- a/chromium/content/browser/media/capture/cursor_renderer.h
+++ b/chromium/content/browser/media/capture/cursor_renderer.h
@@ -21,6 +21,8 @@ namespace content {
// will listen to mouse events.
class CONTENT_EXPORT CursorRenderer {
public:
+ static std::unique_ptr<CursorRenderer> Create(gfx::NativeView view);
+
virtual ~CursorRenderer() {}
// Clears the cursor state being tracked. Called when there is a need to
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura.cc b/chromium/content/browser/media/capture/cursor_renderer_aura.cc
index 238ed9a1e52..6beceea099f 100644
--- a/chromium/content/browser/media/capture/cursor_renderer_aura.cc
+++ b/chromium/content/browser/media/capture/cursor_renderer_aura.cc
@@ -35,11 +35,24 @@ inline int alpha_blend(int alpha, int src, int dst) {
} // namespace
-CursorRendererAura::CursorRendererAura(aura::Window* window)
- : window_(window), tick_clock_(&default_tick_clock_), weak_factory_(this) {
+// static
+std::unique_ptr<CursorRenderer> CursorRenderer::Create(
+ gfx::NativeWindow window) {
+ return std::unique_ptr<CursorRenderer>(
+ new CursorRendererAura(window, kCursorEnabledOnMouseMovement));
+}
+
+CursorRendererAura::CursorRendererAura(
+ aura::Window* window,
+ CursorDisplaySetting cursor_display_setting)
+ : window_(window),
+ cursor_display_setting_(cursor_display_setting),
+ tick_clock_(&default_tick_clock_),
+ weak_factory_(this) {
if (window_) {
window_->AddObserver(this);
- window_->AddPreTargetHandler(this);
+ if (cursor_display_setting == kCursorEnabledOnMouseMovement)
+ window_->AddPreTargetHandler(this);
}
Clear();
}
@@ -47,7 +60,8 @@ CursorRendererAura::CursorRendererAura(aura::Window* window)
CursorRendererAura::~CursorRendererAura() {
if (window_) {
window_->RemoveObserver(this);
- window_->RemovePreTargetHandler(this);
+ if (cursor_display_setting_ == kCursorEnabledOnMouseMovement)
+ window_->RemovePreTargetHandler(this);
}
}
@@ -61,7 +75,11 @@ void CursorRendererAura::Clear() {
scaled_cursor_bitmap_.reset();
last_mouse_position_x_ = 0;
last_mouse_position_y_ = 0;
- cursor_displayed_ = false;
+ if (cursor_display_setting_ == kCursorEnabledOnMouseMovement) {
+ cursor_displayed_ = false;
+ } else {
+ cursor_displayed_ = true;
+ }
}
bool CursorRendererAura::SnapshotCursorState(const gfx::Rect& region_in_frame) {
@@ -94,6 +112,20 @@ bool CursorRendererAura::SnapshotCursorState(const gfx::Rect& region_in_frame) {
}
}
+ if (cursor_display_setting_ == kCursorEnabledOnMouseMovement) {
+ if (cursor_displayed_) {
+ // Stop displaying cursor if there has been no mouse movement
+ base::TimeDelta now = tick_clock_->NowTicks() - base::TimeTicks();
+ if ((now - last_mouse_movement_timestamp_) >
+ base::TimeDelta::FromSeconds(MAX_IDLE_TIME_SECONDS)) {
+ cursor_displayed_ = false;
+ DVLOG(2) << "Turning off cursor display after idle time";
+ }
+ }
+ if (!cursor_displayed_)
+ return false;
+ }
+
gfx::NativeCursor cursor = window_->GetHost()->last_cursor();
gfx::Point cursor_hot_point;
if (last_cursor_ != cursor ||
@@ -131,16 +163,7 @@ bool CursorRendererAura::SnapshotCursorState(const gfx::Rect& region_in_frame) {
cursor_position.y() * region_in_frame.height() /
window_bounds.height());
- if (cursor_displayed_) {
- // Stop displaying cursor if there has been no mouse movement
- base::TimeDelta now = tick_clock_->NowTicks() - base::TimeTicks();
- if ((now - last_mouse_movement_timestamp_) >
- base::TimeDelta::FromSeconds(MAX_IDLE_TIME_SECONDS)) {
- cursor_displayed_ = false;
- DVLOG(2) << "Turning off cursor display after idle time";
- }
- }
- return cursor_displayed_;
+ return true;
}
// Helper function to composite a cursor bitmap on a YUV420 video frame.
@@ -218,7 +241,8 @@ void CursorRendererAura::OnMouseEvent(ui::MouseEvent* event) {
void CursorRendererAura::OnWindowDestroying(aura::Window* window) {
DCHECK_EQ(window_, window);
- window_->RemovePreTargetHandler(this);
+ if (cursor_display_setting_ == kCursorEnabledOnMouseMovement)
+ window_->RemovePreTargetHandler(this);
window_->RemoveObserver(this);
window_ = nullptr;
}
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura.h b/chromium/content/browser/media/capture/cursor_renderer_aura.h
index 42dffa6b392..eaa1790d471 100644
--- a/chromium/content/browser/media/capture/cursor_renderer_aura.h
+++ b/chromium/content/browser/media/capture/cursor_renderer_aura.h
@@ -23,13 +23,21 @@
namespace content {
+// Setting to control cursor display based on either mouse movement or always
+// forced to be enabled.
+enum CursorDisplaySetting {
+ kCursorAlwaysEnabled,
+ kCursorEnabledOnMouseMovement
+};
+
// Tracks state for making decisions on cursor display on a captured video
// frame.
class CONTENT_EXPORT CursorRendererAura : public CursorRenderer,
public ui::EventHandler,
public aura::WindowObserver {
public:
- explicit CursorRendererAura(aura::Window* window);
+ explicit CursorRendererAura(aura::Window* window,
+ CursorDisplaySetting cursor_display);
~CursorRendererAura() final;
// CursorRender implementation.
@@ -64,6 +72,9 @@ class CONTENT_EXPORT CursorRendererAura : public CursorRenderer,
float last_mouse_position_y_;
bool cursor_displayed_;
+ // Controls whether cursor is displayed based on active mouse movement.
+ const CursorDisplaySetting cursor_display_setting_;
+
// Allows tests to replace the clock.
base::DefaultTickClock default_tick_clock_;
base::TickClock* tick_clock_;
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc b/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc
index bb210b9737e..c3989455eb8 100644
--- a/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc
+++ b/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc
@@ -6,8 +6,9 @@
#include <stdint.h>
+#include <memory>
+
#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
@@ -48,7 +49,8 @@ class CursorRendererAuraTest : public AuraTestBase {
window_.reset(aura::test::CreateTestWindowWithBounds(
gfx::Rect(0, 0, 800, 600), root_window()));
- cursor_renderer_.reset(new CursorRendererAura(window_.get()));
+ cursor_renderer_.reset(
+ new CursorRendererAura(window_.get(), kCursorEnabledOnMouseMovement));
new wm::DefaultActivationClient(root_window());
}
@@ -125,10 +127,36 @@ class CursorRendererAuraTest : public AuraTestBase {
}
protected:
- scoped_ptr<aura::Window> window_;
- scoped_ptr<CursorRendererAura> cursor_renderer_;
+ std::unique_ptr<aura::Window> window_;
+ std::unique_ptr<CursorRendererAura> cursor_renderer_;
};
+TEST_F(CursorRendererAuraTest, CursorAlwaysDisplayed) {
+ // Set up cursor renderer to always display cursor.
+ cursor_renderer_.reset(
+ new CursorRendererAura(window_.get(), kCursorAlwaysEnabled));
+
+ // Cursor displayed at start.
+ EXPECT_TRUE(CursorDisplayed());
+
+ base::SimpleTestTickClock clock;
+ SetTickClock(&clock);
+
+ // Cursor displayed after mouse movement.
+ MoveMouseCursorWithinWindow();
+ EXPECT_TRUE(CursorDisplayed());
+
+ // Cursor displayed after idle period.
+ clock.Advance(base::TimeDelta::FromSeconds(5));
+ SnapshotCursorState(gfx::Rect(10, 10, 200, 200));
+ EXPECT_TRUE(CursorDisplayed());
+
+ // Cursor displayed with mouse outside the window.
+ MoveMouseCursorOutsideWindow();
+ SnapshotCursorState(gfx::Rect(10, 10, 200, 200));
+ EXPECT_TRUE(CursorDisplayed());
+}
+
TEST_F(CursorRendererAuraTest, CursorDuringMouseMovement) {
// Keep window activated.
wm::ActivateWindow(window_.get());
@@ -166,7 +194,7 @@ TEST_F(CursorRendererAuraTest, CursorOnActiveWindow) {
EXPECT_TRUE(CursorDisplayed());
// Cursor not be displayed if a second window is activated.
- scoped_ptr<aura::Window> window2(aura::test::CreateTestWindowWithBounds(
+ std::unique_ptr<aura::Window> window2(aura::test::CreateTestWindowWithBounds(
gfx::Rect(0, 0, 800, 600), root_window()));
wm::ActivateWindow(window2.get());
SnapshotCursorState(gfx::Rect(10, 10, 200, 200));
@@ -200,4 +228,21 @@ TEST_F(CursorRendererAuraTest, CursorRenderedOnFrame) {
EXPECT_TRUE(NonZeroPixelsInRegion(frame, gfx::Rect(50, 50, 70, 70)));
}
+TEST_F(CursorRendererAuraTest, CursorRenderedOnRootWindow) {
+ cursor_renderer_.reset(new CursorRendererAura(root_window(),
+ kCursorEnabledOnMouseMovement));
+ EXPECT_FALSE(CursorDisplayed());
+
+ // Cursor displayed after mouse movement.
+ MoveMouseCursorWithinWindow();
+ EXPECT_TRUE(CursorDisplayed());
+
+ // Cursor being displayed even if another window is activated.
+ std::unique_ptr<aura::Window> window2(aura::test::CreateTestWindowWithBounds(
+ gfx::Rect(0, 0, 800, 600), root_window()));
+ wm::ActivateWindow(window2.get());
+ SnapshotCursorState(gfx::Rect(0, 0, 800, 600));
+ EXPECT_TRUE(CursorDisplayed());
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/capture/cursor_renderer_mac.h b/chromium/content/browser/media/capture/cursor_renderer_mac.h
new file mode 100644
index 00000000000..dc0ab1a322d
--- /dev/null
+++ b/chromium/content/browser/media/capture/cursor_renderer_mac.h
@@ -0,0 +1,48 @@
+// 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 CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/media/capture/cursor_renderer.h"
+#include "content/common/content_export.h"
+#include "media/base/video_frame.h"
+
+namespace content {
+
+// Tracks state for making decisions on cursor display on a captured video
+// frame.
+class CONTENT_EXPORT CursorRendererMac : public CursorRenderer {
+ public:
+ explicit CursorRendererMac(NSView* view);
+ ~CursorRendererMac() final;
+
+ // CursorRender implementation.
+ void Clear() final;
+ bool SnapshotCursorState(const gfx::Rect& region_in_frame) final;
+ void RenderOnVideoFrame(
+ const scoped_refptr<media::VideoFrame>& target) const final;
+ base::WeakPtr<CursorRenderer> GetWeakPtr() final;
+
+ private:
+ NSView* const view_;
+ base::ScopedCFTypeRef<CFDataRef> last_cursor_data_;
+ int last_cursor_width_;
+ int last_cursor_height_;
+ gfx::Point cursor_position_in_frame_;
+
+ base::TimeTicks last_mouse_movement_timestamp_;
+ float last_mouse_location_x_;
+ float last_mouse_location_y_;
+
+ base::WeakPtrFactory<CursorRendererMac> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(CursorRendererMac);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
diff --git a/chromium/content/browser/media/capture/cursor_renderer_mac.mm b/chromium/content/browser/media/capture/cursor_renderer_mac.mm
new file mode 100644
index 00000000000..b00394e592d
--- /dev/null
+++ b/chromium/content/browser/media/capture/cursor_renderer_mac.mm
@@ -0,0 +1,189 @@
+// 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 "content/browser/media/capture/cursor_renderer_mac.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <stdint.h>
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace content {
+
+namespace {
+
+// RGBA format on cursor bitmap
+const int kBytesPerPixel = 4;
+
+inline int clip_byte(int x) {
+ return std::max(0, std::min(x, 255));
+}
+
+inline int alpha_blend(int alpha, int src, int dst) {
+ return (src * alpha + dst * (255 - alpha)) / 255;
+}
+
+} // namespace
+
+// static
+std::unique_ptr<CursorRenderer> CursorRenderer::Create(gfx::NativeView view) {
+ return std::unique_ptr<CursorRenderer>(new CursorRendererMac(view));
+}
+
+CursorRendererMac::CursorRendererMac(NSView* view)
+ : view_(view), weak_factory_(this) {
+ Clear();
+}
+
+CursorRendererMac::~CursorRendererMac() {}
+
+base::WeakPtr<CursorRenderer> CursorRendererMac::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void CursorRendererMac::Clear() {
+ last_cursor_data_.reset();
+ last_cursor_width_ = 0;
+ last_cursor_height_ = 0;
+ last_mouse_location_x_ = 0;
+ last_mouse_location_y_ = 0;
+ last_mouse_movement_timestamp_ = base::TimeTicks();
+}
+
+// Polls mouse cursor location and image and returns whether the mouse
+// cursor should be rendered on the frame.
+bool CursorRendererMac::SnapshotCursorState(const gfx::Rect& region_in_frame) {
+ // Mouse location in window co-ordinates.
+ NSPoint mouse_window_location =
+ [view_ window].mouseLocationOutsideOfEventStream;
+
+ // Mouse co-ordinates directly comparable against frame co-ordinates
+ // after translation.
+ if (mouse_window_location.x < 0 || mouse_window_location.y < 0 ||
+ mouse_window_location.x > region_in_frame.width() ||
+ mouse_window_location.y > region_in_frame.height()) {
+ VLOG(2) << "Mouse outside content region";
+ return false;
+ }
+
+ if (![[view_ window] isKeyWindow]) {
+ VLOG(2) << "Window currently inactive";
+ return false;
+ }
+
+ if ((base::TimeTicks::Now() - last_mouse_movement_timestamp_).InSeconds() >
+ MAX_IDLE_TIME_SECONDS &&
+ std::abs(mouse_window_location.x - last_mouse_location_x_) <
+ MIN_MOVEMENT_PIXELS &&
+ std::abs(mouse_window_location.y - last_mouse_location_y_) <
+ MIN_MOVEMENT_PIXELS) {
+ VLOG(2) << "No mouse movement in a while";
+ return false;
+ }
+
+ // Mouse cursor position within the frame.
+ cursor_position_in_frame_ =
+ gfx::Point(region_in_frame.x() + mouse_window_location.x,
+ region_in_frame.y() + mouse_window_location.y);
+
+ // Grab system cursor.
+ NSCursor* nscursor = [NSCursor currentSystemCursor];
+ NSPoint nshotspot = [nscursor hotSpot];
+ NSImage* nsimage = [nscursor image];
+ NSSize nssize = [nsimage size];
+
+ // The cursor co-ordinates in the window and the video frame co-ordinates are
+ // inverted along y-axis. We render the cursor inverse vertically on the
+ // frame. Hence the inversion on hotspot offset here.
+ cursor_position_in_frame_.Offset(-nshotspot.x,
+ -(nssize.height - nshotspot.y));
+ last_cursor_width_ = nssize.width;
+ last_cursor_height_ = nssize.height;
+
+ CGImageRef cg_image =
+ [nsimage CGImageForProposedRect:NULL context:nil hints:nil];
+ if (!cg_image)
+ return false;
+
+ if (CGImageGetBitsPerPixel(cg_image) != kBytesPerPixel * 8 ||
+ CGImageGetBytesPerRow(cg_image) !=
+ static_cast<size_t>(kBytesPerPixel * nssize.width) ||
+ CGImageGetBitsPerComponent(cg_image) != 8) {
+ return false;
+ }
+
+ CGDataProviderRef provider = CGImageGetDataProvider(cg_image);
+ CFDataRef image_data_ref = CGDataProviderCopyData(provider);
+ if (!image_data_ref)
+ return false;
+ last_cursor_data_.reset(image_data_ref, base::scoped_policy::ASSUME);
+
+ if (std::abs(mouse_window_location.x - last_mouse_location_x_) >
+ MIN_MOVEMENT_PIXELS ||
+ std::abs(mouse_window_location.y - last_mouse_location_y_) >
+ MIN_MOVEMENT_PIXELS) {
+ last_mouse_movement_timestamp_ = base::TimeTicks::Now();
+ last_mouse_location_x_ = mouse_window_location.x;
+ last_mouse_location_y_ = mouse_window_location.y;
+ }
+ return true;
+}
+
+// Helper function to composite a RGBA cursor bitmap on a YUV420 video frame.
+void CursorRendererMac::RenderOnVideoFrame(
+ const scoped_refptr<media::VideoFrame>& target) const {
+ DCHECK(target);
+ DCHECK(last_cursor_data_);
+ const uint8_t* cursor_data_ =
+ reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(last_cursor_data_));
+
+ gfx::Rect visible_rect = target->visible_rect();
+ gfx::Rect rect =
+ gfx::IntersectRects(gfx::Rect(last_cursor_width_, last_cursor_height_) +
+ gfx::Vector2d(cursor_position_in_frame_.x(),
+ cursor_position_in_frame_.y()),
+ visible_rect);
+
+ for (int y = rect.y() + 1; y <= rect.bottom(); ++y) {
+ int cursor_y = rect.bottom() - y;
+ int inverted_y = visible_rect.bottom() - y;
+ uint8_t* yplane =
+ target->data(media::VideoFrame::kYPlane) +
+ inverted_y * target->row_bytes(media::VideoFrame::kYPlane);
+ uint8_t* uplane =
+ target->data(media::VideoFrame::kUPlane) +
+ (inverted_y / 2) * target->row_bytes(media::VideoFrame::kUPlane);
+ uint8_t* vplane =
+ target->data(media::VideoFrame::kVPlane) +
+ (inverted_y / 2) * target->row_bytes(media::VideoFrame::kVPlane);
+ for (int x = rect.x(); x < rect.right(); ++x) {
+ int cursor_x = x - rect.x();
+ int byte_pos = cursor_y * last_cursor_width_ * kBytesPerPixel +
+ cursor_x * kBytesPerPixel;
+ int color_r = cursor_data_[byte_pos];
+ int color_g = cursor_data_[byte_pos + 1];
+ int color_b = cursor_data_[byte_pos + 2];
+ int alpha = cursor_data_[byte_pos + 3];
+ int color_y = clip_byte(
+ ((color_r * 66 + color_g * 129 + color_b * 25 + 128) >> 8) + 16);
+ yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
+
+ // Only sample U and V at even coordinates.
+ if ((x % 2 == 0) && (y % 2 == 0)) {
+ int color_u = clip_byte(
+ ((color_r * -38 + color_g * -74 + color_b * 112 + 128) >> 8) + 128);
+ int color_v = clip_byte(
+ ((color_r * 112 + color_g * -94 + color_b * -18 + 128) >> 8) + 128);
+ uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
+ vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
+ }
+ }
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.cc b/chromium/content/browser/media/capture/desktop_capture_device.cc
index 9359b7c9c34..a76bc8d4fd9 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device.cc
@@ -64,20 +64,19 @@ bool IsFrameUnpackedOrInverted(webrtc::DesktopFrame* frame) {
class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
public:
Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- scoped_ptr<webrtc::DesktopCapturer> capturer,
+ std::unique_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type);
~Core() override;
// Implementation of VideoCaptureDevice methods.
void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client);
+ std::unique_ptr<Client> client);
void SetNotificationWindowId(gfx::NativeViewId window_id);
private:
// webrtc::DesktopCapturer::Callback interface
- webrtc::SharedMemory* CreateSharedMemory(size_t size) override;
void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
// Method that is scheduled on |task_runner_| to be called on regular interval
@@ -94,11 +93,11 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// The underlying DesktopCapturer instance used to capture frames.
- scoped_ptr<webrtc::DesktopCapturer> desktop_capturer_;
+ std::unique_ptr<webrtc::DesktopCapturer> desktop_capturer_;
// The device client which proxies device events to the controller. Accessed
// on the task_runner_ thread.
- scoped_ptr<Client> client_;
+ std::unique_ptr<Client> client_;
// Requested video capture frame rate.
float requested_frame_rate_;
@@ -107,12 +106,12 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
webrtc::DesktopSize previous_frame_size_;
// Determines the size of frames to deliver to the |client_|.
- scoped_ptr<media::CaptureResolutionChooser> resolution_chooser_;
+ std::unique_ptr<media::CaptureResolutionChooser> resolution_chooser_;
// DesktopFrame into which captured frames are down-scaled and/or letterboxed,
// depending upon the caller's requested capture capabilities. If frames can
// be returned to the caller directly then this is NULL.
- scoped_ptr<webrtc::DesktopFrame> output_frame_;
+ std::unique_ptr<webrtc::DesktopFrame> output_frame_;
// Timer used to capture the frame.
base::OneShotTimer capture_timer_;
@@ -127,18 +126,18 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
// The type of the capturer.
DesktopMediaID::Type capturer_type_;
- scoped_ptr<webrtc::BasicDesktopFrame> black_frame_;
+ std::unique_ptr<webrtc::BasicDesktopFrame> black_frame_;
// TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
// screen from sleeping for the drive-by web.
- scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
DesktopCaptureDevice::Core::Core(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- scoped_ptr<webrtc::DesktopCapturer> capturer,
+ std::unique_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type)
: task_runner_(task_runner),
desktop_capturer_(std::move(capturer)),
@@ -156,13 +155,13 @@ DesktopCaptureDevice::Core::~Core() {
void DesktopCaptureDevice::Core::AllocateAndStart(
const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
+ std::unique_ptr<Client> client) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_GT(params.requested_format.frame_size.GetArea(), 0);
DCHECK_GT(params.requested_format.frame_rate, 0);
DCHECK(desktop_capturer_);
- DCHECK(client.get());
- DCHECK(!client_.get());
+ DCHECK(client);
+ DCHECK(!client_);
client_ = std::move(client);
requested_frame_rate_ = params.requested_format.frame_rate;
@@ -188,11 +187,6 @@ void DesktopCaptureDevice::Core::SetNotificationWindowId(
desktop_capturer_->SetExcludedWindow(window_id);
}
-webrtc::SharedMemory*
-DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) {
- return NULL;
-}
-
void DesktopCaptureDevice::Core::OnCaptureCompleted(
webrtc::DesktopFrame* frame) {
DCHECK(task_runner_->BelongsToCurrentThread());
@@ -230,7 +224,7 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
}
- scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
+ std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
// If the frame size has changed, drop the output frame (if any), and
// determine the new output size.
@@ -253,7 +247,7 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
// it with a black frame to avoid the video appearing frozen at the last
// frame.
if (frame->size().width() == 1 || frame->size().height() == 1) {
- if (!black_frame_.get()) {
+ if (!black_frame_) {
black_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
memset(black_frame_->data(),
0,
@@ -362,7 +356,7 @@ void DesktopCaptureDevice::Core::DoCapture() {
}
// static
-scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
+std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
const DesktopMediaID& source) {
webrtc::DesktopCaptureOptions options =
webrtc::DesktopCaptureOptions::CreateDefault();
@@ -373,40 +367,40 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
options.set_allow_use_magnification_api(true);
#endif
- scoped_ptr<webrtc::DesktopCapturer> capturer;
-
- switch (source.type) {
- case DesktopMediaID::TYPE_SCREEN: {
- scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
- webrtc::ScreenCapturer::Create(options));
- if (screen_capturer && screen_capturer->SelectScreen(source.id)) {
- capturer.reset(new webrtc::DesktopAndCursorComposer(
- screen_capturer.release(),
- webrtc::MouseCursorMonitor::CreateForScreen(options, source.id)));
- IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED);
- }
- break;
- }
-
- case DesktopMediaID::TYPE_WINDOW: {
- scoped_ptr<webrtc::WindowCapturer> window_capturer(
- webrtc::CroppingWindowCapturer::Create(options));
- if (window_capturer && window_capturer->SelectWindow(source.id)) {
- window_capturer->BringSelectedWindowToFront();
- capturer.reset(new webrtc::DesktopAndCursorComposer(
- window_capturer.release(),
- webrtc::MouseCursorMonitor::CreateForWindow(options, source.id)));
- IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
- }
- break;
- }
-
- default: {
- NOTREACHED();
- }
+ std::unique_ptr<webrtc::DesktopCapturer> capturer;
+
+ switch (source.type) {
+ case DesktopMediaID::TYPE_SCREEN: {
+ std::unique_ptr<webrtc::ScreenCapturer> screen_capturer(
+ webrtc::ScreenCapturer::Create(options));
+ if (screen_capturer && screen_capturer->SelectScreen(source.id)) {
+ capturer.reset(new webrtc::DesktopAndCursorComposer(
+ screen_capturer.release(),
+ webrtc::MouseCursorMonitor::CreateForScreen(options,
+ source.id)));
+ IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED);
+ }
+ break;
+ }
+
+ case DesktopMediaID::TYPE_WINDOW: {
+ std::unique_ptr<webrtc::WindowCapturer> window_capturer(
+ webrtc::CroppingWindowCapturer::Create(options));
+ if (window_capturer && window_capturer->SelectWindow(source.id)) {
+ window_capturer->BringSelectedWindowToFront();
+ capturer.reset(new webrtc::DesktopAndCursorComposer(
+ window_capturer.release(),
+ webrtc::MouseCursorMonitor::CreateForWindow(options,
+ source.id)));
+ IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
+ }
+ break;
+ }
+
+ default: { NOTREACHED(); }
}
- scoped_ptr<media::VideoCaptureDevice> result;
+ std::unique_ptr<media::VideoCaptureDevice> result;
if (capturer)
result.reset(new DesktopCaptureDevice(std::move(capturer), source.type));
@@ -419,7 +413,7 @@ DesktopCaptureDevice::~DesktopCaptureDevice() {
void DesktopCaptureDevice::AllocateAndStart(
const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
+ std::unique_ptr<Client> client) {
thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&Core::AllocateAndStart, base::Unretained(core_.get()), params,
@@ -446,7 +440,7 @@ void DesktopCaptureDevice::SetNotificationWindowId(
}
DesktopCaptureDevice::DesktopCaptureDevice(
- scoped_ptr<webrtc::DesktopCapturer> capturer,
+ std::unique_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type)
: thread_("desktopCaptureThread") {
#if defined(OS_WIN)
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.h b/chromium/content/browser/media/capture/desktop_capture_device.h
index 7afdedc7f5a..2cb77e668bd 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
#include "content/public/browser/desktop_media_id.h"
@@ -33,14 +34,14 @@ class CONTENT_EXPORT DesktopCaptureDevice : public media::VideoCaptureDevice {
// Creates capturer for the specified |source| and then creates
// DesktopCaptureDevice for it. May return NULL in case of a failure (e.g. if
// requested window was destroyed).
- static scoped_ptr<media::VideoCaptureDevice> Create(
+ static std::unique_ptr<media::VideoCaptureDevice> Create(
const DesktopMediaID& source);
~DesktopCaptureDevice() override;
// VideoCaptureDevice interface.
void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) override;
+ std::unique_ptr<Client> client) override;
void StopAndDeAllocate() override;
// Set the platform-dependent window id for the notification window.
@@ -50,11 +51,12 @@ class CONTENT_EXPORT DesktopCaptureDevice : public media::VideoCaptureDevice {
friend class DesktopCaptureDeviceTest;
class Core;
- DesktopCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> desktop_capturer,
- DesktopMediaID::Type type);
+ DesktopCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer> desktop_capturer,
+ DesktopMediaID::Type type);
base::Thread thread_;
- scoped_ptr<Core> core_;
+ std::unique_ptr<Core> core_;
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDevice);
};
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_aura.cc b/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
index 39f7a07edf8..ac8929bfa8d 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/timer/timer.h"
#include "content/browser/media/capture/aura_window_capture_machine.h"
#include "content/public/browser/browser_thread.h"
@@ -30,7 +31,7 @@ void SetCaptureSource(AuraWindowCaptureMachine* machine,
DesktopCaptureDeviceAura::DesktopCaptureDeviceAura(
const DesktopMediaID& source) {
AuraWindowCaptureMachine* machine = new AuraWindowCaptureMachine();
- core_.reset(new media::ScreenCaptureDeviceCore(make_scoped_ptr(machine)));
+ core_.reset(new media::ScreenCaptureDeviceCore(base::WrapUnique(machine)));
// |core_| owns |machine| and deletes it on UI thread so passing the raw
// pointer to the UI thread is safe here.
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@@ -42,21 +43,25 @@ DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() {
}
// static
-scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDeviceAura::Create(
+std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDeviceAura::Create(
const DesktopMediaID& source) {
if (source.aura_id == DesktopMediaID::kNullId)
return nullptr;
- return scoped_ptr<media::VideoCaptureDevice>(
+ return std::unique_ptr<media::VideoCaptureDevice>(
new DesktopCaptureDeviceAura(source));
}
void DesktopCaptureDeviceAura::AllocateAndStart(
const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
+ std::unique_ptr<Client> client) {
DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
core_->AllocateAndStart(params, std::move(client));
}
+void DesktopCaptureDeviceAura::RequestRefreshFrame() {
+ core_->RequestRefreshFrame();
+}
+
void DesktopCaptureDeviceAura::StopAndDeAllocate() {
core_->StopAndDeAllocate();
}
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_aura.h b/chromium/content/browser/media/capture/desktop_capture_device_aura.h
index 82ce5956241..73a7d53761c 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.h
@@ -5,10 +5,10 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_AURA_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_AURA_H_
+#include <memory>
#include <string>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/desktop_media_id.h"
#include "media/capture/content/screen_capture_device_core.h"
@@ -26,20 +26,21 @@ class CONTENT_EXPORT DesktopCaptureDeviceAura
public:
// Creates a VideoCaptureDevice for the Aura desktop. If |source| does not
// reference a registered aura window, returns nullptr instead.
- static scoped_ptr<media::VideoCaptureDevice> Create(
+ static std::unique_ptr<media::VideoCaptureDevice> Create(
const DesktopMediaID& source);
~DesktopCaptureDeviceAura() override;
// VideoCaptureDevice implementation.
void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) override;
+ std::unique_ptr<Client> client) override;
+ void RequestRefreshFrame() override;
void StopAndDeAllocate() override;
private:
explicit DesktopCaptureDeviceAura(const DesktopMediaID& source);
- scoped_ptr<media::ScreenCaptureDeviceCore> core_;
+ std::unique_ptr<media::ScreenCaptureDeviceCore> core_;
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDeviceAura);
};
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc b/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc
index 43ed2aaef7d..e4bef80946c 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc
@@ -60,32 +60,41 @@ class MockDeviceClient : public media::VideoCaptureDevice::Client {
MOCK_METHOD0(DoReserveOutputBuffer, void(void));
MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
+ MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void));
MOCK_METHOD2(OnError,
void(const tracked_objects::Location& from_here,
const std::string& reason));
- // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
- scoped_ptr<Buffer> ReserveOutputBuffer(
+ // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
+ std::unique_ptr<Buffer> ReserveOutputBuffer(
const gfx::Size& dimensions,
media::VideoPixelFormat format,
media::VideoPixelStorage storage) override {
EXPECT_EQ(media::PIXEL_FORMAT_I420, format);
EXPECT_EQ(media::PIXEL_STORAGE_CPU, storage);
DoReserveOutputBuffer();
- return scoped_ptr<Buffer>();
+ return std::unique_ptr<Buffer>();
}
- void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp) override {
DoOnIncomingCapturedBuffer();
}
void OnIncomingCapturedVideoFrame(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp) override {
DoOnIncomingCapturedVideoFrame();
}
-
+ std::unique_ptr<Buffer> ResurrectLastOutputBuffer(
+ const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) override {
+ EXPECT_EQ(media::PIXEL_FORMAT_I420, format);
+ EXPECT_EQ(media::PIXEL_STORAGE_CPU, storage);
+ DoResurrectLastOutputBuffer();
+ return std::unique_ptr<Buffer>();
+ }
double GetBufferPoolUtilization() const override { return 0.0; }
};
@@ -133,21 +142,21 @@ class DesktopCaptureDeviceAuraTest : public testing::Test {
private:
base::MessageLoopForUI message_loop_;
BrowserThreadImpl browser_thread_for_ui_;
- scoped_ptr<aura::test::AuraTestHelper> helper_;
- scoped_ptr<aura::Window> desktop_window_;
- scoped_ptr<aura::test::TestWindowDelegate> window_delegate_;
+ std::unique_ptr<aura::test::AuraTestHelper> helper_;
+ std::unique_ptr<aura::Window> desktop_window_;
+ std::unique_ptr<aura::test::TestWindowDelegate> window_delegate_;
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDeviceAuraTest);
};
TEST_F(DesktopCaptureDeviceAuraTest, StartAndStop) {
- scoped_ptr<media::VideoCaptureDevice> capture_device =
+ std::unique_ptr<media::VideoCaptureDevice> capture_device =
DesktopCaptureDeviceAura::Create(
content::DesktopMediaID::RegisterAuraWindow(
content::DesktopMediaID::TYPE_SCREEN, root_window()));
- ASSERT_TRUE(capture_device.get());
+ ASSERT_TRUE(capture_device);
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_, _)).Times(0);
media::VideoCaptureParams capture_params;
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_uma_types.h b/chromium/content/browser/media/capture/desktop_capture_device_uma_types.h
index 0058e9121ec..2578d6ef745 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_uma_types.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device_uma_types.h
@@ -17,6 +17,9 @@ enum DesktopCaptureCounters {
FIRST_SCREEN_CAPTURE_FAILED,
FIRST_WINDOW_CAPTURE_SUCCEEDED,
FIRST_WINDOW_CAPTURE_FAILED,
+ TAB_VIDEO_CAPTURER_CREATED,
+ TAB_AUDIO_CAPTURER_CREATED,
+ SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED,
DESKTOP_CAPTURE_COUNTER_BOUNDARY
};
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
index c7b7877cc48..a1dc021360d 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -79,32 +79,41 @@ class MockDeviceClient : public media::VideoCaptureDevice::Client {
MOCK_METHOD0(DoReserveOutputBuffer, void(void));
MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
+ MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void));
MOCK_METHOD2(OnError,
void(const tracked_objects::Location& from_here,
const std::string& reason));
- // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
- scoped_ptr<Buffer> ReserveOutputBuffer(
+ // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
+ std::unique_ptr<Buffer> ReserveOutputBuffer(
const gfx::Size& dimensions,
media::VideoPixelFormat format,
media::VideoPixelStorage storage) override {
EXPECT_TRUE(format == media::PIXEL_FORMAT_I420 &&
storage == media::PIXEL_STORAGE_CPU);
DoReserveOutputBuffer();
- return scoped_ptr<Buffer>();
+ return std::unique_ptr<Buffer>();
}
- void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp) override {
DoOnIncomingCapturedBuffer();
}
void OnIncomingCapturedVideoFrame(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp) override {
DoOnIncomingCapturedVideoFrame();
}
-
+ std::unique_ptr<Buffer> ResurrectLastOutputBuffer(
+ const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) override {
+ EXPECT_TRUE(format == media::PIXEL_FORMAT_I420 &&
+ storage == media::PIXEL_STORAGE_CPU);
+ DoResurrectLastOutputBuffer();
+ return std::unique_ptr<Buffer>();
+ }
double GetBufferPoolUtilization() const override { return 0.0; }
};
@@ -143,7 +152,7 @@ class InvertedDesktopFrame : public webrtc::DesktopFrame {
~InvertedDesktopFrame() override {}
private:
- scoped_ptr<webrtc::DesktopFrame> original_frame_;
+ std::unique_ptr<webrtc::DesktopFrame> original_frame_;
DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
};
@@ -254,21 +263,22 @@ class FormatChecker {
class DesktopCaptureDeviceTest : public testing::Test {
public:
- void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
+ void CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer> capturer) {
capture_device_.reset(new DesktopCaptureDevice(
std::move(capturer), DesktopMediaID::TYPE_SCREEN));
}
void CopyFrame(const uint8_t* frame, int size,
const media::VideoCaptureFormat&, int, base::TimeTicks) {
- ASSERT_TRUE(output_frame_.get() != NULL);
+ ASSERT_TRUE(output_frame_);
ASSERT_EQ(output_frame_->stride() * output_frame_->size().height(), size);
memcpy(output_frame_->data(), frame, size);
}
protected:
- scoped_ptr<DesktopCaptureDevice> capture_device_;
- scoped_ptr<webrtc::DesktopFrame> output_frame_;
+ std::unique_ptr<DesktopCaptureDevice> capture_device_;
+ std::unique_ptr<webrtc::DesktopFrame> output_frame_;
};
// There is currently no screen capturer implementation for ozone. So disable
@@ -280,7 +290,7 @@ class DesktopCaptureDeviceTest : public testing::Test {
#define MAYBE_Capture Capture
#endif
TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
- scoped_ptr<webrtc::DesktopCapturer> capturer(
+ std::unique_ptr<webrtc::DesktopCapturer> capturer(
webrtc::ScreenCapturer::Create(
webrtc::DesktopCaptureOptions::CreateDefault()));
CreateScreenCaptureDevice(std::move(capturer));
@@ -289,7 +299,7 @@ TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
base::WaitableEvent done_event(false, false);
int frame_size;
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_, _)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(SaveArg<1>(&frame_size),
@@ -317,13 +327,14 @@ TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
- CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+ CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer>(mock_capturer));
FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
gfx::Size(kTestFrameWidth1, kTestFrameHeight1));
base::WaitableEvent done_event(false, false);
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_, _)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(WithArg<2>(Invoke(&format_checker,
@@ -358,12 +369,13 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) {
FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
- CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+ CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer>(mock_capturer));
FormatChecker format_checker(gfx::Size(888, 500), gfx::Size(532, 300));
base::WaitableEvent done_event(false, false);
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_,_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(WithArg<2>(Invoke(&format_checker,
@@ -401,13 +413,14 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) {
TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
- CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+ CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer>(mock_capturer));
FormatChecker format_checker(gfx::Size(kTestFrameWidth1, kTestFrameHeight1),
gfx::Size(kTestFrameWidth2, kTestFrameHeight2));
base::WaitableEvent done_event(false, false);
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_,_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(WithArg<2>(Invoke(&format_checker,
@@ -444,7 +457,8 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
mock_capturer->set_generate_cropped_frames(true);
- CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+ CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer>(mock_capturer));
media::VideoCaptureFormat format;
base::WaitableEvent done_event(false, false);
@@ -453,7 +467,7 @@ TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
output_frame_.reset(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_,_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
@@ -475,7 +489,7 @@ TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
// Verifies that |output_frame_| has the same data as a packed frame of the
// same size.
- scoped_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
+ std::unique_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
frame_size);
@@ -487,7 +501,8 @@ TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
mock_capturer->set_generate_inverted_frames(true);
- CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+ CreateScreenCaptureDevice(
+ std::unique_ptr<webrtc::DesktopCapturer>(mock_capturer));
media::VideoCaptureFormat format;
base::WaitableEvent done_event(false, false);
@@ -496,7 +511,7 @@ TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
output_frame_.reset(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
- scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
+ std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
EXPECT_CALL(*client, OnError(_,_)).Times(0);
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
@@ -517,7 +532,7 @@ TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
// Verifies that |output_frame_| has the same pixel values as the inverted
// frame.
- scoped_ptr<webrtc::DesktopFrame> inverted_frame(
+ std::unique_ptr<webrtc::DesktopFrame> inverted_frame(
new InvertedDesktopFrame(CreateBasicFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1))));
EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
diff --git a/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc b/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
index 50051a1a8cb..ce8f7f46419 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -4,13 +4,13 @@
#include "content/browser/media/capture/web_contents_audio_input_stream.h"
+#include <memory>
#include <string>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/capture/web_contents_tracker.h"
@@ -101,7 +101,7 @@ class WebContentsAudioInputStream::Impl
const scoped_refptr<WebContentsTracker> tracker_;
// The AudioInputStream implementation that handles the audio conversion and
// mixing details.
- const scoped_ptr<media::VirtualAudioInputStream> mixer_stream_;
+ const std::unique_ptr<media::VirtualAudioInputStream> mixer_stream_;
State state_;
@@ -131,8 +131,8 @@ WebContentsAudioInputStream::Impl::Impl(
is_target_lost_(false),
callback_(NULL) {
DCHECK(mirroring_manager_);
- DCHECK(tracker_.get());
- DCHECK(mixer_stream_.get());
+ DCHECK(tracker_);
+ DCHECK(mixer_stream_);
// WAIS::Impl can be constructed on any thread, but will DCHECK that all
// its methods from here on are called from the same thread.
@@ -228,23 +228,19 @@ void WebContentsAudioInputStream::Impl::ReportError() {
void WebContentsAudioInputStream::Impl::StartMirroring() {
DCHECK(thread_checker_.CalledOnValidThread());
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioMirroringManager::StartMirroring,
- base::Unretained(mirroring_manager_),
- make_scoped_refptr(this)));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioMirroringManager::StartMirroring,
+ base::Unretained(mirroring_manager_),
+ base::RetainedRef(this)));
}
void WebContentsAudioInputStream::Impl::StopMirroring() {
DCHECK(thread_checker_.CalledOnValidThread());
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioMirroringManager::StopMirroring,
- base::Unretained(mirroring_manager_),
- make_scoped_refptr(this)));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioMirroringManager::StopMirroring,
+ base::Unretained(mirroring_manager_),
+ base::RetainedRef(this)));
}
void WebContentsAudioInputStream::Impl::UnmuteWebContentsAudio() {
diff --git a/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
index 1e8ef1f8f3f..6ec220f767a 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -361,10 +361,10 @@ class WebContentsAudioInputStreamTest : public testing::Test {
change_callback_.Run(render_process_id != -1 && render_frame_id != -1);
}
- scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
+ std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
base::Thread audio_thread_;
- scoped_ptr<MockAudioMirroringManager> mock_mirroring_manager_;
+ std::unique_ptr<MockAudioMirroringManager> mock_mirroring_manager_;
scoped_refptr<MockWebContentsTracker> mock_tracker_;
MockVirtualAudioInputStream* mock_vais_; // Owned by wcais_.
diff --git a/chromium/content/browser/media/capture/web_contents_audio_muter.cc b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
index 82a03fa5cf2..e99c768d4bc 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_muter.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
@@ -55,7 +55,7 @@ class AudioDiscarder : public media::AudioOutputStream {
// Calls FetchAudioData() at regular intervals and discards the data.
media::FakeAudioWorker worker_;
- scoped_ptr<media::AudioBus> audio_bus_;
+ std::unique_ptr<media::AudioBus> audio_bus_;
DISALLOW_COPY_AND_ASSIGN(AudioDiscarder);
};
@@ -133,11 +133,10 @@ void WebContentsAudioMuter::StartMuting() {
return;
is_muting_ = true;
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(&AudioMirroringManager::StartMirroring,
base::Unretained(AudioMirroringManager::GetInstance()),
- destination_));
+ base::RetainedRef(destination_)));
}
void WebContentsAudioMuter::StopMuting() {
@@ -146,11 +145,10 @@ void WebContentsAudioMuter::StopMuting() {
return;
is_muting_ = false;
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
+ BrowserThread::IO, FROM_HERE,
base::Bind(&AudioMirroringManager::StopMirroring,
base::Unretained(AudioMirroringManager::GetInstance()),
- destination_));
+ base::RetainedRef(destination_)));
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/web_contents_tracker.cc b/chromium/content/browser/media/capture/web_contents_tracker.cc
index 5007a583af8..01bc9b0b461 100644
--- a/chromium/content/browser/media/capture/web_contents_tracker.cc
+++ b/chromium/content/browser/media/capture/web_contents_tracker.cc
@@ -24,10 +24,10 @@ WebContentsTracker::~WebContentsTracker() {
void WebContentsTracker::Start(int render_process_id, int main_render_frame_id,
const ChangeCallback& callback) {
- DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread());
+ DCHECK(!task_runner_ || task_runner_->BelongsToCurrentThread());
task_runner_ = base::ThreadTaskRunnerHandle::Get();
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
callback_ = callback;
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -81,7 +81,7 @@ RenderWidgetHost* WebContentsTracker::GetTargetRenderWidgetHost() const {
void WebContentsTracker::SetResizeChangeCallback(
const base::Closure& callback) {
- DCHECK(!task_runner_.get() || task_runner_->BelongsToCurrentThread());
+ DCHECK(!task_runner_ || task_runner_->BelongsToCurrentThread());
resize_callback_ = callback;
}
diff --git a/chromium/content/browser/media/capture/web_contents_video_capture_device.cc b/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
index bf2ef5ac662..0733a1fd9a9 100644
--- a/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -51,7 +51,9 @@
#include "content/browser/media/capture/web_contents_video_capture_device.h"
#include <stdint.h>
+
#include <algorithm>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -59,7 +61,6 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
@@ -93,11 +94,6 @@
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/size_conversions.h"
-#if defined(USE_AURA)
-#include "content/browser/media/capture/cursor_renderer_aura.h"
-#include "content/browser/media/capture/window_activity_tracker_aura.h"
-#endif
-
namespace content {
namespace {
@@ -110,7 +106,7 @@ enum InteractiveModeSettings {
kMinPeriodNoAnimationMillis = 3000
};
-void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
+void DeleteOnWorkerThread(std::unique_ptr<base::Thread> render_thread,
const base::Closure& callback) {
render_thread.reset();
@@ -188,19 +184,19 @@ class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
// knows how to do the capture and prepare the result for delivery.
//
// In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in
-// the RenderWidgetHostView, to process compositor updates, and (b) running a
-// timer to possibly initiate forced, non-event-driven captures needed by
-// downstream consumers that require frame repeats of unchanged content.
+// the RenderWidgetHostView, to process compositor updates, and (b) occasionally
+// initiating forced, non-event-driven captures needed by downstream consumers
+// that request "refresh frames" of unchanged content.
//
// All of this happens on the UI thread, although the
// RenderWidgetHostViewFrameSubscriber we install may be dispatching updates
// autonomously on some other thread.
class ContentCaptureSubscription {
public:
- typedef base::Callback<
- void(const base::TimeTicks&,
- const scoped_refptr<media::VideoFrame>&,
- const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)>
+ typedef base::Callback<void(
+ const base::TimeTicks&,
+ const scoped_refptr<media::VideoFrame>&,
+ const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)>
CaptureCallback;
// Create a subscription. Whenever a manual capture is required, the
@@ -212,8 +208,11 @@ class ContentCaptureSubscription {
const CaptureCallback& capture_callback);
~ContentCaptureSubscription();
+ void MaybeCaptureForRefresh();
+
private:
- void OnTimer();
+ // Called for active frame refresh requests, or mouse activity events.
+ void OnEvent(FrameSubscriber* subscriber);
// Maintain a weak reference to the RenderWidgetHost (via its routing ID),
// since the instance could be destroyed externally during the lifetime of
@@ -222,18 +221,18 @@ class ContentCaptureSubscription {
const int render_widget_id_;
VideoFrameDeliveryLog delivery_log_;
- scoped_ptr<FrameSubscriber> timer_subscriber_;
+ std::unique_ptr<FrameSubscriber> refresh_subscriber_;
+ std::unique_ptr<FrameSubscriber> mouse_activity_subscriber_;
CaptureCallback capture_callback_;
- base::Timer timer_;
// Responsible for tracking the cursor state and input events to make
// decisions and then render the mouse cursor on the video frame after
// capture is completed.
- scoped_ptr<content::CursorRenderer> cursor_renderer_;
+ std::unique_ptr<content::CursorRenderer> cursor_renderer_;
// Responsible for tracking the UI events and making a decision on whether
// user is actively interacting with content.
- scoped_ptr<content::WindowActivityTracker> window_activity_tracker_;
+ std::unique_ptr<content::WindowActivityTracker> window_activity_tracker_;
DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
};
@@ -269,6 +268,7 @@ class WebContentsCaptureMachine : public media::VideoCaptureMachine {
bool IsAutoThrottlingEnabled() const override {
return auto_throttling_enabled_;
}
+ void MaybeCaptureForRefresh() override;
// Starts a copy from the backing store or the composited surface. Must be run
// on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
@@ -285,6 +285,7 @@ class WebContentsCaptureMachine : public media::VideoCaptureMachine {
const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
const media::VideoCaptureParams& params);
void InternalStop(const base::Closure& callback);
+ void InternalMaybeCaptureForRefresh();
bool IsStarted() const;
// Computes the preferred size of the target RenderWidget for optimal capture.
@@ -329,7 +330,7 @@ class WebContentsCaptureMachine : public media::VideoCaptureMachine {
// A dedicated worker thread on which SkBitmap->VideoFrame conversion will
// occur. Only used when this activity cannot be done on the GPU.
- scoped_ptr<base::Thread> render_thread_;
+ std::unique_ptr<base::Thread> render_thread_;
// Makes all the decisions about which frames to copy, and how.
scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_;
@@ -342,7 +343,7 @@ class WebContentsCaptureMachine : public media::VideoCaptureMachine {
// Responsible for forwarding events from the active RenderWidgetHost to the
// oracle, and initiating captures accordingly.
- scoped_ptr<ContentCaptureSubscription> subscription_;
+ std::unique_ptr<ContentCaptureSubscription> subscription_;
// Weak pointer factory used to invalidate callbacks.
// NOTE: Weak pointers must be invalidated before all other member variables.
@@ -356,8 +357,8 @@ bool FrameSubscriber::ShouldCaptureFrame(
base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage,
DeliverFrameCallback* deliver_frame_cb) {
- TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame",
- "instance", this);
+ TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame", "instance",
+ this);
media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
@@ -405,17 +406,17 @@ void FrameSubscriber::DidCaptureFrame(
bool FrameSubscriber::IsUserInteractingWithContent() {
bool interactive_mode = false;
bool ui_activity = false;
- if (window_activity_tracker_.get()) {
+ if (window_activity_tracker_) {
ui_activity = window_activity_tracker_->IsUiInteractionActive();
}
- if (cursor_renderer_.get()) {
+ if (cursor_renderer_) {
bool animation_active =
(base::TimeTicks::Now() -
oracle_proxy_->last_time_animation_was_detected()) <
base::TimeDelta::FromMilliseconds(kMinPeriodNoAnimationMillis);
if (ui_activity && !animation_active) {
interactive_mode = true;
- } else if (animation_active) {
+ } else if (animation_active && window_activity_tracker_.get()) {
window_activity_tracker_->Reset();
}
}
@@ -429,39 +430,35 @@ ContentCaptureSubscription::ContentCaptureSubscription(
: render_process_id_(source.GetProcess()->GetID()),
render_widget_id_(source.GetRoutingID()),
delivery_log_(),
- capture_callback_(capture_callback),
- timer_(true, true) {
+ capture_callback_(capture_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderWidgetHostView* const view = source.GetView();
-// TODO(isheriff): Cursor resources currently only available on linux. Remove
-// this once we add the necessary resources for windows.
-// https://crbug.com/554280 https://crbug.com/549182
-#if defined(USE_AURA) && defined(OS_LINUX)
- if (view) {
- cursor_renderer_.reset(
- new content::CursorRendererAura(view->GetNativeView()));
- }
-#endif
-// TODO(isheriff): Needs implementation on non-aura platforms.
-// https://crbug.com/567735
-#if defined(USE_AURA)
+#if defined(USE_AURA) || defined(OS_MACOSX)
if (view) {
- window_activity_tracker_.reset(
- new content::WindowActivityTrackerAura(view->GetNativeView()));
+ cursor_renderer_ = CursorRenderer::Create(view->GetNativeView());
+ window_activity_tracker_ =
+ WindowActivityTracker::Create(view->GetNativeView());
}
#endif
- timer_subscriber_.reset(new FrameSubscriber(
- media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_,
+ refresh_subscriber_.reset(new FrameSubscriber(
+ media::VideoCaptureOracle::kActiveRefreshRequest, oracle_proxy,
+ &delivery_log_,
cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
: base::WeakPtr<CursorRenderer>(),
window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
: base::WeakPtr<WindowActivityTracker>()));
+ mouse_activity_subscriber_.reset(new FrameSubscriber(
+ media::VideoCaptureOracle::kMouseCursorUpdate, oracle_proxy,
+ &delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
+ : base::WeakPtr<CursorRenderer>(),
+ window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
+ : base::WeakPtr<WindowActivityTracker>()));
// Subscribe to compositor updates. These will be serviced directly by the
// oracle.
if (view) {
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
+ std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
new FrameSubscriber(
media::VideoCaptureOracle::kCompositorUpdate, oracle_proxy,
&delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
@@ -471,13 +468,12 @@ ContentCaptureSubscription::ContentCaptureSubscription(
view->BeginFrameSubscription(std::move(subscriber));
}
- // Subscribe to timer events. This instance will service these as well.
- timer_.Start(FROM_HERE,
- std::max(oracle_proxy->min_capture_period(),
- base::TimeDelta::FromMilliseconds(media
- ::VideoCaptureOracle::kMinTimerPollPeriodMillis)),
- base::Bind(&ContentCaptureSubscription::OnTimer,
- base::Unretained(this)));
+ // Subscribe to mouse movement and mouse cursor update events.
+ if (window_activity_tracker_) {
+ window_activity_tracker_->RegisterMouseInteractionObserver(
+ base::Bind(&ContentCaptureSubscription::OnEvent, base::Unretained(this),
+ mouse_activity_subscriber_.get()));
+ }
}
ContentCaptureSubscription::~ContentCaptureSubscription() {
@@ -495,16 +491,23 @@ ContentCaptureSubscription::~ContentCaptureSubscription() {
view->EndFrameSubscription();
}
-void ContentCaptureSubscription::OnTimer() {
+void ContentCaptureSubscription::MaybeCaptureForRefresh() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer");
+ OnEvent(refresh_subscriber_.get());
+}
+
+void ContentCaptureSubscription::OnEvent(FrameSubscriber* subscriber) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnEvent");
scoped_refptr<media::VideoFrame> frame;
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
const base::TimeTicks start_time = base::TimeTicks::Now();
- if (timer_subscriber_->ShouldCaptureFrame(gfx::Rect(), start_time, &frame,
- &deliver_frame_cb)) {
+ DCHECK(subscriber == refresh_subscriber_.get() ||
+ subscriber == mouse_activity_subscriber_.get());
+ if (subscriber->ShouldCaptureFrame(gfx::Rect(), start_time, &frame,
+ &deliver_frame_cb)) {
capture_callback_.Run(start_time, frame, deliver_frame_cb);
}
}
@@ -519,12 +522,10 @@ void RenderVideoFrame(
SkAutoLockPixels locker(input);
// Sanity-check the captured bitmap.
- if (input.empty() ||
- !input.readyToDraw() ||
- input.colorType() != kN32_SkColorType ||
- input.width() < 2 || input.height() < 2) {
- DVLOG(1) << "input unacceptable (size="
- << input.getSize()
+ if (input.empty() || !input.readyToDraw() ||
+ input.colorType() != kN32_SkColorType || input.width() < 2 ||
+ input.height() < 2) {
+ DVLOG(1) << "input unacceptable (size=" << input.getSize()
<< ", ready=" << input.readyToDraw()
<< ", colorType=" << input.colorType() << ')';
return;
@@ -555,11 +556,10 @@ void RenderVideoFrame(
method = skia::ImageOperations::RESIZE_BOX;
}
- TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture",
- "Capture", output.get(), "Scale");
- scaled_bitmap = skia::ImageOperations::Resize(input, method,
- region_in_frame.width(),
- region_in_frame.height());
+ TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", output.get(),
+ "Scale");
+ scaled_bitmap = skia::ImageOperations::Resize(
+ input, method, region_in_frame.width(), region_in_frame.height());
} else {
scaled_bitmap = input;
}
@@ -568,10 +568,9 @@ void RenderVideoFrame(
{
// Align to 2x2 pixel boundaries, as required by
// media::CopyRGBToVideoFrame().
- const gfx::Rect region_in_yv12_frame(region_in_frame.x() & ~1,
- region_in_frame.y() & ~1,
- region_in_frame.width() & ~1,
- region_in_frame.height() & ~1);
+ const gfx::Rect region_in_yv12_frame(
+ region_in_frame.x() & ~1, region_in_frame.y() & ~1,
+ region_in_frame.width() & ~1, region_in_frame.height() & ~1);
if (region_in_yv12_frame.IsEmpty())
return;
@@ -587,9 +586,7 @@ void RenderVideoFrame(
}
VideoFrameDeliveryLog::VideoFrameDeliveryLog()
- : last_frame_rate_log_time_(),
- count_frames_rendered_(0) {
-}
+ : last_frame_rate_log_time_(), count_frames_rendered_(0) {}
void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
// Log frame rate, if verbose logging is turned on.
@@ -602,11 +599,9 @@ void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
++count_frames_rendered_;
const base::TimeDelta elapsed = frame_time - last_frame_rate_log_time_;
if (elapsed >= kFrameRateLogInterval) {
- const double measured_fps =
- count_frames_rendered_ / elapsed.InSecondsF();
- UMA_HISTOGRAM_COUNTS(
- "TabCapture.FrameRate",
- static_cast<int>(measured_fps));
+ const double measured_fps = count_frames_rendered_ / elapsed.InSecondsF();
+ UMA_HISTOGRAM_COUNTS("TabCapture.FrameRate",
+ static_cast<int>(measured_fps));
VLOG(1) << "Current measured frame rate for "
<< "WebContentsVideoCaptureDevice is " << measured_fps << " FPS.";
last_frame_rate_log_time_ = frame_time;
@@ -624,8 +619,8 @@ WebContentsCaptureMachine::WebContentsCaptureMachine(
tracker_(new WebContentsTracker(true)),
auto_throttling_enabled_(enable_auto_throttling),
weak_ptr_factory_(this) {
- DVLOG(1) << "Created WebContentsCaptureMachine for "
- << render_process_id << ':' << main_render_frame_id
+ DVLOG(1) << "Created WebContentsCaptureMachine for " << render_process_id
+ << ':' << main_render_frame_id
<< (auto_throttling_enabled_ ? " with auto-throttling enabled" : "");
}
@@ -642,12 +637,9 @@ void WebContentsCaptureMachine::Start(
const base::Callback<void(bool)> callback) {
// Starts the capture machine asynchronously.
BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI,
- FROM_HERE,
+ BrowserThread::UI, FROM_HERE,
base::Bind(&WebContentsCaptureMachine::InternalStart,
- base::Unretained(this),
- oracle_proxy,
- params),
+ base::Unretained(this), oracle_proxy, params),
callback);
}
@@ -657,7 +649,7 @@ bool WebContentsCaptureMachine::InternalStart(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!IsStarted());
- DCHECK(oracle_proxy.get());
+ DCHECK(oracle_proxy);
oracle_proxy_ = oracle_proxy;
capture_params_ = params;
@@ -682,11 +674,9 @@ bool WebContentsCaptureMachine::InternalStart(
void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
// Stops the capture machine asynchronously.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, base::Bind(
- &WebContentsCaptureMachine::InternalStop,
- base::Unretained(this),
- callback));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebContentsCaptureMachine::InternalStop,
+ base::Unretained(this), callback));
}
void WebContentsCaptureMachine::InternalStop(const base::Closure& callback) {
@@ -708,14 +698,28 @@ void WebContentsCaptureMachine::InternalStop(const base::Closure& callback) {
// The render thread cannot be stopped on the UI thread, so post a message
// to the thread pool used for blocking operations.
- if (render_thread_.get()) {
+ if (render_thread_) {
BrowserThread::PostBlockingPoolTask(
- FROM_HERE,
- base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
- callback));
+ FROM_HERE, base::Bind(&DeleteOnWorkerThread,
+ base::Passed(&render_thread_), callback));
}
}
+void WebContentsCaptureMachine::MaybeCaptureForRefresh() {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebContentsCaptureMachine::InternalMaybeCaptureForRefresh,
+ // Use of Unretained() is safe here since this task must run
+ // before InternalStop().
+ base::Unretained(this)));
+}
+
+void WebContentsCaptureMachine::InternalMaybeCaptureForRefresh() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (IsStarted() && subscription_)
+ subscription_->MaybeCaptureForRefresh();
+}
+
void WebContentsCaptureMachine::Capture(
const base::TimeTicks& start_time,
const scoped_refptr<media::VideoFrame>& target,
@@ -736,29 +740,28 @@ void WebContentsCaptureMachine::Capture(
last_view_size_ = view_size;
// Measure the number of kilopixels.
- UMA_HISTOGRAM_COUNTS_10000(
- "TabCapture.ViewChangeKiloPixels",
- view_size.width() * view_size.height() / 1024);
+ UMA_HISTOGRAM_COUNTS_10000("TabCapture.ViewChangeKiloPixels",
+ view_size.width() * view_size.height() / 1024);
}
if (view->CanCopyToVideoFrame()) {
view->CopyFromCompositingSurfaceToVideoFrame(
- gfx::Rect(view_size),
- target,
+ gfx::Rect(view_size), target,
base::Bind(&WebContentsCaptureMachine::
- DidCopyFromCompositingSurfaceToVideoFrame,
- weak_ptr_factory_.GetWeakPtr(),
- start_time, deliver_frame_cb));
+ DidCopyFromCompositingSurfaceToVideoFrame,
+ weak_ptr_factory_.GetWeakPtr(), start_time,
+ deliver_frame_cb));
} else {
- const gfx::Size fitted_size = view_size.IsEmpty() ? gfx::Size() :
- media::ComputeLetterboxRegion(target->visible_rect(), view_size).size();
+ const gfx::Size fitted_size =
+ view_size.IsEmpty()
+ ? gfx::Size()
+ : media::ComputeLetterboxRegion(target->visible_rect(), view_size)
+ .size();
rwh->CopyFromBackingStore(
gfx::Rect(),
fitted_size, // Size here is a request not always honored.
base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore,
- weak_ptr_factory_.GetWeakPtr(),
- start_time,
- target,
+ weak_ptr_factory_.GetWeakPtr(), start_time, target,
deliver_frame_cb),
kN32_SkColorType);
}
@@ -784,18 +787,17 @@ gfx::Size WebContentsCaptureMachine::ComputeOptimalViewSize() const {
// issues caused by "one pixel stretching" and/or odd-to-even dimension
// scaling, and to improve the performance of consumers of the captured
// video.
- const auto HasIntendedAspectRatio =
- [](const gfx::Size& size, int width_units, int height_units) {
+ const auto HasIntendedAspectRatio = [](
+ const gfx::Size& size, int width_units, int height_units) {
const int a = height_units * size.width();
const int b = width_units * size.height();
const int percentage_diff = 100 * std::abs((a - b)) / b;
return percentage_diff <= 1; // Effectively, anything strictly <2%.
};
- const auto RoundToExactAspectRatio =
- [](const gfx::Size& size, int width_step, int height_step) {
- const int adjusted_height =
- std::max(size.height() - (size.height() % height_step),
- height_step);
+ const auto RoundToExactAspectRatio = [](const gfx::Size& size,
+ int width_step, int height_step) {
+ const int adjusted_height = std::max(
+ size.height() - (size.height() % height_step), height_step);
DCHECK_EQ((adjusted_height * width_step) % height_step, 0);
return gfx::Size(adjusted_height * width_step / height_step,
adjusted_height);
@@ -841,15 +843,15 @@ void WebContentsCaptureMachine::DidCopyFromBackingStore(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::TimeTicks now = base::TimeTicks::Now();
- DCHECK(render_thread_.get());
+ DCHECK(render_thread_);
if (response == READBACK_SUCCESS) {
UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
"Render");
render_thread_->task_runner()->PostTask(
FROM_HERE, media::BindToCurrentLoop(
- base::Bind(&RenderVideoFrame, bitmap, target,
- base::Bind(deliver_frame_cb, start_time))));
+ base::Bind(&RenderVideoFrame, bitmap, target,
+ base::Bind(deliver_frame_cb, start_time))));
} else {
// Capture can fail due to transient issues, so just skip this frame.
DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
@@ -903,9 +905,9 @@ void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
if (!had_subscription && tracker_->web_contents())
tracker_->web_contents()->IncrementCapturerCount(ComputeOptimalViewSize());
- subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
- base::Bind(&WebContentsCaptureMachine::Capture,
- weak_ptr_factory_.GetWeakPtr())));
+ subscription_.reset(new ContentCaptureSubscription(
+ *rwh, oracle_proxy_, base::Bind(&WebContentsCaptureMachine::Capture,
+ weak_ptr_factory_.GetWeakPtr())));
}
void WebContentsCaptureMachine::UpdateCaptureSize() {
@@ -938,10 +940,10 @@ WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
int main_render_frame_id,
bool enable_auto_throttling)
: core_(new media::ScreenCaptureDeviceCore(
- scoped_ptr<media::VideoCaptureMachine>(new WebContentsCaptureMachine(
- render_process_id,
- main_render_frame_id,
- enable_auto_throttling)))) {}
+ std::unique_ptr<media::VideoCaptureMachine>(
+ new WebContentsCaptureMachine(render_process_id,
+ main_render_frame_id,
+ enable_auto_throttling)))) {}
WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying.";
@@ -965,11 +967,15 @@ media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create(
void WebContentsVideoCaptureDevice::AllocateAndStart(
const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
+ std::unique_ptr<Client> client) {
DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
core_->AllocateAndStart(params, std::move(client));
}
+void WebContentsVideoCaptureDevice::RequestRefreshFrame() {
+ core_->RequestRefreshFrame();
+}
+
void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
core_->StopAndDeAllocate();
}
diff --git a/chromium/content/browser/media/capture/web_contents_video_capture_device.h b/chromium/content/browser/media/capture/web_contents_video_capture_device.h
index ab0e03ad7d4..ea92b3b2f0f 100644
--- a/chromium/content/browser/media/capture/web_contents_video_capture_device.h
+++ b/chromium/content/browser/media/capture/web_contents_video_capture_device.h
@@ -5,10 +5,10 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_VIDEO_CAPTURE_DEVICE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_VIDEO_CAPTURE_DEVICE_H_
+#include <memory>
#include <string>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "media/capture/content/screen_capture_device_core.h"
#include "media/capture/video/video_capture_device.h"
@@ -36,7 +36,8 @@ class CONTENT_EXPORT WebContentsVideoCaptureDevice
// VideoCaptureDevice implementation.
void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) override;
+ std::unique_ptr<Client> client) override;
+ void RequestRefreshFrame() override;
void StopAndDeAllocate() override;
private:
@@ -45,7 +46,7 @@ class CONTENT_EXPORT WebContentsVideoCaptureDevice
int main_render_frame_id,
bool enable_auto_throttling);
- const scoped_ptr<media::ScreenCaptureDeviceCore> core_;
+ const std::unique_ptr<media::ScreenCaptureDeviceCore> core_;
DISALLOW_COPY_AND_ASSIGN(WebContentsVideoCaptureDevice);
};
diff --git a/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 9e3bf83c461..81674324bd2 100644
--- a/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -6,11 +6,13 @@
#include <stddef.h>
#include <stdint.h>
+
#include <utility>
#include "base/bind_helpers.h"
#include "base/debug/debugger.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
@@ -22,8 +24,6 @@
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "content/public/test/mock_render_process_host.h"
@@ -60,7 +60,8 @@ const SkColor kNotInterested = ~kNothingYet;
void DeadlineExceeded(base::Closure quit_closure) {
if (!base::debug::BeingDebugged()) {
- quit_closure.Run();
+ if (!quit_closure.is_null())
+ quit_closure.Run();
FAIL() << "Deadline exceeded while waiting, quitting";
} else {
LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
@@ -94,8 +95,7 @@ class CaptureTestSourceController {
CaptureTestSourceController()
: color_(SK_ColorMAGENTA),
copy_result_size_(kTestWidth, kTestHeight),
- can_copy_to_video_frame_(false),
- use_frame_subscriber_(false) {}
+ can_copy_to_video_frame_(true) {}
void SetSolidColor(SkColor color) {
base::AutoLock guard(lock_);
@@ -136,16 +136,6 @@ class CaptureTestSourceController {
return can_copy_to_video_frame_;
}
- void SetUseFrameSubscriber(bool value) {
- base::AutoLock guard(lock_);
- use_frame_subscriber_ = value;
- }
-
- bool CanUseFrameSubscriber() {
- base::AutoLock guard(lock_);
- return use_frame_subscriber_;
- }
-
void WaitForNextCopy() {
{
base::AutoLock guard(lock_);
@@ -160,7 +150,6 @@ class CaptureTestSourceController {
SkColor color_;
gfx::Size copy_result_size_;
bool can_copy_to_video_frame_;
- bool use_frame_subscriber_;
base::Closure copy_done_;
DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
@@ -209,7 +198,8 @@ class CaptureTestView : public TestRenderWidgetHostView {
}
void BeginFrameSubscription(
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override {
+ std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber)
+ override {
subscriber_.reset(subscriber.release());
}
@@ -233,7 +223,7 @@ class CaptureTestView : public TestRenderWidgetHostView {
}
private:
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_;
+ std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber_;
CaptureTestSourceController* const controller_;
gfx::Rect fake_bounds_;
@@ -286,7 +276,7 @@ class CaptureTestRenderViewHost : public TestRenderViewHost {
bool swapped_out,
CaptureTestSourceController* controller)
: TestRenderViewHost(instance,
- make_scoped_ptr(new CaptureTestRenderWidgetHost(
+ base::WrapUnique(new CaptureTestRenderWidgetHost(
widget_delegate,
instance->GetProcess(),
routing_id,
@@ -368,30 +358,31 @@ class StubClient : public media::VideoCaptureDevice::Client {
MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> ReserveOutputBuffer(
- const gfx::Size& dimensions,
- media::VideoPixelFormat format,
- media::VideoPixelStorage storage) override {
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
+ ReserveOutputBuffer(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) override {
CHECK_EQ(format, media::PIXEL_FORMAT_I420);
int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId; // Ignored.
const int buffer_id = buffer_pool_->ReserveForProducer(
- format, storage, dimensions, &buffer_id_to_drop);
+ dimensions, format, storage, &buffer_id_to_drop);
if (buffer_id == VideoCaptureBufferPool::kInvalidId)
return NULL;
- return scoped_ptr<media::VideoCaptureDevice::Client::Buffer>(
+ return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
new AutoReleaseBuffer(
buffer_pool_, buffer_pool_->GetBufferHandle(buffer_id), buffer_id));
}
- // Trampoline method to workaround GMOCK problems with scoped_ptr<>.
- void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+
+ // Trampoline method to workaround GMOCK problems with std::unique_ptr<>.
+ void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp) override {
DoOnIncomingCapturedBuffer();
}
void OnIncomingCapturedVideoFrame(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp) override {
EXPECT_FALSE(frame->visible_rect().IsEmpty());
@@ -419,6 +410,20 @@ class StubClient : public media::VideoCaptureDevice::Client {
frame->visible_rect().size());
}
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
+ ResurrectLastOutputBuffer(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) override {
+ CHECK_EQ(format, media::PIXEL_FORMAT_I420);
+ const int buffer_id =
+ buffer_pool_->ResurrectLastForProducer(dimensions, format, storage);
+ if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+ return nullptr;
+ return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
+ new AutoReleaseBuffer(
+ buffer_pool_, buffer_pool_->GetBufferHandle(buffer_id), buffer_id));
+ }
+
void OnError(const tracked_objects::Location& from_here,
const std::string& reason) override {
error_callback_.Run();
@@ -431,21 +436,23 @@ class StubClient : public media::VideoCaptureDevice::Client {
public:
AutoReleaseBuffer(
const scoped_refptr<VideoCaptureBufferPool>& pool,
- scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
+ std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
int buffer_id)
: id_(buffer_id),
pool_(pool),
buffer_handle_(std::move(buffer_handle)) {
- DCHECK(pool_.get());
+ DCHECK(pool_);
}
int id() const override { return id_; }
- gfx::Size dimensions() const override { return gfx::Size(); }
+ gfx::Size dimensions() const override {
+ return buffer_handle_->dimensions();
+ }
size_t mapped_size() const override {
return buffer_handle_->mapped_size();
}
void* data(int plane) override { return buffer_handle_->data(plane); }
ClientBuffer AsClientBuffer(int plane) override { return nullptr; }
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
base::FileDescriptor AsPlatformFile() override {
return base::FileDescriptor();
}
@@ -456,7 +463,7 @@ class StubClient : public media::VideoCaptureDevice::Client {
const int id_;
const scoped_refptr<VideoCaptureBufferPool> pool_;
- const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
+ const std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
};
scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
@@ -470,8 +477,7 @@ class StubClientObserver {
public:
StubClientObserver()
: error_encountered_(false),
- wait_color_yuv_(0xcafe1950),
- wait_size_(kTestWidth, kTestHeight) {
+ wait_color_yuv_(0xcafe1950) {
client_.reset(new StubClient(
base::Bind(&StubClientObserver::DidDeliverFrame,
base::Unretained(this)),
@@ -480,34 +486,41 @@ class StubClientObserver {
virtual ~StubClientObserver() {}
- scoped_ptr<media::VideoCaptureDevice::Client> PassClient() {
+ std::unique_ptr<media::VideoCaptureDevice::Client> PassClient() {
return std::move(client_);
}
void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
base::AutoLock guard(lock_);
- if (error_encountered_)
- base::MessageLoop::current()->QuitWhenIdle();
- else if (wait_color_yuv_ == color && wait_size_.IsEmpty())
- base::MessageLoop::current()->QuitWhenIdle();
- else if (wait_color_yuv_ == color && wait_size_ == size)
+ if (error_encountered_ || wait_color_yuv_ == kNotInterested ||
+ wait_color_yuv_ == color) {
+ last_frame_color_yuv_ = color;
+ last_frame_size_ = size;
base::MessageLoop::current()->QuitWhenIdle();
+ }
}
- // Run the current loop until a frame is delivered with the |expected_color|
- // and any non-empty frame size.
- void WaitForNextColor(SkColor expected_color) {
- WaitForNextColorAndFrameSize(expected_color, gfx::Size());
+ // Run the current loop until the next frame is delivered. Returns the YUV
+ // color and frame size.
+ std::pair<SkColor, gfx::Size> WaitForNextFrame() {
+ {
+ base::AutoLock guard(lock_);
+ wait_color_yuv_ = kNotInterested;
+ error_encountered_ = false;
+ }
+ RunCurrentLoopWithDeadline();
+ {
+ base::AutoLock guard(lock_);
+ CHECK(!error_encountered_);
+ return std::make_pair(last_frame_color_yuv_, last_frame_size_);
+ }
}
- // Run the current loop until a frame is delivered with the |expected_color|
- // and is of the |expected_size|.
- void WaitForNextColorAndFrameSize(SkColor expected_color,
- const gfx::Size& expected_size) {
+ // Run the current loop until a frame is delivered with the |expected_color|.
+ void WaitForNextColor(SkColor expected_color) {
{
base::AutoLock guard(lock_);
wait_color_yuv_ = ConvertRgbToYuv(expected_color);
- wait_size_ = expected_size;
error_encountered_ = false;
}
RunCurrentLoopWithDeadline();
@@ -521,7 +534,6 @@ class StubClientObserver {
{
base::AutoLock guard(lock_);
wait_color_yuv_ = kNotInterested;
- wait_size_ = gfx::Size();
error_encountered_ = false;
}
RunCurrentLoopWithDeadline();
@@ -560,8 +572,9 @@ class StubClientObserver {
base::Lock lock_;
bool error_encountered_;
SkColor wait_color_yuv_;
- gfx::Size wait_size_;
- scoped_ptr<StubClient> client_;
+ SkColor last_frame_color_yuv_;
+ gfx::Size last_frame_size_;
+ std::unique_ptr<StubClient> client_;
DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
};
@@ -590,8 +603,8 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
test_screen_.display()->set_bounds(gfx::Rect(0, 0, 2560, 1440));
test_screen_.display()->set_device_scale_factor(kTestDeviceScaleFactor);
- gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, &test_screen_);
- ASSERT_EQ(&test_screen_, gfx::Screen::GetNativeScreen());
+ gfx::Screen::SetScreenInstance(&test_screen_);
+ ASSERT_EQ(&test_screen_, gfx::Screen::GetScreen());
// TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
// eliminated here, if only we could use RenderViewHostTestHarness. The
@@ -649,7 +662,7 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
render_view_host_factory_.reset();
render_process_host_factory_.reset();
- gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, NULL);
+ gfx::Screen::SetScreenInstance(nullptr);
}
// Accessors.
@@ -669,19 +682,30 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
}
void SimulateDrawEvent() {
- if (source()->CanUseFrameSubscriber()) {
- // Print
- CaptureTestView* test_view = static_cast<CaptureTestView*>(
- web_contents_->GetRenderViewHost()->GetWidget()->GetView());
- test_view->SimulateUpdate();
- } else {
- // Simulate a non-accelerated paint.
- NotificationService::current()->Notify(
- NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
- Source<RenderWidgetHost>(
- web_contents_->GetRenderViewHost()->GetWidget()),
- NotificationService::NoDetails());
- }
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Force at least one frame period's worth of time to pass. Otherwise,
+ // internal logic may decide not to capture a frame because the draw events
+ // are more frequent that kTestFramesPerSecond.
+ //
+ // TODO(miu): Instead of physically waiting, we should inject simulated
+ // clocks for testing.
+ base::RunLoop run_loop;
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ run_loop.QuitClosure(),
+ base::TimeDelta::FromMicroseconds(
+ base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
+ run_loop.Run();
+
+ // Schedule the update to occur when the test runs the event loop (and not
+ // before expectations have been set).
+ CaptureTestView* test_view = static_cast<CaptureTestView*>(
+ web_contents_->GetRenderViewHost()->GetWidget()->GetView());
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&CaptureTestView::SimulateUpdate,
+ base::Unretained(test_view)));
}
void SimulateSourceSizeChange(const gfx::Size& size) {
@@ -700,6 +724,45 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true);
}
+ // Repeatedly schedules draw events and scans for frames until the output from
+ // the capture device matches the given RGB |color| and frame |size|.
+ void SimulateDrawsUntilNewFrameSizeArrives(SkColor color,
+ const gfx::Size& size) {
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ while ((base::TimeTicks::Now() - start_time) <
+ TestTimeouts::action_max_timeout()) {
+ SimulateDrawEvent();
+ const auto color_and_size = client_observer()->WaitForNextFrame();
+ if (color_and_size.first == ConvertRgbToYuv(color) &&
+ color_and_size.second == size) {
+ return;
+ }
+ }
+ DeadlineExceeded(base::Closure());
+ }
+
+ void SimulateRefreshFrameRequest() {
+ // Force at least three frame period's worth of time to pass. The wait is
+ // needed because refresh frame requests are only honored when drawing
+ // events, which trigger frame captures, are not occurring frequently
+ // enough.
+ //
+ // TODO(miu): Instead of physically waiting, we should inject simulated
+ // clocks for testing.
+ base::RunLoop run_loop;
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ run_loop.QuitClosure(),
+ base::TimeDelta::FromMicroseconds(
+ 3 * base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
+ run_loop.Run();
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame,
+ base::Unretained(device_.get())));
+ }
+
void DestroyVideoCaptureDevice() { device_.reset(); }
StubClientObserver* client_observer() {
@@ -715,21 +778,21 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
CaptureTestSourceController controller_;
// Self-registering RenderProcessHostFactory.
- scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
+ std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
// Creates capture-capable RenderViewHosts whose pixel content production is
// under the control of |controller_|.
- scoped_ptr<CaptureTestRenderViewHostFactory> render_view_host_factory_;
+ std::unique_ptr<CaptureTestRenderViewHostFactory> render_view_host_factory_;
// Self-registering RenderFrameHostFactory.
- scoped_ptr<TestRenderFrameHostFactory> render_frame_host_factory_;
+ std::unique_ptr<TestRenderFrameHostFactory> render_frame_host_factory_;
// A mocked-out browser and tab.
- scoped_ptr<TestBrowserContext> browser_context_;
- scoped_ptr<WebContents> web_contents_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
+ std::unique_ptr<WebContents> web_contents_;
// Finally, the WebContentsVideoCaptureDevice under test.
- scoped_ptr<media::VideoCaptureDevice> device_;
+ std::unique_ptr<media::VideoCaptureDevice> device_;
TestBrowserThreadBundle thread_bundle_;
};
@@ -764,7 +827,9 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) {
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
- // Do one capture to prove
+
+ // Do one capture to prove the tab is initially open and being captured
+ // normally.
source()->SetSolidColor(SK_ColorRED);
SimulateDrawEvent();
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
@@ -804,9 +869,9 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
}
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
- // Set up the test to use RGB copies and an normal
+ // Set up the test to use RGB captures into SkBitmaps instead of YUV captures
+ // into VideoFrames.
source()->SetCanCopyToVideoFrame(false);
- source()->SetUseFrameSubscriber(false);
media::VideoCaptureParams capture_params;
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
@@ -815,7 +880,7 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
base::RunLoop().RunUntilIdle();
- for (int i = 0; i < 10; ++i)
+ for (int i = 0; i < 3; ++i)
SimulateDrawEvent();
ASSERT_FALSE(client_observer()->HasError());
@@ -861,8 +926,8 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, DeviceRestart) {
// The "happy case" test. No scaling is needed, so we should be able to change
// the picture emitted from the source and expect to see each delivered to the
-// consumer. The test will alternate between the three capture paths, simulating
-// falling in and out of accelerated compositing.
+// consumer. The test will alternate between the RGB/SkBitmap and YUV/VideoFrame
+// capture paths.
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
media::VideoCaptureParams capture_params;
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
@@ -870,26 +935,14 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
- for (int i = 0; i < 6; i++) {
+ for (int i = 0; i < 4; i++) {
const char* name = NULL;
- switch (i % 3) {
- case 0:
- source()->SetCanCopyToVideoFrame(true);
- source()->SetUseFrameSubscriber(false);
- name = "VideoFrame";
- break;
- case 1:
- source()->SetCanCopyToVideoFrame(false);
- source()->SetUseFrameSubscriber(true);
- name = "Subscriber";
- break;
- case 2:
- source()->SetCanCopyToVideoFrame(false);
- source()->SetUseFrameSubscriber(false);
- name = "SkBitmap";
- break;
- default:
- FAIL();
+ if (i % 2) {
+ source()->SetCanCopyToVideoFrame(false);
+ name = "SkBitmap";
+ } else {
+ source()->SetCanCopyToVideoFrame(true);
+ name = "VideoFrame";
}
SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
@@ -925,17 +978,18 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
// These frames ought to be dropped during the Render stage. Let
// several captures to happen.
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
+ for (int i = 0; i < 3; ++i) {
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
+ }
// Now push some good frames through; they should be processed normally.
source()->SetCopyResultSize(kTestWidth, kTestHeight);
source()->SetSolidColor(SK_ColorGREEN);
+ SimulateDrawEvent();
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
source()->SetSolidColor(SK_ColorRED);
+ SimulateDrawEvent();
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
device()->StopAndDeAllocate();
@@ -955,17 +1009,14 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
- source()->SetUseFrameSubscriber(true);
-
// Source size equals maximum size. Expect delivered frames to be
// kTestWidth by kTestHeight.
source()->SetSolidColor(SK_ColorRED);
const float device_scale_factor = GetDeviceScaleFactor();
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
// Source size is half in both dimensions. Expect delivered frames to be of
// the same aspect ratio as kTestWidth by kTestHeight, but larger than the
@@ -973,27 +1024,24 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
source()->SetSolidColor(SK_ColorGREEN);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180));
// Source size changes aspect ratio. Expect delivered frames to be padded
// in the horizontal dimension to preserve aspect ratio.
source()->SetSolidColor(SK_ColorBLUE);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight));
// Source size changes aspect ratio again. Expect delivered frames to be
// padded in the vertical dimension to preserve aspect ratio.
source()->SetSolidColor(SK_ColorBLACK);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth, kTestHeight / 2)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight));
device()->StopAndDeAllocate();
}
@@ -1012,26 +1060,22 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
- source()->SetUseFrameSubscriber(true);
-
// Source size equals maximum size. Expect delivered frames to be
// kTestWidth by kTestHeight.
source()->SetSolidColor(SK_ColorRED);
const float device_scale_factor = GetDeviceScaleFactor();
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
// Source size is half in both dimensions. Expect delivered frames to also
// be half in both dimensions.
source()->SetSolidColor(SK_ColorGREEN);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
+ SimulateDrawsUntilNewFrameSizeArrives(
+ SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2));
// Source size changes to something arbitrary. Since the source size is
// less than the maximum size, expect delivered frames to be the same size
@@ -1040,9 +1084,7 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
arbitrary_source_size));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
- SK_ColorBLUE, arbitrary_source_size));
+ SimulateDrawsUntilNewFrameSizeArrives(SK_ColorBLUE, arbitrary_source_size);
// Source size changes to something arbitrary that exceeds the maximum frame
// size. Since the source size exceeds the maximum size, expect delivered
@@ -1051,11 +1093,10 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
arbitrary_source_size = gfx::Size(kTestWidth * 2, kTestHeight / 2);
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
arbitrary_source_size));
- SimulateDrawEvent();
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
+ SimulateDrawsUntilNewFrameSizeArrives(
SK_ColorBLACK, gfx::Size(kTestWidth,
kTestWidth * arbitrary_source_size.height() /
- arbitrary_source_size.width())));
+ arbitrary_source_size.width()));
device()->StopAndDeAllocate();
}
@@ -1154,5 +1195,36 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
}
}
+// Tests the RequestRefreshFrame() functionality.
+TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, ProvidesRefreshFrames) {
+ media::VideoCaptureParams capture_params;
+ capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
+ capture_params.requested_format.frame_rate = kTestFramesPerSecond;
+ capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
+ device()->AllocateAndStart(capture_params, client_observer()->PassClient());
+
+ // Request a refresh frame before the first frame has been drawn. This forces
+ // a capture.
+ source()->SetSolidColor(SK_ColorRED);
+ SimulateRefreshFrameRequest();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
+
+ // Now, draw a frame and wait for a normal frame capture to occur.
+ source()->SetSolidColor(SK_ColorGREEN);
+ SimulateDrawEvent();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
+
+ // Now, make three more refresh frame requests. Although the source has
+ // changed to BLUE, no draw event has occurred. Therefore, expect the refresh
+ // frames to contain the content from the last drawn frame, which is GREEN.
+ source()->SetSolidColor(SK_ColorBLUE);
+ for (int i = 0; i < 3; ++i) {
+ SimulateRefreshFrameRequest();
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
+ }
+
+ device()->StopAndDeAllocate();
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/media/capture/window_activity_tracker.cc b/chromium/content/browser/media/capture/window_activity_tracker.cc
new file mode 100644
index 00000000000..394792d8a2e
--- /dev/null
+++ b/chromium/content/browser/media/capture/window_activity_tracker.cc
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/window_activity_tracker.h"
+
+#include "base/time/time.h"
+
+namespace content {
+
+namespace {
+
+// The time period within which a triggered UI event is considered
+// currently active.
+const int kTimePeriodUiEventMicros = 100000; // 100 ms
+
+// Minimum number of user interactions before we consider the user to be in
+// interactive mode. The goal is to prevent user interactions to launch
+// animated content from causing target playout time flip-flop.
+const int kMinUserInteractions = 5;
+
+} // namespace
+
+WindowActivityTracker::WindowActivityTracker() {
+ Reset();
+}
+
+WindowActivityTracker::~WindowActivityTracker() {}
+
+bool WindowActivityTracker::IsUiInteractionActive() const {
+ return ui_events_count_ > kMinUserInteractions;
+}
+
+void WindowActivityTracker::RegisterMouseInteractionObserver(
+ const base::Closure& observer) {
+ mouse_interaction_observer_ = observer;
+}
+
+void WindowActivityTracker::Reset() {
+ ui_events_count_ = 0;
+ last_time_ui_event_detected_ = base::TimeTicks();
+}
+
+void WindowActivityTracker::OnMouseActivity() {
+ if (!mouse_interaction_observer_.is_null())
+ mouse_interaction_observer_.Run();
+ if (base::TimeTicks::Now() - last_time_ui_event_detected_ >
+ base::TimeDelta::FromMicroseconds(kTimePeriodUiEventMicros)) {
+ ui_events_count_++;
+ }
+ last_time_ui_event_detected_ = base::TimeTicks::Now();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/window_activity_tracker.h b/chromium/content/browser/media/capture/window_activity_tracker.h
index 5fd9f0bc8d9..1d07a8ba512 100644
--- a/chromium/content/browser/media/capture/window_activity_tracker.h
+++ b/chromium/content/browser/media/capture/window_activity_tracker.h
@@ -5,9 +5,13 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_H_
+#include <memory>
+
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
+#include "ui/gfx/native_widget_types.h"
namespace content {
@@ -15,16 +19,39 @@ namespace content {
// whether the user is actively interacting with UI.
class CONTENT_EXPORT WindowActivityTracker {
public:
- virtual ~WindowActivityTracker() {}
+ static std::unique_ptr<WindowActivityTracker> Create(gfx::NativeView view);
+
+ WindowActivityTracker();
+ virtual ~WindowActivityTracker();
// Returns true if UI interaction is active.
- virtual bool IsUiInteractionActive() const = 0;
+ bool IsUiInteractionActive() const;
+
+ // Reports on every mouse movement activity on the window.
+ void RegisterMouseInteractionObserver(const base::Closure& observer);
// Resets any previous UI activity tracked.
- virtual void Reset() = 0;
+ void Reset();
// Returns a weak pointer.
virtual base::WeakPtr<WindowActivityTracker> GetWeakPtr() = 0;
+
+ protected:
+ void OnMouseActivity();
+
+ private:
+ // The last time a UI event was detected.
+ base::TimeTicks last_time_ui_event_detected_;
+
+ // Runs on any mouse interaction from user.
+ base::Closure mouse_interaction_observer_;
+
+ // The number of UI events detected so far. In case of continuous events
+ // such as mouse movement, a single continuous movement is treated
+ // as one event.
+ int ui_events_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowActivityTracker);
};
} // namespace content
diff --git a/chromium/content/browser/media/capture/window_activity_tracker_aura.cc b/chromium/content/browser/media/capture/window_activity_tracker_aura.cc
index e56e4a3f04c..e5a1783146a 100644
--- a/chromium/content/browser/media/capture/window_activity_tracker_aura.cc
+++ b/chromium/content/browser/media/capture/window_activity_tracker_aura.cc
@@ -11,21 +11,15 @@
namespace content {
-namespace {
-// The time period within which a triggered UI event is considered
-// currently active.
-const int kTimePeriodUiEventMicros = 100000; // 100 ms
-
-// Minimum number of user interactions before we consider the user to be in
-// interactive mode. The goal is to prevent user interactions to launch
-// animated content from causing target playout time flip-flop.
-const int kMinUserInteractions = 5;
-} // namespace
+// static
+std::unique_ptr<WindowActivityTracker> WindowActivityTracker::Create(
+ gfx::NativeView window) {
+ return std::unique_ptr<WindowActivityTracker>(
+ new WindowActivityTrackerAura(window));
+}
WindowActivityTrackerAura::WindowActivityTrackerAura(aura::Window* window)
: window_(window),
- last_time_ui_event_detected_(base::TimeTicks()),
- ui_events_count_(0),
weak_factory_(this) {
if (window_) {
window_->AddObserver(this);
@@ -44,21 +38,16 @@ base::WeakPtr<WindowActivityTracker> WindowActivityTrackerAura::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
-bool WindowActivityTrackerAura::IsUiInteractionActive() const {
- return ui_events_count_ > kMinUserInteractions;
-}
-
-void WindowActivityTrackerAura::Reset() {
- ui_events_count_ = 0;
- last_time_ui_event_detected_ = base::TimeTicks();
-}
-
void WindowActivityTrackerAura::OnEvent(ui::Event* event) {
- if (base::TimeTicks::Now() - last_time_ui_event_detected_ >
- base::TimeDelta::FromMicroseconds(kTimePeriodUiEventMicros)) {
- ui_events_count_++;
+ switch (event->type()) {
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_MOVED:
+ WindowActivityTracker::OnMouseActivity();
+ break;
+ default:
+ break;
}
- last_time_ui_event_detected_ = base::TimeTicks::Now();
}
void WindowActivityTrackerAura::OnWindowDestroying(aura::Window* window) {
diff --git a/chromium/content/browser/media/capture/window_activity_tracker_aura.h b/chromium/content/browser/media/capture/window_activity_tracker_aura.h
index c382c7a4bf6..be5f29c3567 100644
--- a/chromium/content/browser/media/capture/window_activity_tracker_aura.h
+++ b/chromium/content/browser/media/capture/window_activity_tracker_aura.h
@@ -24,9 +24,6 @@ class CONTENT_EXPORT WindowActivityTrackerAura : public WindowActivityTracker,
explicit WindowActivityTrackerAura(aura::Window* window);
~WindowActivityTrackerAura() final;
- // WindowActivityTracker overrides.
- bool IsUiInteractionActive() const final;
- void Reset() final;
base::WeakPtr<WindowActivityTracker> GetWeakPtr() final;
private:
@@ -38,14 +35,6 @@ class CONTENT_EXPORT WindowActivityTrackerAura : public WindowActivityTracker,
aura::Window* window_;
- // The last time a UI event was detected.
- base::TimeTicks last_time_ui_event_detected_;
-
- // The number of UI events detected so far. In case of continuous events
- // such as mouse movement, a single continuous movement is treated
- // as one event.
- int ui_events_count_;
-
base::WeakPtrFactory<WindowActivityTrackerAura> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowActivityTrackerAura);
diff --git a/chromium/content/browser/media/capture/window_activity_tracker_mac.h b/chromium/content/browser/media/capture/window_activity_tracker_mac.h
new file mode 100644
index 00000000000..64c91a03ea1
--- /dev/null
+++ b/chromium/content/browser/media/capture/window_activity_tracker_mac.h
@@ -0,0 +1,62 @@
+// 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 CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_MAC_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_MAC_H_
+
+#import <AppKit/AppKit.h>
+#import <CoreFoundation/CoreFoundation.h>
+
+#include "base/callback.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/media/capture/window_activity_tracker.h"
+#include "content/common/content_export.h"
+#include "ui/base/cocoa/tracking_area.h"
+#include "ui/gfx/native_widget_types.h"
+
+@interface MouseTracker : NSObject {
+ @private
+ ui::ScopedCrTrackingArea trackingArea_;
+
+ // The view on which mouse movement is detected.
+ NSView* nsView_;
+
+ // Runs on any mouse interaction from user.
+ base::Closure mouseInteractionObserver_;
+}
+
+- (instancetype)initWithView:(NSView*)nsView;
+
+// Register an observer for mouse interaction.
+- (void)registerMouseInteractionObserver:(const base::Closure&)observer;
+
+@end
+
+namespace content {
+
+// Tracks UI events and makes a decision on whether the user has been
+// actively interacting with a specified window.
+class CONTENT_EXPORT WindowActivityTrackerMac : public WindowActivityTracker {
+ public:
+ explicit WindowActivityTrackerMac(NSView* view);
+ ~WindowActivityTrackerMac() final;
+
+ base::WeakPtr<WindowActivityTracker> GetWeakPtr() final;
+
+ private:
+ void OnMouseActivity();
+
+ NSView* const view_;
+ base::scoped_nsobject<MouseTracker> mouse_tracker_;
+
+ base::WeakPtrFactory<WindowActivityTrackerMac> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowActivityTrackerMac);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_WINDOW_ACTIVITY_TRACKER_MAC_H_
diff --git a/chromium/content/browser/media/capture/window_activity_tracker_mac.mm b/chromium/content/browser/media/capture/window_activity_tracker_mac.mm
new file mode 100644
index 00000000000..a0ec7d31afc
--- /dev/null
+++ b/chromium/content/browser/media/capture/window_activity_tracker_mac.mm
@@ -0,0 +1,82 @@
+// 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 "content/browser/media/capture/window_activity_tracker_mac.h"
+
+#include <AppKit/AppKit.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/bind.h"
+#include "ui/base/cocoa/tracking_area.h"
+
+@implementation MouseTracker
+
+- (instancetype)initWithView:(NSView*)nsView {
+ self = [super init];
+ // TODO(isheriff): why are there no pressed/released events ?
+ NSTrackingAreaOptions trackingOptions =
+ NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect;
+ trackingArea_.reset([[CrTrackingArea alloc] initWithRect:NSZeroRect
+ options:trackingOptions
+ owner:self
+ userInfo:nil]);
+ [nsView addTrackingArea:trackingArea_.get()];
+ nsView_ = nsView;
+ return self;
+}
+
+- (void)stopTracking {
+ if (trackingArea_.get()) {
+ [nsView_ removeTrackingArea:trackingArea_.get()];
+ trackingArea_.reset();
+ }
+}
+
+- (void)registerMouseInteractionObserver:(const base::Closure&)observer {
+ mouseInteractionObserver_ = observer;
+}
+
+- (void)mouseMoved:(NSEvent*)theEvent {
+ mouseInteractionObserver_.Run();
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+}
+
+@end
+
+namespace content {
+
+// static
+std::unique_ptr<WindowActivityTracker> WindowActivityTracker::Create(
+ gfx::NativeView view) {
+ return std::unique_ptr<WindowActivityTracker>(
+ new WindowActivityTrackerMac(view));
+}
+
+WindowActivityTrackerMac::WindowActivityTrackerMac(NSView* view)
+ : view_(view), weak_factory_(this) {
+ mouse_tracker_.reset([[MouseTracker alloc] initWithView:view]);
+ [mouse_tracker_ registerMouseInteractionObserver:
+ base::Bind(&WindowActivityTrackerMac::OnMouseActivity,
+ base::Unretained(this))];
+}
+
+WindowActivityTrackerMac::~WindowActivityTrackerMac() {
+ [mouse_tracker_ stopTracking];
+}
+
+void WindowActivityTrackerMac::OnMouseActivity() {
+ WindowActivityTracker::OnMouseActivity();
+}
+
+base::WeakPtr<WindowActivityTracker> WindowActivityTrackerMac::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.cc b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
index 2f997d078ca..b2bc2c97c2e 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.cc
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
@@ -5,13 +5,14 @@
#include "content/browser/media/cdm/browser_cdm_manager.h"
#include <stddef.h>
+
+#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
#include "base/task_runner.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
@@ -72,7 +73,10 @@ class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> {
DCHECK(manager_);
}
- ~CdmPromiseInternal() final {}
+ ~CdmPromiseInternal() final {
+ if (!IsPromiseSettled())
+ RejectPromiseOnDestruction();
+ }
// CdmPromiseTemplate<> implementation.
void resolve(const T&... result) final;
@@ -88,7 +92,9 @@ class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> {
}
private:
+ using media::CdmPromiseTemplate<T...>::IsPromiseSettled;
using media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
+ using media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction;
base::WeakPtr<BrowserCdmManager> const manager_;
const int render_frame_id_;
@@ -370,7 +376,7 @@ void BrowserCdmManager::OnInitializeCdm(
DCHECK(task_runner_->RunsTasksOnCurrentThread());
DCHECK(!GetCdm(render_frame_id, cdm_id));
- scoped_ptr<SimplePromise> promise(new SimplePromise(
+ std::unique_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
if (params.key_system.size() > media::limits::kMaxKeySystemLength) {
@@ -412,7 +418,7 @@ void BrowserCdmManager::OnSetServerCertificate(
const std::vector<uint8_t>& certificate) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
- scoped_ptr<SimplePromise> promise(new SimplePromise(
+ std::unique_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
@@ -436,9 +442,9 @@ void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
int render_frame_id = params.render_frame_id;
int cdm_id = params.cdm_id;
const std::vector<uint8_t>& init_data = params.init_data;
- scoped_ptr<NewSessionPromise> promise(
- new NewSessionPromise(weak_ptr_factory_.GetWeakPtr(),
- render_frame_id, cdm_id, params.promise_id));
+ std::unique_ptr<NewSessionPromise> promise(
+ new NewSessionPromise(weak_ptr_factory_.GetWeakPtr(), render_frame_id,
+ cdm_id, params.promise_id));
if (init_data.size() > media::limits::kMaxInitDataLength) {
LOG(WARNING) << "InitData for ID: " << cdm_id
@@ -495,7 +501,7 @@ void BrowserCdmManager::OnLoadSession(
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
- scoped_ptr<NewSessionPromise> promise(new NewSessionPromise(
+ std::unique_ptr<NewSessionPromise> promise(new NewSessionPromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
@@ -519,7 +525,7 @@ void BrowserCdmManager::OnUpdateSession(int render_frame_id,
const std::vector<uint8_t>& response) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
- scoped_ptr<SimplePromise> promise(new SimplePromise(
+ std::unique_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
@@ -549,7 +555,7 @@ void BrowserCdmManager::OnCloseSession(int render_frame_id,
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
- scoped_ptr<SimplePromise> promise(new SimplePromise(
+ std::unique_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
@@ -567,7 +573,7 @@ void BrowserCdmManager::OnRemoveSession(int render_frame_id,
const std::string& session_id) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
- scoped_ptr<SimplePromise> promise(new SimplePromise(
+ std::unique_ptr<SimplePromise> promise(new SimplePromise(
weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id));
scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id);
@@ -588,7 +594,7 @@ void BrowserCdmManager::OnCdmCreated(
int render_frame_id,
int cdm_id,
const GURL& security_origin,
- scoped_ptr<media::SimpleCdmPromise> promise,
+ std::unique_ptr<media::SimpleCdmPromise> promise,
const scoped_refptr<media::MediaKeys>& cdm,
const std::string& error_message) {
if (!cdm) {
@@ -666,11 +672,12 @@ void BrowserCdmManager::CheckPermissionStatusOnUIThread(
return;
}
- PermissionStatus permission_status = permission_manager->GetPermissionStatus(
- PermissionType::PROTECTED_MEDIA_IDENTIFIER, security_origin,
- web_contents->GetLastCommittedURL().GetOrigin());
+ blink::mojom::PermissionStatus permission_status =
+ permission_manager->GetPermissionStatus(
+ PermissionType::PROTECTED_MEDIA_IDENTIFIER, security_origin,
+ web_contents->GetLastCommittedURL().GetOrigin());
- bool allowed = (permission_status == PERMISSION_STATUS_GRANTED);
+ bool allowed = (permission_status == blink::mojom::PermissionStatus::GRANTED);
if (!task_runner_->RunsTasksOnCurrentThread()) {
task_runner_->PostTask(FROM_HERE,
base::Bind(permission_status_cb, allowed));
@@ -685,7 +692,7 @@ void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted(
media::MediaKeys::SessionType session_type,
media::EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
- scoped_ptr<media::NewSessionCdmPromise> promise,
+ std::unique_ptr<media::NewSessionCdmPromise> promise,
bool permission_was_allowed) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
@@ -709,7 +716,7 @@ void BrowserCdmManager::LoadSessionIfPermitted(
int cdm_id,
media::MediaKeys::SessionType session_type,
const std::string& session_id,
- scoped_ptr<media::NewSessionCdmPromise> promise,
+ std::unique_ptr<media::NewSessionCdmPromise> promise,
bool permission_was_allowed) {
DCHECK_NE(media::MediaKeys::SessionType::TEMPORARY_SESSION, session_type);
DCHECK(task_runner_->RunsTasksOnCurrentThread());
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.h b/chromium/content/browser/media/cdm/browser_cdm_manager.h
index e3a986a6f7f..cdf088f3cb8 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.h
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.h
@@ -8,22 +8,22 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/common/media/cdm_messages.h"
#include "content/common/media/cdm_messages_enums.h"
#include "content/public/browser/browser_message_filter.h"
-#include "content/public/common/permission_status.mojom.h"
#include "ipc/ipc_message.h"
#include "media/base/cdm_promise.h"
#include "media/base/eme_constants.h"
#include "media/base/media_keys.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
#include "url/gurl.h"
struct CdmHostMsg_CreateSessionAndGenerateRequest_Params;
@@ -151,7 +151,7 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
void OnCdmCreated(int render_frame_id,
int cdm_id,
const GURL& security_origin,
- scoped_ptr<media::SimpleCdmPromise> promise,
+ std::unique_ptr<media::SimpleCdmPromise> promise,
const scoped_refptr<media::MediaKeys>& cdm,
const std::string& error_message);
@@ -184,17 +184,18 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
media::MediaKeys::SessionType session_type,
media::EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
- scoped_ptr<media::NewSessionCdmPromise> promise,
+ std::unique_ptr<media::NewSessionCdmPromise> promise,
bool permission_was_allowed);
// Calls LoadSession() on the CDM if |permission_was_allowed| is true.
// Otherwise rejects |promise|.
- void LoadSessionIfPermitted(int render_frame_id,
- int cdm_id,
- media::MediaKeys::SessionType session_type,
- const std::string& session_id,
- scoped_ptr<media::NewSessionCdmPromise> promise,
- bool permission_was_allowed);
+ void LoadSessionIfPermitted(
+ int render_frame_id,
+ int cdm_id,
+ media::MediaKeys::SessionType session_type,
+ const std::string& session_id,
+ std::unique_ptr<media::NewSessionCdmPromise> promise,
+ bool permission_was_allowed);
const int render_process_id_;
@@ -202,7 +203,7 @@ class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
// dispatched to the browser UI thread.
scoped_refptr<base::TaskRunner> task_runner_;
- scoped_ptr<media::CdmFactory> cdm_factory_;
+ std::unique_ptr<media::CdmFactory> cdm_factory_;
// The key in the following maps is a combination of |render_frame_id| and
// |cdm_id|.
diff --git a/chromium/content/browser/media/encrypted_media_browsertest.cc b/chromium/content/browser/media/encrypted_media_browsertest.cc
index 0f5316302d3..67ba9bbd9f9 100644
--- a/chromium/content/browser/media/encrypted_media_browsertest.cc
+++ b/chromium/content/browser/media/encrypted_media_browsertest.cc
@@ -12,6 +12,7 @@
#include "content/shell/browser/shell.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
+#include "media/base/media.h"
#endif
// Available key systems.
@@ -136,11 +137,8 @@ class EncryptedMediaTest : public content::MediaBrowserTest,
using ::testing::Combine;
using ::testing::Values;
-#if !defined(OS_ANDROID)
-// Encrypted media playback with SRC is not supported on Android.
INSTANTIATE_TEST_CASE_P(SRC_ClearKey, EncryptedMediaTest,
Combine(Values(kClearKeyKeySystem), Values(SRC)));
-#endif // !defined(OS_ANDROID)
INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
Combine(Values(kClearKeyKeySystem), Values(MSE)));
@@ -166,25 +164,25 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM_Opus) {
- // Opus is not supported on Android. http://crbug.com/318436
#if defined(OS_ANDROID)
- return;
+ if (!media::PlatformHasOpusSupport())
+ return;
#endif
TestSimplePlayback("bear-320x240-opus-a_enc-a.webm", kWebMAudioOnly);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {
- // Opus is not supported on Android. http://crbug.com/318436
#if defined(OS_ANDROID)
- return;
+ if (!media::PlatformHasOpusSupport())
+ return;
#endif
TestSimplePlayback("bear-320x240-opus-av_enc-av.webm", kWebMAudioVideo);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM_Opus) {
- // Opus is not supported on Android. http://crbug.com/318436
#if defined(OS_ANDROID)
- return;
+ if (!media::PlatformHasOpusSupport())
+ return;
#endif
TestSimplePlayback("bear-320x240-opus-av_enc-v.webm", kWebMAudioVideo);
}
@@ -193,9 +191,13 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
TestConfigChange();
}
+// Playback of this video on Android w/ Spitzer enabled causes glitches. See
+// http://crbug.com/598963.
+#if !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
TestFrameSizeChange();
}
+#endif
IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, UnknownKeySystemThrowsException) {
RunEncryptedMediaTest(kDefaultEmePlayer,
diff --git a/chromium/content/browser/media/media_browsertest.cc b/chromium/content/browser/media/media_browsertest.cc
index 43db9ad4f72..4f6779926ce 100644
--- a/chromium/content/browser/media/media_browsertest.cc
+++ b/chromium/content/browser/media/media_browsertest.cc
@@ -27,7 +27,7 @@ void MediaBrowserTest::RunMediaTestPage(const std::string& html_page,
bool http) {
GURL gurl;
std::string query = media::GetURLQueryString(query_params);
- scoped_ptr<net::EmbeddedTestServer> http_test_server;
+ std::unique_ptr<net::EmbeddedTestServer> http_test_server;
if (http) {
http_test_server.reset(new net::EmbeddedTestServer);
http_test_server->ServeFilesFromSourceDirectory(media::GetTestDataPath());
@@ -131,6 +131,10 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMp4) {
PlayVideo("bear.mp4", GetParam());
}
+IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearHighBitDepthMp4) {
+ PlayVideo("bear-320x180-hi10p.mp4", GetParam());
+}
+
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearSilentMp4) {
PlayVideo("bear_silent.mp4", GetParam());
}
@@ -259,6 +263,10 @@ IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pRec709H264) {
RunColorFormatTest("yuv420p_rec709.mp4", kEnded);
}
+IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pHighBitDepth) {
+ RunColorFormatTest("yuv420p_hi10p.mp4", kEnded);
+}
+
IN_PROC_BROWSER_TEST_F(MediaTest, Yuvj420pH264) {
RunColorFormatTest("yuvj420p.mp4", kEnded);
}
diff --git a/chromium/content/browser/media/media_canplaytype_browsertest.cc b/chromium/content/browser/media/media_canplaytype_browsertest.cc
index 83493ccc317..7dba85b1d1a 100644
--- a/chromium/content/browser/media/media_canplaytype_browsertest.cc
+++ b/chromium/content/browser/media/media_canplaytype_browsertest.cc
@@ -21,25 +21,25 @@ const char kMaybe[] = "maybe";
const char kNot[] = "";
#if defined(USE_PROPRIETARY_CODECS)
-const char kPropProbably[] = "probably";
-const char kPropMaybe[] = "maybe";
+const char* kPropProbably = kProbably;
+const char* kPropMaybe = kMaybe;
#else
-const char kPropProbably[] = "";
-const char kPropMaybe[] = "";
+const char* kPropProbably = kNot;
+const char* kPropMaybe = kNot;
#endif // USE_PROPRIETARY_CODECS
#if !defined(OS_ANDROID)
-const char kOggVideoProbably[] = "probably";
-const char kOggVideoMaybe[] = "maybe";
-const char kTheoraProbably[] = "probably";
-const char kOggOpusProbably[] = "probably";
-const char* kMpeg2AacProbably = kPropProbably;
+const char* kOggVideoProbably = kProbably;
+const char* kOggVideoMaybe = kMaybe;
+const char* kTheoraProbably = kProbably;
+const char* kHlsProbably = kNot;
+const char* kHlsMaybe = kNot;
#else
-const char kOggVideoProbably[] = "";
-const char kOggVideoMaybe[] = "";
-const char kTheoraProbably[] = "";
-const char kOggOpusProbably[] = "";
-const char kMpeg2AacProbably[] = "";
+const char* kOggVideoProbably = kNot;
+const char* kOggVideoMaybe = kNot;
+const char* kTheoraProbably = kNot;
+const char* kHlsProbably = kPropProbably;
+const char* kHlsMaybe = kPropMaybe;
#endif // !OS_ANDROID
#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
@@ -69,6 +69,15 @@ const char* kMp2tsAc3Eac3Probably = kPropProbably;
const char* kMp2tsAc3Eac3Probably = kNot;
#endif
+// High 10-bit profile is only available when we can use ffmpeg to decode H.264.
+// Even though FFmpeg is used on Android, we only use platform decoders for
+// H.264
+#if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID)
+const char* kHi10pProbably = kPropProbably;
+#else
+const char* kHi10pProbably = kPropMaybe;
+#endif
+
namespace content {
class MediaCanPlayTypeTest : public MediaBrowserTest {
@@ -136,6 +145,16 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.300.30\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.-1.30\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.x.30\"'"));
+ // Old-style avc1 codec ids are supported only for video/mp2t container.
+ if (mime != "video/mp2t") {
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.66.13\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.77.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.100.40\"'"));
+ }
+ // Old-style codec ids are not supported for avc3 codec strings.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.66.13\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.77.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.100.40\"'"));
// AAC codecs must be followed by one or two valid hexadecimal numbers.
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.no\"'"));
@@ -174,6 +193,19 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\";mp4a.40+\"'"));
// Codecs not belonging to MPEG container.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, 1\"'"));
+
+ // Remove all but "audio/mpeg" when https://crbug.com/592889 is fixed.
+ if (mime != "audio/mpeg" && mime != "audio/mp4" && mime != "video/mp4" &&
+ mime != "application/x-mpegurl" &&
+ mime != "application/vnd.apple.mpegurl" && mime != "video/mp2t") {
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp3\"'"));
+ }
+
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, vorbis\"'"));
@@ -195,12 +227,6 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, mp4a.40.02\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, 1\"'"));
-
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, mp4a.40.2\"'"));
@@ -299,36 +325,47 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
void TestOGGUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to OGG container.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, vorbis\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9, vorbis\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.66.30\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, 1\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8.0\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, vorbis\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9.0\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, vorbis\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0,opus\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0,opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp3\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.6B\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
@@ -337,54 +374,59 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, 1\"'"));
-
// Codecs are case sensitive.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"Theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"Theora, Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"Theora, Vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"Theora\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"Opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"Vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"Theora, Opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"Theora, Vorbis\"'"));
// Unknown codecs.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
}
void TestWEBMUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to WEBM container.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9.0, 1\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, opus\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.66.30\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8.0, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9.0, 1\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, opus\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0,opus\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0,opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8, mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9, mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0, mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9.0, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp3\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.6B\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8.0, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9.0, mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
@@ -394,43 +436,51 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
// Codecs are case sensitive.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP8, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP8.0, Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP9, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP9.0, Opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"VP8, Vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"VP8.0, Opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"VP9, Vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"VP9.0, Opus\"'"));
// Unknown codec.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
}
void TestWAVUnacceptableCombinations(const std::string& mime) {
// Codecs not belonging to WAV container.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9.0, 1\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, 1\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1.66.30\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc1, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8.0, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9.0, 1\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, 1\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, 1\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hev1.1.6.L93.B0,opus\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"hvc1.1.6.L93.B0,opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp3\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.6B\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
@@ -440,7 +490,7 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
// Unknown codec.
- EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
}
private:
@@ -461,45 +511,31 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_wav) {
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
- // On Android, VP9 is supported only on KitKat and above (API level 19) and
- // Opus is supported only on Lollipop and above (API level 21).
- std::string VP9Probably = "probably";
- std::string VP9AndOpusProbably = "probably";
- std::string OpusProbably = "probably";
-#if defined(OS_ANDROID)
- if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
- VP9Probably = "";
- if (base::android::BuildInfo::GetInstance()->sdk_int() < 21) {
- OpusProbably = "";
- VP9AndOpusProbably = "";
- }
-#endif
EXPECT_EQ(kMaybe, CanPlay("'video/webm'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8\"'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0\"'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8, vorbis\"'"));
EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0, vorbis\"'"));
- EXPECT_EQ(OpusProbably, CanPlay("'video/webm; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(OpusProbably, CanPlay("'video/webm; codecs=\"vp8.0, opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8, opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0, opus\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9.0\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9, vorbis\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp9.0, vorbis\"'"));
- EXPECT_EQ(VP9AndOpusProbably, CanPlay("'video/webm; codecs=\"vp9, opus\"'"));
- EXPECT_EQ(VP9AndOpusProbably,
- CanPlay("'video/webm; codecs=\"vp9.0, opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9.0\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9, vorbis\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9.0, vorbis\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9, opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp9.0, opus\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp8, vp9\"'"));
- EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp8.0, vp9.0\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8, vp9\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"vp8.0, vp9.0\"'"));
TestWEBMUnacceptableCombinations("video/webm");
EXPECT_EQ(kMaybe, CanPlay("'audio/webm'"));
EXPECT_EQ(kProbably, CanPlay("'audio/webm; codecs=\"vorbis\"'"));
- EXPECT_EQ(OpusProbably, CanPlay("'audio/webm; codecs=\"opus\"'"));
- EXPECT_EQ(OpusProbably, CanPlay("'audio/webm; codecs=\"opus, vorbis\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'audio/webm; codecs=\"opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'audio/webm; codecs=\"opus, vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp8\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp8.0\"'"));
@@ -532,8 +568,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kMaybe, CanPlay("'audio/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"vorbis\"'"));
- EXPECT_EQ(kOggOpusProbably, CanPlay("'audio/ogg; codecs=\"opus\"'"));
- EXPECT_EQ(kOggOpusProbably, CanPlay("'audio/ogg; codecs=\"vorbis, opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"vorbis, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora, opus\"'"));
@@ -544,13 +580,12 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kMaybe, CanPlay("'application/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'application/ogg; codecs=\"vorbis\"'"));
EXPECT_EQ(kTheoraProbably, CanPlay("'application/ogg; codecs=\"theora\"'"));
- EXPECT_EQ(kOggOpusProbably, CanPlay("'application/ogg; codecs=\"opus\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'application/ogg; codecs=\"opus\"'"));
EXPECT_EQ(kTheoraProbably,
CanPlay("'application/ogg; codecs=\"theora, vorbis\"'"));
EXPECT_EQ(kTheoraProbably,
CanPlay("'application/ogg; codecs=\"theora, opus\"'"));
- EXPECT_EQ(kOggOpusProbably,
- CanPlay("'application/ogg; codecs=\"opus, vorbis\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'application/ogg; codecs=\"opus, vorbis\"'"));
TestOGGUnacceptableCombinations("application/ogg");
}
@@ -572,8 +607,13 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.68\"'"));
+ // The next two results are wrong due to https://crbug.com/592889.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.6B\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.02\"'"));
@@ -587,12 +627,17 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.6B\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.40.02\"'"));
TestMPEGUnacceptableCombinations("audio/mp3");
+ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp3\"'"));
// audio/x-mp3 does not allow any codecs parameter
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-mp3'"));
@@ -602,12 +647,17 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1.66.30\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.6B\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.40.02\"'"));
TestMPEGUnacceptableCombinations("audio/x-mp3");
+ EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp3\"'"));
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
@@ -621,18 +671,19 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, avc3\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42F01E\"'"));
+
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E01E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42801E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42C01E\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.66.13\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.77.30\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.100.40\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E11E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42101E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42701E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42F01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.6B\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.02\"'"));
@@ -691,6 +742,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
CanPlay("'video/mp4; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'"));
TestMPEGUnacceptableCombinations("video/mp4");
+ // This result is incorrect. See https://crbug.com/592889.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp3\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v'"));
@@ -702,18 +755,19 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, avc3\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42F01E\"'"));
+
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.42E01E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.42801E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.42C01E\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.66.13\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.77.30\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.100.40\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1.42E11E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42101E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42701E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42F01E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.6B\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.40.02\"'"));
@@ -737,37 +791,35 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe,
CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40\"'"));
- EXPECT_EQ(kHevcSupported,
- CanPlay("'video/x-m4v; codecs=\"hev1.1.6.L93.B0\"'"));
- EXPECT_EQ(kHevcSupported,
- CanPlay("'video/x-m4v; codecs=\"hvc1.1.6.L93.B0\"'"));
- EXPECT_EQ(kHevcSupported,
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"hev1.1.6.L93.B0\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"hvc1.1.6.L93.B0\"'"));
+ EXPECT_EQ(kNot,
CanPlay("'video/x-m4v; codecs=\"hev1.1.6.L93.B0, mp4a.40.5\"'"));
- EXPECT_EQ(kHevcSupported,
+ EXPECT_EQ(kNot,
CanPlay("'video/x-m4v; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"ac-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.a5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.A5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"ec-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.a6\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.A6\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,ac-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a5\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A5\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,ec-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a6\"'"));
- EXPECT_EQ(kAc3Eac3Probably,
- CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A6\"'"));
TestMPEGUnacceptableCombinations("video/x-m4v");
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'"));
+
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.02\"'"));
@@ -782,7 +834,6 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1.66.30\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"hev1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"hvc1.1.6.L93.B0\"'"));
@@ -797,8 +848,17 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"mp4a.A6\"'"));
TestMPEGUnacceptableCombinations("audio/mp4");
+ // This result is incorrect. See https://crbug.com/592889.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp3\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a'"));
+
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.6B\"'"));
+
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.02\"'"));
@@ -813,7 +873,6 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1.66.30\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"hev1.1.6.L93.B0\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"hvc1.1.6.L93.B0\"'"));
@@ -822,27 +881,32 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot,
CanPlay("'audio/x-m4a; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"ac-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.a5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.A5\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"ec-3\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.a6\"'"));
- EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.A6\"'"));
TestMPEGUnacceptableCombinations("audio/x-m4a");
}
-// When modifying this test, also change CodecSupportTest_Avc3Variants.
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc1Variants) {
// avc1 without extensions results in "maybe" for compatibility.
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1\"'"));
- // Any 6-digit hexadecimal number will result in at least "maybe".
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.123456\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.ABCDEF\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.abcdef\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.12345\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.1234567\"'"));
+ // A valid-looking 6-digit hexadecimal number will result in at least "maybe".
+ // But the first hex byte after the dot must be a valid profile_idc and the
+ // lower two bits of the second byte/4th digit must be zero.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42AC23\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42ACDF\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42acdf\"'"));
+
+ // Invalid profile 0x12.
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.123456\"'"));
+ // Valid profile/level, but reserved bits are set to 1 (4th digit after dot).
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.42011E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.42021E\"'"));
// Both upper and lower case hexadecimal digits are accepted.
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
@@ -856,68 +920,97 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc1Variants) {
//
// Baseline Profile (66 == 0x42).
- // The first two digits must be 42. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 42. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42401E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42801E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.42G01E\"'"));
-
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E11E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.42000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E0FF\"'"));
//
// Main Profile (77 == 0x4D).
- // The first two digits must be 4D. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 4D. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D400A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D800A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4DE00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.4DG01E\"'"));
-
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4DE11E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.4D000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.4DE0FF\"'"));
//
// High Profile (100 == 0x64).
- // The first two digits must be 64. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 64. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64400A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64800A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.64E00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.64G01E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.64000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.64E0FF\"'"));
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.64E11E\"'"));
+ //
+ // High 10-bit Profile (110 == 0x6E).
+ // The first two digits after the dot must be 6E. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
+ //
+ EXPECT_EQ(kHi10pProbably, CanPlay("'video/mp4; codecs=\"avc1.6E001E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.6E400A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.6E800A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.6EE00A\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.6EG01E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc1.6E000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.6EE0FF\"'"));
//
// Other profiles are not known to be supported.
//
// Extended Profile (88 == 0x58).
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.58A01E\"'"));
+ // Without any constraint flags.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.58001E\"'"));
+ // With constraint_set0_flag==1 indicating compatibility with baseline
+ // profile.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.58801E\"'"));
+ // With constraint_set1_flag==1 indicating compatibility with main profile.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.58401E\"'"));
+ // With constraint_set2_flag==1 indicating compatibility with extended
+ // profile, the result is 'maybe' the same as for straight extended profile.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.58201E\"'"));
}
-// When modifying this test, also change CodecSupportTest_Avc1Variants.
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc3Variants) {
// avc3 without extensions results in "maybe" for compatibility.
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3\"'"));
- // Any 6-digit hexadecimal number will result in at least "maybe".
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.123456\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.ABCDEF\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.abcdef\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.12345\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.1234567\"'"));
+ // A valid-looking 6-digit hexadecimal number will result in at least "maybe".
+ // But the first hex byte after the dot must be a valid profile_idc and the
+ // lower two bits of the second byte/4th digit must be zero.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42AC23\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42ACDF\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42acdf\"'"));
+
+ // Invalid profile 0x12.
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.123456\"'"));
+ // Valid profile/level, but reserved bits are set to 1 (4th digit after dot).
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.42011E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.42021E\"'"));
// Both upper and lower case hexadecimal digits are accepted.
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E01E\"'"));
@@ -931,55 +1024,79 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Avc3Variants) {
//
// Baseline Profile (66 == 0x42).
- // The first two digits must be 42. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 42. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42400A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42800A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.42E00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.42G01E\"'"));
-
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42E11E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.42000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.42E0FF\"'"));
//
// Main Profile (77 == 0x4D).
- // The first two digits must be 4D. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 4D. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4D001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4D400A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4D800A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.4DE00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.4DG01E\"'"));
-
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4DE11E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.4D000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.4DE0FF\"'"));
//
// High Profile (100 == 0x64).
- // The first two digits must be 64. The third digit (constraint_set_flags)
- // must be valid hex but it otherwise is ignored. The fourth digit (reserved)
- // must be 0. The last two digits must be any valid level.
+ // The first two digits after the dot must be 64. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
//
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64001E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64400A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64800A\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64E00A\"'"));
EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.64G01E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.64000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.64E0FF\"'"));
- // The fourth digit must be 0.
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.64E11E\"'"));
+ //
+ // High 10-bit Profile (110 == 0x6E).
+ // The first two digits after the dot must be 6E. The third and fourth digits
+ // contain constraint_set_flags and must be valid hex. The last two digits
+ // should be any valid H.264 level. If the level value is invalid the result
+ // will be kMaybe.
+ //
+ EXPECT_EQ(kHi10pProbably, CanPlay("'video/mp4; codecs=\"avc3.6E001E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.6E400A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.6E800A\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.6EE00A\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.6EG01E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/mp4; codecs=\"avc3.6E000G\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.6EE0FF\"'"));
//
// Other profiles are not known to be supported.
//
// Extended Profile (88 == 0x58).
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.58A01E\"'"));
+ // Without any constraint flags.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.58001E\"'"));
+ // With constraint_set0_flag==1 indicating compatibility with baseline
+ // profile.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.58801E\"'"));
+ // With constraint_set1_flag==1 indicating compatibility with main profile.
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.58401E\"'"));
+ // With constraint_set2_flag==1 indicating compatibility with extended
+ // profile, the result is 'maybe' the same as for straight extended profile.
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3.58201E\"'"));
}
// Tests AVC levels using AVC1 Baseline (0x42E0zz).
@@ -1080,10 +1197,10 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mp4aVariants) {
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.63\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.65\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.65\"'"));
- // MPEG2 AAC Main, LC, and SSR are supported except on Android.
- EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.66\"'"));
- EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'"));
- EXPECT_EQ(kMpeg2AacProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'"));
+ // MPEG2 AAC Main, LC, and SSR are supported.
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'"));
// MP3.
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6A\"'"));
@@ -1133,9 +1250,11 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mp4aVariants) {
// See http://crbug.com/440607.
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.00\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.01\"'"));
+ // MPEG4 AAC LC.
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.03\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.04\"'"));
+ // MPEG4 AAC SBR v1.
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.05\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.40.029\"'"));
@@ -1151,59 +1270,62 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mp4aVariants) {
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
- // HLS are supported only on Android IceCreamSandwich and above (API level 14)
- std::string probablyCanPlayHLS = kNot;
- std::string maybeCanPlayHLS = kNot;
-#if defined(OS_ANDROID)
- if (base::android::BuildInfo::GetInstance()->sdk_int() > 13) {
- probablyCanPlayHLS = kProbably;
- maybeCanPlayHLS = kMaybe;
- }
-#endif
- EXPECT_EQ(maybeCanPlayHLS, CanPlay("'application/x-mpegurl'"));
-
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc1\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc3\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/x-mpegurl'"));
+
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/x-mpegurl; codecs=\"avc1\"'"));
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/x-mpegurl; codecs=\"avc3\"'"));
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/x-mpegurl; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42F01E\"'"));
+
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42801E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42C01E\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.42E11E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.42101E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.42701E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.42F01E\"'"));
+ // Android, is the only platform that supports these types, and its HLS
+ // implementations uses platform codecs, which do not include MPEG-2 AAC.
+ // See https://crbug.com/544268.
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.68\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/x-mpegurl; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/x-mpegurl; codecs=\"mp4a.6B\"'"));
+
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"mp4a.40.02\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(
+ kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(
+ kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40.02\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(
+ kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(
+ kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.05\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(
+ kHlsProbably,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.29\"'"));
EXPECT_EQ(kNot,
@@ -1222,77 +1344,98 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.a5\"'"));
EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.a6\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.02\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40.02\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40\"'"));
TestMPEGUnacceptableCombinations("application/x-mpegurl");
+ // This result is incorrect. See https://crbug.com/592889.
+ EXPECT_EQ(kHlsProbably, CanPlay("'application/x-mpegurl; codecs=\"mp3\"'"));
- EXPECT_EQ(maybeCanPlayHLS, CanPlay("'application/vnd.apple.mpegurl'"));
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/vnd.apple.mpegurl'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42E01E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42F01E\"'"));
+
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42E01E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42801E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42C01E\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42E11E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42101E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42701E\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42F01E\"'"));
+ // Android, is the only platform that supports these types, and its HLS
+ // implementations uses platform codecs, which do not include MPEG-2 AAC.
+ // See https://crbug.com/544268.
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.68\"'"));
+
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.6B\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.02\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.5\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.05\"'"));
- EXPECT_EQ(probablyCanPlayHLS,
+ EXPECT_EQ(kHlsProbably,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.29\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40.02\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
+ EXPECT_EQ(
+ kHlsMaybe,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40.02\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; "
- "codecs=\"avc1.42E01E, mp4a.40\"'"));
- EXPECT_EQ(maybeCanPlayHLS,
- CanPlay("'application/vnd.apple.mpegurl; "
- "codecs=\"avc3.42E01E, mp4a.40\"'"));
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/vnd.apple.mpegurl; "
+ "codecs=\"avc1.42E01E, mp4a.40\"'"));
+ EXPECT_EQ(kHlsMaybe, CanPlay("'application/vnd.apple.mpegurl; "
+ "codecs=\"avc3.42E01E, mp4a.40\"'"));
EXPECT_EQ(kNot,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"hev1.1.6.L93.B0\"'"));
@@ -1317,6 +1460,9 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.a6\"'"));
TestMPEGUnacceptableCombinations("application/vnd.apple.mpegurl");
+ // This result is incorrect. See https://crbug.com/592889.
+ EXPECT_EQ(kHlsProbably,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp3\"'"));
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_AAC_ADTS) {
@@ -1336,6 +1482,13 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mpeg2Ts) {
EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"avc1.42E01E\"'"));
EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"avc1.4D401E\"'"));
EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"avc1.640028\"'"));
+
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.66\"'"));
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.67\"'"));
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.68\"'"));
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.69\"'"));
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.6B\"'"));
+
// AAC LC audio
EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp4a.40.2\"'"));
// H.264 + AAC audio combinations
@@ -1360,6 +1513,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mpeg2Ts) {
CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.a6\"'"));
TestMPEGUnacceptableCombinations("video/mp2t");
+ // This result is incorrect. See https://crbug.com/592889.
+ EXPECT_EQ(kMp2tsProbably, CanPlay("'video/mp2t; codecs=\"mp3\"'"));
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest,
diff --git a/chromium/content/browser/media/media_internals.cc b/chromium/content/browser/media/media_internals.cc
index c6455766ce2..02e40ce350a 100644
--- a/chromium/content/browser/media/media_internals.cc
+++ b/chromium/content/browser/media/media_internals.cc
@@ -123,10 +123,11 @@ class AudioLogImpl : public media::AudioLog {
void StoreComponentMetadata(int component_id, base::DictionaryValue* dict);
std::string FormatCacheKey(int component_id);
- static void SendWebContentsTitleHelper(const std::string& cache_key,
- scoped_ptr<base::DictionaryValue> dict,
- int render_process_id,
- int render_frame_id);
+ static void SendWebContentsTitleHelper(
+ const std::string& cache_key,
+ std::unique_ptr<base::DictionaryValue> dict,
+ int render_process_id,
+ int render_frame_id);
const int owner_id_;
const media::AudioLogFactory::AudioComponent component_;
@@ -208,7 +209,7 @@ void AudioLogImpl::OnSwitchOutputDevice(int component_id,
void AudioLogImpl::SendWebContentsTitle(int component_id,
int render_process_id,
int render_frame_id) {
- scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
StoreComponentMetadata(component_id, dict.get());
SendWebContentsTitleHelper(FormatCacheKey(component_id), std::move(dict),
render_process_id, render_frame_id);
@@ -221,7 +222,7 @@ std::string AudioLogImpl::FormatCacheKey(int component_id) {
// static
void AudioLogImpl::SendWebContentsTitleHelper(
const std::string& cache_key,
- scoped_ptr<base::DictionaryValue> dict,
+ std::unique_ptr<base::DictionaryValue> dict,
int render_process_id,
int render_frame_id) {
// Page title information can only be retrieved from the UI thread.
@@ -281,20 +282,15 @@ class MediaInternals::MediaInternalsUMAHandler {
private:
struct PipelineInfo {
- media::PipelineStatus last_pipeline_status;
- bool has_audio;
- bool has_video;
- bool video_dds;
- bool video_decoder_changed;
+ bool has_pipeline = false;
+ media::PipelineStatus last_pipeline_status = media::PIPELINE_OK;
+ bool has_audio = false;
+ bool has_video = false;
+ bool video_dds = false;
+ bool video_decoder_changed = false;
std::string audio_codec_name;
std::string video_codec_name;
std::string video_decoder;
- PipelineInfo()
- : last_pipeline_status(media::PIPELINE_OK),
- has_audio(false),
- has_video(false),
- video_dds(false),
- video_decoder_changed(false) {}
};
// Helper function to report PipelineStatus associated with a player to UMA.
@@ -324,6 +320,10 @@ void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PlayerInfoMap& player_info = renderer_info_[render_process_id];
switch (event.type) {
+ case media::MediaLogEvent::PIPELINE_STATE_CHANGED: {
+ player_info[event.id].has_pipeline = true;
+ break;
+ }
case media::MediaLogEvent::PIPELINE_ERROR: {
int status;
event.params.GetInteger("pipeline_error", &status);
@@ -404,6 +404,12 @@ std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream(
void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
const PipelineInfo& player_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Don't log pipeline status for players which don't actually have a pipeline;
+ // e.g., the Android MediaSourcePlayer implementation.
+ if (!player_info.has_pipeline)
+ return;
+
if (player_info.has_video && player_info.has_audio) {
base::LinearHistogram::FactoryGet(
GetUMANameForAVStream(player_info), 1, media::PIPELINE_STATUS_MAX,
@@ -419,6 +425,9 @@ void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
player_info.last_pipeline_status,
media::PIPELINE_STATUS_MAX + 1);
} else {
+ // Note: This metric can be recorded as a result of normal operation with
+ // Media Source Extensions. If a site creates a MediaSource object but never
+ // creates a source buffer or appends data, PIPELINE_OK will be recorded.
UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Unsupported",
player_info.last_pipeline_status,
media::PIPELINE_STATUS_MAX + 1);
@@ -612,11 +621,11 @@ void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
SendVideoCaptureDeviceCapabilities();
}
-scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
+std::unique_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
AudioComponent component) {
base::AutoLock auto_lock(lock_);
- return scoped_ptr<media::AudioLog>(new AudioLogImpl(
- owner_ids_[component]++, component, this));
+ return std::unique_ptr<media::AudioLog>(
+ new AudioLogImpl(owner_ids_[component]++, component, this));
}
void MediaInternals::SetWebContentsTitleForAudioLogEntry(
@@ -675,7 +684,7 @@ void MediaInternals::UpdateAudioLog(AudioLogUpdateType type,
DCHECK_EQ(type, CREATE);
audio_streams_cached_data_.Set(cache_key, value->DeepCopy());
} else if (type == UPDATE_AND_DELETE) {
- scoped_ptr<base::Value> out_value;
+ std::unique_ptr<base::Value> out_value;
CHECK(audio_streams_cached_data_.Remove(cache_key, &out_value));
} else {
base::DictionaryValue* existing_dict = NULL;
diff --git a/chromium/content/browser/media/media_internals.h b/chromium/content/browser/media/media_internals.h
index e4869281ed5..7203b2fc9ac 100644
--- a/chromium/content/browser/media/media_internals.h
+++ b/chromium/content/browser/media/media_internals.h
@@ -76,7 +76,8 @@ class CONTENT_EXPORT MediaInternals
const media::VideoCaptureDeviceInfos& video_capture_device_infos);
// AudioLogFactory implementation. Safe to call from any thread.
- scoped_ptr<media::AudioLog> CreateAudioLog(AudioComponent component) override;
+ std::unique_ptr<media::AudioLog> CreateAudioLog(
+ AudioComponent component) override;
// If possible, i.e. a WebContents exists for the given RenderFrameHostID,
// tells an existing AudioLogEntry the WebContents title for easier
@@ -137,7 +138,7 @@ class CONTENT_EXPORT MediaInternals
bool can_update_;
base::DictionaryValue audio_streams_cached_data_;
int owner_ids_[AUDIO_COMPONENT_MAX];
- scoped_ptr<MediaInternalsUMAHandler> uma_handler_;
+ std::unique_ptr<MediaInternalsUMAHandler> uma_handler_;
DISALLOW_COPY_AND_ASSIGN(MediaInternals);
};
diff --git a/chromium/content/browser/media/media_internals_proxy.cc b/chromium/content/browser/media/media_internals_proxy.cc
index 0ff34cf51af..a8ef88271bf 100644
--- a/chromium/content/browser/media/media_internals_proxy.cc
+++ b/chromium/content/browser/media/media_internals_proxy.cc
@@ -178,7 +178,7 @@ void MediaInternalsProxy::SendNetEventsOnUIThread() {
void MediaInternalsProxy::CallJavaScriptFunctionOnUIThread(
const std::string& function, base::Value* args) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- scoped_ptr<base::Value> args_value(args);
+ std::unique_ptr<base::Value> args_value(args);
std::vector<const base::Value*> args_vector;
args_vector.push_back(args_value.get());
base::string16 update = WebUI::GetJavascriptCall(function, args_vector);
diff --git a/chromium/content/browser/media/media_internals_proxy.h b/chromium/content/browser/media/media_internals_proxy.h
index 5eb9294f14f..84b4a1b1aad 100644
--- a/chromium/content/browser/media/media_internals_proxy.h
+++ b/chromium/content/browser/media/media_internals_proxy.h
@@ -78,7 +78,7 @@ class MediaInternalsProxy
base::Value* args);
MediaInternalsMessageHandler* handler_;
- scoped_ptr<base::ListValue> pending_net_updates_;
+ std::unique_ptr<base::ListValue> pending_net_updates_;
NotificationRegistrar registrar_;
MediaInternals::UpdateCallback update_callback_;
diff --git a/chromium/content/browser/media/media_internals_unittest.cc b/chromium/content/browser/media/media_internals_unittest.cc
index 2ab0539fdb2..808ae856537 100644
--- a/chromium/content/browser/media/media_internals_unittest.cc
+++ b/chromium/content/browser/media/media_internals_unittest.cc
@@ -44,7 +44,7 @@ class MediaInternalsTestBase {
std::string utf8_update = base::UTF16ToUTF8(update);
const std::string::size_type first_brace = utf8_update.find('{');
const std::string::size_type last_brace = utf8_update.rfind('}');
- scoped_ptr<base::Value> output_value = base::JSONReader::Read(
+ std::unique_ptr<base::Value> output_value = base::JSONReader::Read(
utf8_update.substr(first_brace, last_brace - first_brace + 1));
CHECK(output_value);
@@ -122,13 +122,11 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
CaptureApiTypeStringMap m;
#if defined(OS_LINUX)
m[VideoCaptureDeviceName::V4L2_SINGLE_PLANE] = "V4L2 SPLANE";
- m[VideoCaptureDeviceName::V4L2_MULTI_PLANE] = "V4L2 MPLANE";
#elif defined(OS_WIN)
m[VideoCaptureDeviceName::MEDIA_FOUNDATION] = "Media Foundation";
m[VideoCaptureDeviceName::DIRECT_SHOW] = "Direct Show";
#elif defined(OS_MACOSX)
m[VideoCaptureDeviceName::AVFOUNDATION] = "AV Foundation";
- m[VideoCaptureDeviceName::QTKIT] = "QTKit";
m[VideoCaptureDeviceName::DECKLINK] = "DeckLink";
#elif defined(OS_ANDROID)
m[VideoCaptureDeviceName::API1] = "Camera API1";
@@ -181,8 +179,8 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
formats.push_back(format_hd);
const media::VideoCaptureDeviceInfo device_info(
#if defined(OS_MACOSX)
- media::VideoCaptureDevice::Name("dummy", "dummy",
- media::VideoCaptureDevice::Name::QTKIT),
+ media::VideoCaptureDevice::Name(
+ "dummy", "dummy", media::VideoCaptureDevice::Name::AVFOUNDATION),
#elif defined(OS_WIN)
media::VideoCaptureDevice::Name("dummy", "dummy",
media::VideoCaptureDevice::Name::DIRECT_SHOW),
@@ -220,7 +218,7 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
#elif defined(OS_WIN)
ExpectString("captureApi", "Direct Show");
#elif defined(OS_MACOSX)
- ExpectString("captureApi", "QTKit");
+ ExpectString("captureApi", "AV Foundation");
#elif defined(OS_ANDROID)
ExpectString("captureApi", "Camera API2 Legacy");
#endif
@@ -247,7 +245,7 @@ class MediaInternalsAudioLogTest
MediaInternals::UpdateCallback update_cb_;
const media::AudioParameters test_params_;
const media::AudioLogFactory::AudioComponent test_component_;
- scoped_ptr<media::AudioLog> audio_log_;
+ std::unique_ptr<media::AudioLog> audio_log_;
private:
static media::AudioParameters MakeAudioParams() {
diff --git a/chromium/content/browser/media/media_web_contents_observer.cc b/chromium/content/browser/media/media_web_contents_observer.cc
index 67ef0368680..c301e2e345a 100644
--- a/chromium/content/browser/media/media_web_contents_observer.cc
+++ b/chromium/content/browser/media/media_web_contents_observer.cc
@@ -4,14 +4,15 @@
#include "content/browser/media/media_web_contents_observer.h"
+#include <memory>
+
#include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "content/browser/media/audible_metrics.h"
#include "content/browser/media/audio_stream_monitor.h"
#include "content/browser/power_save_blocker_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/frame_messages.h"
+#include "content/common/media/media_player_delegate_messages.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h"
@@ -26,7 +27,8 @@ static base::LazyInstance<AudibleMetrics>::Leaky g_audible_metrics =
} // anonymous namespace
MediaWebContentsObserver::MediaWebContentsObserver(WebContents* web_contents)
- : WebContentsObserver(web_contents) {}
+ : WebContentsObserver(web_contents),
+ session_controllers_manager_(this) {}
MediaWebContentsObserver::~MediaWebContentsObserver() {}
@@ -37,6 +39,7 @@ void MediaWebContentsObserver::WebContentsDestroyed() {
void MediaWebContentsObserver::RenderFrameDeleted(
RenderFrameHost* render_frame_host) {
ClearPowerSaveBlockers(render_frame_host);
+ session_controllers_manager_.RenderFrameDeleted(render_frame_host);
}
void MediaWebContentsObserver::MaybeUpdateAudibleState() {
@@ -64,28 +67,71 @@ bool MediaWebContentsObserver::OnMessageReceived(
// TODO(dalecurtis): These should no longer be FrameHostMsg.
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserver, msg,
render_frame_host)
- IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
- OnMediaPlayingNotification)
- IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
- OnMediaPausedNotification)
+ IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaDestroyed,
+ OnMediaDestroyed)
+ IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaPaused, OnMediaPaused)
+ IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaPlaying,
+ OnMediaPlaying)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void MediaWebContentsObserver::OnMediaPlayingNotification(
+void MediaWebContentsObserver::WasShown() {
+ // Restore power save blocker if there are active video players running.
+ if (!active_video_players_.empty() && !video_power_save_blocker_)
+ CreateVideoPowerSaveBlocker();
+}
+
+void MediaWebContentsObserver::WasHidden() {
+ // If there are entities capturing screenshots or video (e.g., mirroring),
+ // don't release the power save blocker.
+ if (!web_contents()->GetCapturerCount())
+ video_power_save_blocker_.reset();
+}
+
+void MediaWebContentsObserver::OnMediaDestroyed(
+ RenderFrameHost* render_frame_host,
+ int delegate_id) {
+ OnMediaPaused(render_frame_host, delegate_id, true);
+}
+
+void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host,
+ int delegate_id,
+ bool reached_end_of_stream) {
+ const MediaPlayerId player_id(render_frame_host, delegate_id);
+ const bool removed_audio =
+ RemoveMediaPlayerEntry(player_id, &active_audio_players_);
+ const bool removed_video =
+ RemoveMediaPlayerEntry(player_id, &active_video_players_);
+ MaybeReleasePowerSaveBlockers();
+
+ if (removed_audio || removed_video) {
+ // Notify observers the player has been "paused".
+ static_cast<WebContentsImpl*>(web_contents())
+ ->MediaStoppedPlaying(player_id);
+ }
+
+ if (reached_end_of_stream)
+ session_controllers_manager_.OnEnd(player_id);
+ else
+ session_controllers_manager_.OnPause(player_id);
+}
+
+void MediaWebContentsObserver::OnMediaPlaying(
RenderFrameHost* render_frame_host,
- int64_t player_cookie,
+ int delegate_id,
bool has_video,
bool has_audio,
- bool is_remote) {
+ bool is_remote,
+ base::TimeDelta duration) {
// Ignore the videos playing remotely and don't hold the wake lock for the
// screen. TODO(dalecurtis): Is this correct? It means observers will not
// receive play and pause messages.
if (is_remote)
return;
- const MediaPlayerId id(render_frame_host, player_cookie);
+ const MediaPlayerId id(render_frame_host, delegate_id);
if (has_audio) {
AddMediaPlayerEntry(id, &active_audio_players_);
@@ -107,25 +153,16 @@ void MediaWebContentsObserver::OnMediaPlayingNotification(
}
}
+ if (!session_controllers_manager_.RequestPlay(
+ id, has_audio, is_remote, duration)) {
+ return;
+ }
+
// Notify observers of the new player.
DCHECK(has_audio || has_video);
static_cast<WebContentsImpl*>(web_contents())->MediaStartedPlaying(id);
}
-void MediaWebContentsObserver::OnMediaPausedNotification(
- RenderFrameHost* render_frame_host,
- int64_t player_cookie) {
- const MediaPlayerId id(render_frame_host, player_cookie);
- const bool removed_audio = RemoveMediaPlayerEntry(id, &active_audio_players_);
- const bool removed_video = RemoveMediaPlayerEntry(id, &active_video_players_);
- MaybeReleasePowerSaveBlockers();
-
- if (removed_audio || removed_video) {
- // Notify observers the player has been "paused".
- static_cast<WebContentsImpl*>(web_contents())->MediaStoppedPlaying(id);
- }
-}
-
void MediaWebContentsObserver::ClearPowerSaveBlockers(
RenderFrameHost* render_frame_host) {
std::set<MediaPlayerId> removed_players;
@@ -154,26 +191,12 @@ void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() {
video_power_save_blocker_ = PowerSaveBlocker::Create(
PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
-// TODO(mfomitchev): Support PowerSaveBlocker on Aura - crbug.com/546718.
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
->InitDisplaySleepBlocker(web_contents());
#endif
}
-void MediaWebContentsObserver::WasShown() {
- // Restore power save blocker if there are active video players running.
- if (!active_video_players_.empty() && !video_power_save_blocker_)
- CreateVideoPowerSaveBlocker();
-}
-
-void MediaWebContentsObserver::WasHidden() {
- // If there are entities capturing screenshots or video (e.g., mirroring),
- // don't release the power save blocker.
- if (!web_contents()->GetCapturerCount())
- video_power_save_blocker_.reset();
-}
-
void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() {
// If there are no more audio players and we don't have audio stream
// monitoring, release the audio power save blocker here instead of during
@@ -191,10 +214,7 @@ void MediaWebContentsObserver::MaybeReleasePowerSaveBlockers() {
void MediaWebContentsObserver::AddMediaPlayerEntry(
const MediaPlayerId& id,
ActiveMediaPlayerMap* player_map) {
- DCHECK(std::find((*player_map)[id.first].begin(),
- (*player_map)[id.first].end(),
- id.second) == (*player_map)[id.first].end());
- (*player_map)[id.first].push_back(id.second);
+ (*player_map)[id.first].insert(id.second);
}
bool MediaWebContentsObserver::RemoveMediaPlayerEntry(
@@ -205,11 +225,9 @@ bool MediaWebContentsObserver::RemoveMediaPlayerEntry(
return false;
// Remove the player.
- auto player_for_removal =
- std::remove(it->second.begin(), it->second.end(), id.second);
- if (player_for_removal == it->second.end())
+ bool did_remove = it->second.erase(id.second) == 1;
+ if (!did_remove)
return false;
- it->second.erase(player_for_removal);
// If there are no players left, remove the map entry.
if (it->second.empty())
@@ -226,8 +244,8 @@ void MediaWebContentsObserver::RemoveAllMediaPlayerEntries(
if (it == player_map->end())
return;
- for (int64_t player_cookie : it->second)
- removed_players->insert(MediaPlayerId(render_frame_host, player_cookie));
+ for (int delegate_id : it->second)
+ removed_players->insert(MediaPlayerId(render_frame_host, delegate_id));
player_map->erase(it);
}
diff --git a/chromium/content/browser/media/media_web_contents_observer.h b/chromium/content/browser/media/media_web_contents_observer.h
index 1f76029cf4e..072ef4239fe 100644
--- a/chromium/content/browser/media/media_web_contents_observer.h
+++ b/chromium/content/browser/media/media_web_contents_observer.h
@@ -8,15 +8,16 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <set>
-#include <vector>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
+#include "content/browser/media/session/media_session_controllers_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
+
class PowerSaveBlocker;
// This class manages all RenderFrame based media related managers at the
@@ -40,21 +41,29 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void WasHidden() override;
bool has_audio_power_save_blocker_for_testing() const {
- return audio_power_save_blocker_;
+ return !!audio_power_save_blocker_;
}
bool has_video_power_save_blocker_for_testing() const {
- return video_power_save_blocker_;
+ return !!video_power_save_blocker_;
+ }
+
+ protected:
+ MediaSessionControllersManager* session_controllers_manager() {
+ return &session_controllers_manager_;
}
private:
- void OnMediaPlayingNotification(RenderFrameHost* render_frame_host,
- int64_t player_cookie,
- bool has_video,
- bool has_audio,
- bool is_remote);
- void OnMediaPausedNotification(RenderFrameHost* render_frame_host,
- int64_t player_cookie);
+ void OnMediaDestroyed(RenderFrameHost* render_frame_host, int delegate_id);
+ void OnMediaPaused(RenderFrameHost* render_frame_host,
+ int delegate_id,
+ bool reached_end_of_stream);
+ void OnMediaPlaying(RenderFrameHost* render_frame_host,
+ int delegate_id,
+ bool has_video,
+ bool has_audio,
+ bool is_remote,
+ base::TimeDelta duration);
// Clear |render_frame_host|'s tracking entry for its power save blockers.
void ClearPowerSaveBlockers(RenderFrameHost* render_frame_host);
@@ -69,8 +78,8 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void MaybeReleasePowerSaveBlockers();
// Helper methods for adding or removing player entries in |player_map|.
- using PlayerList = std::vector<int64_t>;
- using ActiveMediaPlayerMap = std::map<RenderFrameHost*, PlayerList>;
+ using PlayerSet = std::set<int>;
+ using ActiveMediaPlayerMap = std::map<RenderFrameHost*, PlayerSet>;
void AddMediaPlayerEntry(const MediaPlayerId& id,
ActiveMediaPlayerMap* player_map);
// Returns true if an entry is actually removed.
@@ -85,8 +94,10 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
// Tracking variables and associated power save blockers for media playback.
ActiveMediaPlayerMap active_audio_players_;
ActiveMediaPlayerMap active_video_players_;
- scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
- scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> audio_power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> video_power_save_blocker_;
+
+ MediaSessionControllersManager session_controllers_manager_;
DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserver);
};
diff --git a/chromium/content/browser/media/midi_host.cc b/chromium/content/browser/media/midi_host.cc
index 30261ef7f35..17dccccfea5 100644
--- a/chromium/content/browser/media/midi_host.cc
+++ b/chromium/content/browser/media/midi_host.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/metrics/histogram_macros.h"
#include "base/process/process.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/bad_message.h"
@@ -234,6 +235,7 @@ void MidiHost::Detach() {
// static
bool MidiHost::IsValidWebMIDIData(const std::vector<uint8_t>& data) {
bool in_sysex = false;
+ size_t sysex_start_offset = 0;
size_t waiting_data_length = 0;
for (size_t i = 0; i < data.size(); ++i) {
const uint8_t current = data[i];
@@ -246,14 +248,18 @@ bool MidiHost::IsValidWebMIDIData(const std::vector<uint8_t>& data) {
continue; // Found data byte as expected.
}
if (in_sysex) {
- if (data[i] == kEndOfSysExByte)
+ if (data[i] == kEndOfSysExByte) {
in_sysex = false;
- else if (!IsDataByte(current))
+ UMA_HISTOGRAM_COUNTS("Media.Midi.SysExMessageSizeUpTo1MB",
+ i - sysex_start_offset + 1);
+ } else if (!IsDataByte(current)) {
return false; // Error: |current| should have been data byte.
+ }
continue; // Found data byte as expected.
}
if (current == kSysExByte) {
in_sysex = true;
+ sysex_start_offset = i;
continue; // Found SysEX
}
waiting_data_length = media::midi::GetMidiMessageLength(current);
diff --git a/chromium/content/browser/media/midi_host.h b/chromium/content/browser/media/midi_host.h
index ca3706cbcda..fc126acd357 100644
--- a/chromium/content/browser/media/midi_host.h
+++ b/chromium/content/browser/media/midi_host.h
@@ -8,12 +8,12 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/media/midi_host_unittest.cc b/chromium/content/browser/media/midi_host_unittest.cc
index 655414e858e..21306af09a1 100644
--- a/chromium/content/browser/media/midi_host_unittest.cc
+++ b/chromium/content/browser/media/midi_host_unittest.cc
@@ -126,7 +126,7 @@ class MidiHostTest : public testing::Test {
}
void OnSendData(uint32_t port) {
- scoped_ptr<IPC::Message> message(
+ std::unique_ptr<IPC::Message> message(
new MidiHostMsg_SendData(port, data_, 0.0));
host_->OnMessageReceived(*message.get());
}
diff --git a/chromium/content/browser/media/session/OWNERS b/chromium/content/browser/media/session/OWNERS
new file mode 100644
index 00000000000..dc2593f577e
--- /dev/null
+++ b/chromium/content/browser/media/session/OWNERS
@@ -0,0 +1,2 @@
+avayvod@chromium.org
+mlamouri@chromium.org
diff --git a/chromium/content/browser/media/android/media_session.cc b/chromium/content/browser/media/session/media_session.cc
index d6061541e88..5c63545c3c4 100644
--- a/chromium/content/browser/media/android/media_session.cc
+++ b/chromium/content/browser/media/session/media_session.cc
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/android/media_session.h"
+#include "content/browser/media/session/media_session.h"
-#include "base/android/context_utils.h"
-#include "base/android/jni_android.h"
-#include "content/browser/media/android/media_session_observer.h"
+#include "content/browser/media/session/media_session_delegate.h"
+#include "content/browser/media/session/media_session_observer.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
-#include "jni/MediaSession_jni.h"
namespace content {
+namespace {
+
+const double kDefaultVolumeMultiplier = 1.0;
+
+} // anonymous namespace
+
using MediaSessionSuspendedSource =
MediaSessionUmaHelper::MediaSessionSuspendedSource;
@@ -39,11 +43,6 @@ size_t MediaSession::PlayerIdentifier::Hash::operator()(
}
// static
-bool content::MediaSession::RegisterMediaSession(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-// static
MediaSession* MediaSession::Get(WebContents* web_contents) {
MediaSession* session = FromWebContents(web_contents);
if (!session) {
@@ -62,6 +61,8 @@ MediaSession::~MediaSession() {
bool MediaSession::AddPlayer(MediaSessionObserver* observer,
int player_id,
Type type) {
+ observer->OnSetVolumeMultiplier(player_id, volume_multiplier_);
+
// If the audio focus is already granted and is of type Content, there is
// nothing to do. If it is granted of type Transient the requested type is
// also transient, there is also nothing to do. Otherwise, the session needs
@@ -112,25 +113,9 @@ void MediaSession::RemovePlayers(MediaSessionObserver* observer) {
AbandonSystemAudioFocusIfNeeded();
}
-void MediaSession::OnSuspend(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jboolean temporary) {
- // TODO(mlamouri): this check makes it so that if a MediaSession is paused and
- // then loses audio focus, it will still stay in the Suspended state.
- // See https://crbug.com/539998
- if (audio_focus_state_ != State::ACTIVE)
- return;
-
- OnSuspendInternal(SuspendType::SYSTEM,
- temporary ? State::SUSPENDED : State::INACTIVE);
-
-}
-
-void MediaSession::OnResume(JNIEnv* env, const JavaParamRef<jobject>& obj) {
- if (audio_focus_state_ != State::SUSPENDED)
- return;
-
- OnResumeInternal(SuspendType::SYSTEM);
+void MediaSession::RecordSessionDuck() {
+ uma_helper_.RecordSessionSuspended(
+ MediaSessionSuspendedSource::SystemTransientDuck);
}
void MediaSession::OnPlayerPaused(MediaSessionObserver* observer,
@@ -154,39 +139,65 @@ void MediaSession::OnPlayerPaused(MediaSessionObserver* observer,
OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED);
}
-void MediaSession::Resume() {
- DCHECK(IsSuspended());
-
- // Request audio focus again in case we lost it because another app started
- // playing while the playback was paused.
- State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_)
- ? State::ACTIVE
- : State::INACTIVE;
- SetAudioFocusState(audio_focus_state);
-
- if (audio_focus_state_ != State::ACTIVE)
- return;
+void MediaSession::Resume(SuspendType type) {
+ DCHECK(IsReallySuspended());
+
+ // When the resume requests comes from another source than system, audio focus
+ // must be requested.
+ if (type != SuspendType::SYSTEM) {
+ // Request audio focus again in case we lost it because another app started
+ // playing while the playback was paused.
+ State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_)
+ ? State::ACTIVE
+ : State::INACTIVE;
+ SetAudioFocusState(audio_focus_state);
+
+ if (audio_focus_state_ != State::ACTIVE)
+ return;
+ }
- OnResumeInternal(SuspendType::UI);
+ OnResumeInternal(type);
}
-void MediaSession::Suspend() {
+void MediaSession::Suspend(SuspendType type) {
DCHECK(!IsSuspended());
- OnSuspendInternal(SuspendType::UI, State::SUSPENDED);
+ OnSuspendInternal(type, State::SUSPENDED);
}
-void MediaSession::Stop() {
+void MediaSession::Stop(SuspendType type) {
DCHECK(audio_focus_state_ != State::INACTIVE);
+ DCHECK(type != SuspendType::CONTENT);
+
+ // TODO(mlamouri): merge the logic between UI and SYSTEM.
+ if (type == SuspendType::SYSTEM) {
+ OnSuspendInternal(type, State::INACTIVE);
+ return;
+ }
+
if (audio_focus_state_ != State::SUSPENDED)
- OnSuspendInternal(SuspendType::UI, State::SUSPENDED);
+ OnSuspendInternal(type, State::SUSPENDED);
DCHECK(audio_focus_state_ == State::SUSPENDED);
players_.clear();
AbandonSystemAudioFocusIfNeeded();
}
+void MediaSession::SetVolumeMultiplier(double volume_multiplier) {
+ volume_multiplier_ = volume_multiplier;
+ for (const auto& it : players_)
+ it.observer->OnSetVolumeMultiplier(it.player_id, volume_multiplier_);
+}
+
+bool MediaSession::IsActive() const {
+ return audio_focus_state_ == State::ACTIVE;
+}
+
+bool MediaSession::IsReallySuspended() const {
+ return audio_focus_state_ == State::SUSPENDED;
+}
+
bool MediaSession::IsSuspended() const {
// TODO(mlamouri): should be == State::SUSPENDED.
return audio_focus_state_ != State::ACTIVE;
@@ -198,8 +209,15 @@ bool MediaSession::IsControllable() const {
audio_focus_type_ == Type::Content;
}
-void MediaSession::ResetJavaRefForTest() {
- j_media_session_.Reset();
+std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription>
+MediaSession::RegisterMediaSessionStateChangedCallbackForTest(
+ const StateChangedCallback& cb) {
+ return media_session_state_listeners_.Add(cb);
+}
+
+void MediaSession::SetDelegateForTests(
+ std::unique_ptr<MediaSessionDelegate> delegate) {
+ delegate_ = std::move(delegate);
}
bool MediaSession::IsActiveForTest() const {
@@ -224,6 +242,9 @@ void MediaSession::OnSuspendInternal(SuspendType type, State new_state) {
// UI suspend cannot use State::INACTIVE.
DCHECK(type == SuspendType::SYSTEM || new_state == State::SUSPENDED);
+ if (audio_focus_state_ != State::ACTIVE)
+ return;
+
switch (type) {
case SuspendType::UI:
uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI);
@@ -277,26 +298,16 @@ void MediaSession::OnResumeInternal(SuspendType type) {
MediaSession::MediaSession(WebContents* web_contents)
: WebContentsObserver(web_contents),
audio_focus_state_(State::INACTIVE),
- audio_focus_type_(Type::Transient) {}
+ audio_focus_type_(Type::Transient),
+ volume_multiplier_(kDefaultVolumeMultiplier) {
+}
void MediaSession::Initialize() {
- JNIEnv* env = base::android::AttachCurrentThread();
- DCHECK(env);
- j_media_session_.Reset(Java_MediaSession_createMediaSession(
- env,
- base::android::GetApplicationContext(),
- reinterpret_cast<intptr_t>(this)));
+ delegate_ = MediaSessionDelegate::Create(this);
}
bool MediaSession::RequestSystemAudioFocus(Type type) {
- // During tests, j_media_session_ might be null.
- if (j_media_session_.is_null())
- return true;
-
- JNIEnv* env = base::android::AttachCurrentThread();
- DCHECK(env);
- bool result = Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(),
- type == Type::Transient);
+ bool result = delegate_->RequestAudioFocus(type);
uma_helper_.RecordRequestAudioFocusResult(result);
return result;
}
@@ -305,18 +316,14 @@ void MediaSession::AbandonSystemAudioFocusIfNeeded() {
if (audio_focus_state_ == State::INACTIVE || !players_.empty())
return;
- // During tests, j_media_session_ might be null.
- if (!j_media_session_.is_null()) {
- JNIEnv* env = base::android::AttachCurrentThread();
- DCHECK(env);
- Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj());
- }
+ delegate_->AbandonAudioFocus();
SetAudioFocusState(State::INACTIVE);
UpdateWebContents();
}
void MediaSession::UpdateWebContents() {
+ media_session_state_listeners_.Notify(audio_focus_state_);
static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
}
diff --git a/chromium/content/browser/media/session/media_session.h b/chromium/content/browser/media/session/media_session.h
new file mode 100644
index 00000000000..3c0cf1594c3
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session.h
@@ -0,0 +1,212 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_H_
+
+#include <stddef.h>
+
+#include "base/callback_list.h"
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "content/browser/media/session/media_session_uma_helper.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "content/public/common/media_metadata.h"
+
+class MediaSessionBrowserTest;
+
+namespace content {
+
+class MediaSessionDelegate;
+class MediaSessionObserver;
+class MediaSessionStateObserver;
+class MediaSessionVisibilityBrowserTest;
+
+// MediaSession manages the media session and audio focus for a given
+// WebContents. It is requesting the audio focus, pausing when requested by the
+// system and dropping it on demand.
+// The audio focus can be of two types: Transient or Content. A Transient audio
+// focus will allow other players to duck instead of pausing and will be
+// declared as temporary to the system. A Content audio focus will not be
+// declared as temporary and will not allow other players to duck. If a given
+// WebContents can only have one audio focus at a time, it will be Content in
+// case of Transient and Content audio focus are both requested.
+// TODO(thakis,mlamouri): MediaSession isn't CONTENT_EXPORT'd because it creates
+// complicated build issues with WebContentsUserData being a non-exported
+// template, see htttps://crbug.com/589840. As a result, the class uses
+// CONTENT_EXPORT for methods that are being used from tests. CONTENT_EXPORT
+// should be moved back to the class when the Windows build will work with it.
+class MediaSession : public WebContentsObserver,
+ protected WebContentsUserData<MediaSession> {
+ public:
+ enum class Type {
+ Content,
+ Transient
+ };
+
+ enum class SuspendType {
+ // Suspended by the system because a transient sound needs to be played.
+ SYSTEM,
+ // Suspended by the UI.
+ UI,
+ // Suspended by the page via script or user interaction.
+ CONTENT,
+ };
+
+ // Returns the MediaSession associated to this WebContents. Creates one if
+ // none is currently available.
+ CONTENT_EXPORT static MediaSession* Get(WebContents* web_contents);
+
+ ~MediaSession() override;
+
+ void setMetadata(const MediaMetadata& metadata) {
+ metadata_ = metadata;
+ }
+ const MediaMetadata& metadata() const { return metadata_; }
+
+ // Adds the given player to the current media session. Returns whether the
+ // player was successfully added. If it returns false, AddPlayer() should be
+ // called again later.
+ CONTENT_EXPORT bool AddPlayer(MediaSessionObserver* observer,
+ int player_id, Type type);
+
+ // Removes the given player from the current media session. Abandons audio
+ // focus if that was the last player in the session.
+ CONTENT_EXPORT void RemovePlayer(MediaSessionObserver* observer,
+ int player_id);
+
+ // Removes all the players associated with |observer|. Abandons audio focus if
+ // these were the last players in the session.
+ CONTENT_EXPORT void RemovePlayers(MediaSessionObserver* observer);
+
+ // Record that the session was ducked.
+ void RecordSessionDuck();
+
+ // Called when a player is paused in the content.
+ // If the paused player is the last player, we suspend the MediaSession.
+ // Otherwise, the paused player will be removed from the MediaSession.
+ CONTENT_EXPORT void OnPlayerPaused(MediaSessionObserver* observer,
+ int player_id);
+
+ // Resume the media session.
+ // |type| represents the origin of the request.
+ CONTENT_EXPORT void Resume(SuspendType type);
+
+ // Suspend the media session.
+ // |type| represents the origin of the request.
+ CONTENT_EXPORT void Suspend(SuspendType type);
+
+ // Stop the media session.
+ // |type| represents the origin of the request.
+ CONTENT_EXPORT void Stop(SuspendType type);
+
+ // Change the volume multiplier of the session to |volume_multiplier|.
+ CONTENT_EXPORT void SetVolumeMultiplier(double volume_multiplier);
+
+ // Returns if the session can be controlled by Resume() and Suspend calls
+ // above.
+ CONTENT_EXPORT bool IsControllable() const;
+
+ // Returns if the session is currently active.
+ CONTENT_EXPORT bool IsActive() const;
+
+ // Returns if the session is currently suspended.
+ // TODO(mlamouri): IsSuspended() below checks if the state is not ACTIVE
+ // instead of checking if the state is SUSPENDED. In order to not have to
+ // change all the callers and make the current refactoring ridiculously huge,
+ // this method is introduced temporarily and will be removed later.
+ bool IsReallySuspended() const;
+
+ // Returns if the session is currently suspended or inactive.
+ CONTENT_EXPORT bool IsSuspended() const;
+
+ private:
+ friend class content::WebContentsUserData<MediaSession>;
+ friend class ::MediaSessionBrowserTest;
+ friend class content::MediaSessionVisibilityBrowserTest;
+ friend class content::MediaSessionStateObserver;
+
+ CONTENT_EXPORT void SetDelegateForTests(
+ std::unique_ptr<MediaSessionDelegate> delegate);
+ CONTENT_EXPORT bool IsActiveForTest() const;
+ CONTENT_EXPORT Type audio_focus_type_for_test() const;
+ CONTENT_EXPORT void RemoveAllPlayersForTest();
+ CONTENT_EXPORT MediaSessionUmaHelper* uma_helper_for_test();
+
+ enum class State {
+ ACTIVE,
+ SUSPENDED,
+ INACTIVE
+ };
+
+ // Representation of a player for the MediaSession.
+ struct PlayerIdentifier {
+ PlayerIdentifier(MediaSessionObserver* observer, int player_id);
+ PlayerIdentifier(const PlayerIdentifier&) = default;
+
+ void operator=(const PlayerIdentifier&) = delete;
+ bool operator==(const PlayerIdentifier& player_identifier) const;
+
+ // Hash operator for base::hash_map<>.
+ struct Hash {
+ size_t operator()(const PlayerIdentifier& player_identifier) const;
+ };
+
+ MediaSessionObserver* observer;
+ int player_id;
+ };
+ using PlayersMap = base::hash_set<PlayerIdentifier, PlayerIdentifier::Hash>;
+ using StateChangedCallback = base::Callback<void(State)>;
+
+ CONTENT_EXPORT explicit MediaSession(WebContents* web_contents);
+
+ void Initialize();
+
+ CONTENT_EXPORT void OnSuspendInternal(SuspendType type, State new_state);
+ CONTENT_EXPORT void OnResumeInternal(SuspendType type);
+
+ // Requests audio focus to the MediaSessionDelegate.
+ // Returns whether the request was granted.
+ bool RequestSystemAudioFocus(Type type);
+
+ // To be called after a call to AbandonAudioFocus() in order request the
+ // delegate to abandon the audio focus.
+ void AbandonSystemAudioFocusIfNeeded();
+
+ // Notifies WebContents about the state change of the media session.
+ void UpdateWebContents();
+
+ // Internal method that should be used instead of setting audio_focus_state_.
+ // It sets audio_focus_state_ and notifies observers about the state change.
+ void SetAudioFocusState(State audio_focus_state);
+
+ // Registers a MediaSession state change callback.
+ CONTENT_EXPORT std::unique_ptr<base::CallbackList<void(State)>::Subscription>
+ RegisterMediaSessionStateChangedCallbackForTest(
+ const StateChangedCallback& cb);
+
+ std::unique_ptr<MediaSessionDelegate> delegate_;
+ PlayersMap players_;
+
+ State audio_focus_state_;
+ SuspendType suspend_type_;
+ Type audio_focus_type_;
+
+ MediaSessionUmaHelper uma_helper_;
+
+ // The volume multiplier of this session. All players in this session should
+ // multiply their volume with this multiplier to get the effective volume.
+ double volume_multiplier_;
+
+ MediaMetadata metadata_;
+ base::CallbackList<void(State)> media_session_state_listeners_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSession);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_H_
diff --git a/chromium/content/browser/media/android/media_session_browsertest.cc b/chromium/content/browser/media/session/media_session_browsertest.cc
index a0628ae7093..db7a67ee5b6 100644
--- a/chromium/content/browser/media/android/media_session_browsertest.cc
+++ b/chromium/content/browser/media/session/media_session_browsertest.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 "content/browser/media/android/media_session.h"
+#include "content/browser/media/session/media_session.h"
#include <stddef.h>
@@ -13,7 +13,8 @@
#include "base/metrics/histogram_samples.h"
#include "base/test/histogram_tester.h"
#include "base/test/simple_test_clock.h"
-#include "content/browser/media/android/media_session_observer.h"
+#include "content/browser/media/session/media_session_delegate.h"
+#include "content/browser/media/session/mock_media_session_observer.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/content_browser_test.h"
@@ -23,68 +24,23 @@
using content::WebContents;
using content::WebContentsObserver;
using content::MediaSession;
+using content::MediaSessionDelegate;
using content::MediaSessionObserver;
using content::MediaSessionUmaHelper;
+using content::MockMediaSessionObserver;
using ::testing::Expectation;
namespace {
-class MockMediaSessionObserver : public MediaSessionObserver {
+class MockMediaSessionDelegate : public MediaSessionDelegate {
public:
- MockMediaSessionObserver()
- : received_resume_calls_(0),
- received_suspend_calls_(0) {
+ bool RequestAudioFocus(MediaSession::Type) override {
+ return true;
}
- ~MockMediaSessionObserver() override = default;
-
- // Implements MediaSessionObserver.
- void OnSuspend(int player_id) override {
- DCHECK(player_id >= 0);
- DCHECK(players_.size() > static_cast<size_t>(player_id));
-
- ++received_suspend_calls_;
- players_[player_id] = false;
- }
- void OnResume(int player_id) override {
- DCHECK(player_id >= 0);
- DCHECK(players_.size() > static_cast<size_t>(player_id));
-
- ++received_resume_calls_;
- players_[player_id] = true;
- }
-
- int StartNewPlayer() {
- players_.push_back(true);
- return players_.size() - 1;
- }
-
- bool IsPlaying(size_t player_id) {
- DCHECK(players_.size() > player_id);
- return players_[player_id];
- }
-
- void SetPlaying(size_t player_id, bool playing) {
- DCHECK(players_.size() > player_id);
- players_[player_id] = playing;
+ void AbandonAudioFocus() override {
}
-
- int received_suspend_calls() const {
- return received_suspend_calls_;
- }
-
- int received_resume_calls() const {
- return received_resume_calls_;
- }
-
- private:
- // Basic representation of the players. The position in the vector is the
- // player_id. The value of the vector is the playing status.
- std::vector<bool> players_;
-
- int received_resume_calls_;
- int received_suspend_calls_;
};
class MockWebContentsObserver : public WebContentsObserver {
@@ -92,8 +48,9 @@ class MockWebContentsObserver : public WebContentsObserver {
MockWebContentsObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
- MOCK_METHOD2(MediaSessionStateChanged,
- void(bool is_controllable, bool is_suspended));
+ MOCK_METHOD3(MediaSessionStateChanged,
+ void(bool is_controllable, bool is_suspended,
+ const content::MediaMetadata& metadata));
};
} // namespace
@@ -108,7 +65,8 @@ class MediaSessionBrowserTest : public content::ContentBrowserTest {
mock_web_contents_observer_.reset(
new MockWebContentsObserver(shell()->web_contents()));
media_session_ = MediaSession::Get(shell()->web_contents());
- media_session_->ResetJavaRefForTest();
+ media_session_->SetDelegateForTests(
+ std::unique_ptr<MediaSessionDelegate>(new MockMediaSessionDelegate()));
ASSERT_TRUE(media_session_);
}
@@ -161,27 +119,34 @@ class MediaSessionBrowserTest : public content::ContentBrowserTest {
bool IsSuspended() { return media_session_->IsSuspended(); }
void UIResume() {
- media_session_->Resume();
+ media_session_->Resume(MediaSession::SuspendType::UI);
}
void SystemResume() {
- media_session_->OnResume(nullptr, nullptr);
+ media_session_->OnResumeInternal(MediaSession::SuspendType::SYSTEM);
}
void UISuspend() {
- media_session_->Suspend();
+ media_session_->Suspend(MediaSession::SuspendType::UI);
}
void SystemSuspend(bool temporary) {
- media_session_->OnSuspend(nullptr, nullptr, temporary);
+ media_session_->OnSuspendInternal(
+ MediaSession::SuspendType::SYSTEM,
+ temporary ? MediaSession::State::SUSPENDED
+ : MediaSession::State::INACTIVE);
+ }
+
+ void SystemSetVolumeMultiplier(double volume_multiplier) {
+ media_session_->SetVolumeMultiplier(volume_multiplier);
}
MockWebContentsObserver* mock_web_contents_observer() {
return mock_web_contents_observer_.get();
}
- scoped_ptr<MediaSession> CreateDummyMediaSession() {
- return scoped_ptr<MediaSession>(new MediaSession(nullptr));
+ std::unique_ptr<MediaSession> CreateDummyMediaSession() {
+ return std::unique_ptr<MediaSession>(new MediaSession(nullptr));
}
MediaSessionUmaHelper* GetMediaSessionUMAHelper() {
@@ -190,14 +155,14 @@ class MediaSessionBrowserTest : public content::ContentBrowserTest {
protected:
MediaSession* media_session_;
- scoped_ptr<MockWebContentsObserver> mock_web_contents_observer_;
+ std::unique_ptr<MockWebContentsObserver> mock_web_contents_observer_;
DISALLOW_COPY_AND_ASSIGN(MediaSessionBrowserTest);
};
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
PlayersFromSameObserverDoNotStopEachOtherInSameSession) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -211,15 +176,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
PlayersFromManyObserverDoNotStopEachOtherInSameSession) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer_1(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_1(
new MockMediaSessionObserver);
- scoped_ptr<MockMediaSessionObserver> media_session_observer_2(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_2(
new MockMediaSessionObserver);
- scoped_ptr<MockMediaSessionObserver> media_session_observer_3(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_3(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer_1.get(), MediaSession::Type::Content);
-
StartNewPlayer(media_session_observer_2.get(), MediaSession::Type::Content);
StartNewPlayer(media_session_observer_3.get(), MediaSession::Type::Content);
@@ -230,7 +194,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
SuspendedMediaSessionStopsPlayers) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -246,7 +210,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ResumedMediaSessionRestartsPlayers) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -263,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
StartedPlayerOnSuspendedSessionPlaysAlone) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -286,12 +250,31 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
EXPECT_TRUE(media_session_observer->IsPlaying(2));
}
+IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
+ MediaSessionSetVolumeMultiplier) {
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
+
+ StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
+ StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
+
+ double volume_multiplier = 0.2f;
+ SystemSetVolumeMultiplier(volume_multiplier);
+
+ EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(0));
+ EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(1));
+
+ StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
+
+ EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(2));
+}
+
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, AudioFocusInitialState) {
EXPECT_FALSE(HasAudioFocus());
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, StartPlayerGivesFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -300,7 +283,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, StartPlayerGivesFocus) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, SuspendGivesAwayAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -311,18 +294,18 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, SuspendGivesAwayAudioFocus) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, StopGivesAwayAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
EXPECT_FALSE(HasAudioFocus());
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeGivesBackAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -335,7 +318,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeGivesBackAudioFocus) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
RemovingLastPlayerDropsAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -352,11 +335,11 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
RemovingLastPlayerFromManyObserversDropsAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer_1(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_1(
new MockMediaSessionObserver);
- scoped_ptr<MockMediaSessionObserver> media_session_observer_2(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_2(
new MockMediaSessionObserver);
- scoped_ptr<MockMediaSessionObserver> media_session_observer_3(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_3(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer_1.get(), MediaSession::Type::Content);
@@ -373,9 +356,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
RemovingAllPlayersFromObserversDropsAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer_1(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_1(
new MockMediaSessionObserver);
- scoped_ptr<MockMediaSessionObserver> media_session_observer_2(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer_2(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer_1.get(), MediaSession::Type::Content);
@@ -390,7 +373,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumePlayGivesAudioFocus) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -405,7 +388,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumePlayGivesAudioFocus) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ResumeSuspendAreSentOnlyOncePerPlayers) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -424,7 +407,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ResumeSuspendAreSentOnlyOncePerPlayersAddedTwice) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -451,7 +434,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
RemovingTheSamePlayerTwiceIsANoop) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -461,7 +444,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, MediaSessionType) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
// Starting a player with a given type should set the session to that type.
@@ -506,9 +489,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, MediaSessionType) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShowForContent) {
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
// Starting a player with a content type should show the media controls.
@@ -520,9 +503,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShowForContent) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsNoShowForTransient) {
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, false));
+ MediaSessionStateChanged(false, false, testing::_));
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
// Starting a player with a transient type should not show the media controls.
@@ -534,12 +517,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsNoShowForTransient) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsHideWhenStopped) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, true))
+ MediaSessionStateChanged(false, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -552,9 +535,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsHideWhenStopped) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShownAcceptTransient) {
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -568,13 +551,13 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShownAcceptTransient) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsShownAfterContentAdded) {
- Expectation dontShowControls = EXPECT_CALL(
- *mock_web_contents_observer(), MediaSessionStateChanged(false, false));
+ Expectation dontShowControls = EXPECT_CALL(*mock_web_contents_observer(),
+ MediaSessionStateChanged(false, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false))
+ MediaSessionStateChanged(true, false, testing::_))
.After(dontShowControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Transient);
@@ -589,9 +572,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsStayIfOnlyOnePlayerHasBeenPaused) {
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -608,11 +591,11 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsHideWhenTheLastPlayerIsRemoved) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, true))
+ MediaSessionStateChanged(false, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -632,12 +615,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsHideWhenAllThePlayersAreRemoved) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, true))
+ MediaSessionStateChanged(false, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -652,12 +635,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsNotHideWhenTheLastPlayerIsPaused) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
+ MediaSessionStateChanged(true, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -677,12 +660,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
SuspendTemporaryUpdatesControls) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
+ MediaSessionStateChanged(true, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -695,15 +678,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsUpdatedWhenResumed) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false))
+ MediaSessionStateChanged(true, false, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -717,12 +699,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsUpdatedWhenResumed) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsHideWhenSessionSuspendedPermanently) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, true))
+ MediaSessionStateChanged(false, true, testing::_))
.After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -736,20 +718,19 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ConstrolsHideWhenSessionStops) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, true))
+ MediaSessionStateChanged(false, true, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
EXPECT_FALSE(IsControllable());
EXPECT_TRUE(IsSuspended());
@@ -758,15 +739,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsHideWhenSessionChangesFromContentToTransient) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(false, false))
+ MediaSessionStateChanged(false, false, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -783,15 +763,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsUpdatedWhenNewPlayerResetsSession) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false))
+ MediaSessionStateChanged(true, false, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -807,15 +786,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsResumedWhenPlayerIsResumed) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false))
+ MediaSessionStateChanged(true, false, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -831,11 +809,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsUpdatedDueToResumeSessionAction) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true)).After(showControls);
+ MediaSessionStateChanged(true, true, testing::_))
+ .After(showControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -848,15 +827,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
ControlsUpdatedDueToSuspendSessionAction) {
Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false));
+ MediaSessionStateChanged(true, false, testing::_));
Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, true))
- .After(showControls);
+ MediaSessionStateChanged(true, true, testing::_)).After(showControls);
EXPECT_CALL(*mock_web_contents_observer(),
- MediaSessionStateChanged(true, false))
+ MediaSessionStateChanged(true, false, testing::_))
.After(pauseControls);
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -869,7 +847,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
DontResumeBySystemUISuspendedSessions) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -884,7 +862,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
AllowUIResumeForSystemSuspend) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -898,7 +876,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeSuspendFromUI) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -912,7 +890,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeSuspendFromUI) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeSuspendFromSystem) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -926,14 +904,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ResumeSuspendFromSystem) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_SystemTransient) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
SystemSuspend(true);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(0)); // System Transient
@@ -944,14 +922,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_SystemTransient) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_Suspended_SystemPermantent) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
SystemSuspend(false);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(0, samples->GetCount(0)); // System Transient
@@ -960,14 +938,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_UI) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
UISuspend();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(0, samples->GetCount(0)); // System Transient
@@ -976,7 +954,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_UI) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Multiple) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
@@ -993,7 +971,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Multiple) {
SystemSuspend(false);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(4, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(0)); // System Transient
@@ -1002,7 +980,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Multiple) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Crossing) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
@@ -1018,7 +996,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Crossing) {
SystemSuspend(false);
SystemResume();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(0)); // System Transient
@@ -1027,14 +1005,14 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Crossing) {
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Stop) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
base::HistogramTester tester;
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.Suspended"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(0, samples->GetCount(0)); // System Transient
@@ -1045,33 +1023,33 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_Suspended_Stop) {
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, UMA_ActiveTime_NoActivation) {
base::HistogramTester tester;
- scoped_ptr<MediaSession> media_session = CreateDummyMediaSession();
+ std::unique_ptr<MediaSession> media_session = CreateDummyMediaSession();
media_session.reset();
// A MediaSession that wasn't active doesn't register an active time.
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_SimpleActivation) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(1000));
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -1079,15 +1057,15 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_ActivationWithUISuspension) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -1098,9 +1076,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UIResume();
clock->Advance(base::TimeDelta::FromMilliseconds(1000));
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(2000));
@@ -1108,15 +1086,15 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_ActivationWithSystemSuspension) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
@@ -1127,9 +1105,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
SystemResume();
clock->Advance(base::TimeDelta::FromMilliseconds(1000));
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(2000));
@@ -1137,22 +1115,22 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_ActivateSuspendedButNotStopped) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(500));
SystemSuspend(true);
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -1162,7 +1140,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UISuspend();
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -1170,27 +1148,27 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_ActivateSuspendStopTwice) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(500));
SystemSuspend(true);
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(5000));
SystemResume();
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(500));
@@ -1199,15 +1177,15 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
UMA_ActiveTime_MultipleActivations) {
- scoped_ptr<MockMediaSessionObserver> media_session_observer(
- new MockMediaSessionObserver);
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
base::HistogramTester tester;
MediaSessionUmaHelper* media_session_uma_helper = GetMediaSessionUMAHelper();
base::SimpleTestClock* clock = new base::SimpleTestClock();
clock->SetNow(base::Time::Now());
media_session_uma_helper->SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock));
+ std::unique_ptr<base::SimpleTestClock>(clock));
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(10000));
@@ -1215,9 +1193,9 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
StartNewPlayer(media_session_observer.get(), MediaSession::Type::Content);
clock->Advance(base::TimeDelta::FromMilliseconds(1000));
- media_session_->Stop();
+ media_session_->Stop(MediaSession::SuspendType::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
tester.GetHistogramSamplesSinceCreation("Media.Session.ActiveTime"));
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
diff --git a/chromium/content/browser/media/session/media_session_controller.cc b/chromium/content/browser/media/session/media_session_controller.cc
new file mode 100644
index 00000000000..00ba5a91f88
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_controller.cc
@@ -0,0 +1,109 @@
+// 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 "content/browser/media/session/media_session_controller.h"
+
+#include "content/browser/media/media_web_contents_observer.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/common/media/media_player_delegate_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+
+namespace content {
+
+MediaSessionController::MediaSessionController(
+ const WebContentsObserver::MediaPlayerId& id,
+ MediaWebContentsObserver* media_web_contents_observer)
+ : id_(id),
+ media_web_contents_observer_(media_web_contents_observer),
+ media_session_(
+ MediaSession::Get(media_web_contents_observer_->web_contents())) {}
+
+MediaSessionController::~MediaSessionController() {
+ if (!has_session_)
+ return;
+ media_session_->RemovePlayer(this, player_id_);
+}
+
+bool MediaSessionController::Initialize(bool has_audio,
+ bool is_remote,
+ base::TimeDelta duration) {
+ // Don't generate a new id if one has already been set.
+ if (!has_session_) {
+ // These objects are only created on the UI thread, so this is safe.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ static uint32_t player_id = 0;
+ player_id_ = static_cast<int>(player_id++);
+ } else {
+ // WebMediaPlayerAndroid does not have an accurate sense of audio presence,
+ // only the MediaPlayerManager does, so WMPA never reports audio unless it's
+ // sure (no video stream). This leads to issues when Initialize() is called
+ // by WMPA (reporting no audio and subsequently releasing the session) after
+ // the manager accurately reported audio.
+ //
+ // To workaround this, |has_audio| is sticky; I.e., once a session has been
+ // created with audio all future sessions will also have audio.
+ //
+ // TODO(dalecurtis): Delete sticky audio once we're no longer using WMPA and
+ // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626
+ has_audio = true;
+ }
+
+ // Don't bother with a MediaSession for remote players or without audio. If
+ // we already have a session from a previous call, release it.
+ if (!has_audio || is_remote) {
+ if (has_session_) {
+ has_session_ = false;
+ media_session_->RemovePlayer(this, player_id_);
+ }
+ return true;
+ }
+
+ const MediaSession::Type media_session_type =
+ duration == base::TimeDelta() ||
+ duration >
+ base::TimeDelta::FromSeconds(kMinimumDurationForContentSecs)
+ ? MediaSession::Type::Content
+ : MediaSession::Type::Transient;
+
+ // If a session can't be created, force a pause immediately. Attempt to add a
+ // session even if we already have one. MediaSession expects AddPlayer() to
+ // be called after OnPlaybackPaused() to reactivate the session.
+ if (!media_session_->AddPlayer(this, player_id_, media_session_type)) {
+ OnSuspend(player_id_);
+ return false;
+ }
+
+ has_session_ = true;
+ return true;
+}
+
+void MediaSessionController::OnSuspend(int player_id) {
+ DCHECK_EQ(player_id_, player_id);
+ media_web_contents_observer_->Send(
+ new MediaPlayerDelegateMsg_Pause(id_.first->GetRoutingID(), id_.second));
+}
+
+void MediaSessionController::OnResume(int player_id) {
+ DCHECK_EQ(player_id_, player_id);
+ media_web_contents_observer_->Send(
+ new MediaPlayerDelegateMsg_Play(id_.first->GetRoutingID(), id_.second));
+}
+
+void MediaSessionController::OnSetVolumeMultiplier(int player_id,
+ double volume_multiplier) {
+ DCHECK_EQ(player_id_, player_id);
+ media_web_contents_observer_->Send(
+ new MediaPlayerDelegateMsg_UpdateVolumeMultiplier(
+ id_.first->GetRoutingID(), id_.second, volume_multiplier));
+}
+
+void MediaSessionController::OnPlaybackPaused() {
+ // We check for suspension here since the renderer may issue its own pause
+ // in response to or while a pause from the browser is in flight.
+ if (!media_session_->IsSuspended())
+ media_session_->OnPlayerPaused(this, player_id_);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_controller.h b/chromium/content/browser/media/session/media_session_controller.h
new file mode 100644
index 00000000000..c87aa2a464e
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_controller.h
@@ -0,0 +1,71 @@
+// 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 CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/time/time.h"
+#include "content/browser/media/session/media_session_observer.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class MediaSession;
+class MediaWebContentsObserver;
+
+// Helper class for controlling a single player's MediaSession instance. Sends
+// browser side MediaSession commands back to a player hosted in the renderer
+// process.
+class CONTENT_EXPORT MediaSessionController :
+ NON_EXPORTED_BASE(public MediaSessionObserver) {
+ public:
+ MediaSessionController(const WebContentsObserver::MediaPlayerId& id,
+ MediaWebContentsObserver* media_web_contents_observer);
+ ~MediaSessionController() override;
+
+ // Minimum duration of content for a MediaSession instance to be created.
+ enum { kMinimumDurationForContentSecs = 5 };
+
+ // Clients must call this after construction and destroy the controller if it
+ // returns false. May be called more than once; does nothing if none of the
+ // input parameters have changed since the last call.
+ //
+ // Note: Once a session has been initialized with |has_audio| as true, all
+ // future calls to Initialize() will retain this flag.
+ // TODO(dalecurtis): Delete sticky audio once we're no longer using WMPA and
+ // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626
+ bool Initialize(bool has_audio, bool is_remote, base::TimeDelta duration);
+
+ // Must be called when a pause occurs on the renderer side media player; keeps
+ // the MediaSession instance in sync with renderer side behavior.
+ void OnPlaybackPaused();
+
+ // MediaSessionObserver implementation.
+ void OnSuspend(int player_id) override;
+ void OnResume(int player_id) override;
+ void OnSetVolumeMultiplier(int player_id, double volume_multiplier) override;
+
+ // Test helpers.
+ int get_player_id_for_testing() const { return player_id_; }
+
+ private:
+ const WebContentsObserver::MediaPlayerId id_;
+
+ // Non-owned pointer; |media_web_contents_observer_| is the owner of |this|.
+ MediaWebContentsObserver* const media_web_contents_observer_;
+
+ // Non-owned pointer; lifetime is the same as |media_web_contents_observer_|.
+ MediaSession* const media_session_;
+
+ int player_id_ = 0;
+ bool has_session_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSessionController);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_
diff --git a/chromium/content/browser/media/session/media_session_controller_unittest.cc b/chromium/content/browser/media/session/media_session_controller_unittest.cc
new file mode 100644
index 00000000000..1b04aac3cc9
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_controller_unittest.cc
@@ -0,0 +1,214 @@
+// 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 "base/tuple.h"
+#include "content/browser/media/media_web_contents_observer.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/browser/media/session/media_session_controller.h"
+#include "content/common/media/media_player_delegate_messages.h"
+#include "content/test/test_render_view_host.h"
+#include "content/test/test_web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class MediaSessionControllerTest : public RenderViewHostImplTestHarness {
+ public:
+ void SetUp() override {
+ RenderViewHostImplTestHarness::SetUp();
+ id_ = WebContentsObserver::MediaPlayerId(contents()->GetMainFrame(), 0);
+ controller_ = CreateController();
+ }
+
+ void TearDown() override {
+ // Destruct the controller prior to any other teardown to avoid out of order
+ // destruction relative to the MediaSession instance.
+ controller_.reset();
+ RenderViewHostImplTestHarness::TearDown();
+ }
+
+ protected:
+ std::unique_ptr<MediaSessionController> CreateController() {
+ return std::unique_ptr<MediaSessionController>(new MediaSessionController(
+ id_, contents()->media_web_contents_observer()));
+ }
+
+ MediaSession* media_session() { return MediaSession::Get(contents()); }
+
+ IPC::TestSink& test_sink() { return main_test_rfh()->GetProcess()->sink(); }
+
+ void Suspend() {
+ controller_->OnSuspend(controller_->get_player_id_for_testing());
+ }
+
+ void Resume() {
+ controller_->OnResume(controller_->get_player_id_for_testing());
+ }
+
+ void SetVolumeMultiplier(double multiplier) {
+ controller_->OnSetVolumeMultiplier(controller_->get_player_id_for_testing(),
+ multiplier);
+ }
+
+ // Returns a duration long enough for a media session instance to be created.
+ base::TimeDelta DurationJustRight() {
+ return base::TimeDelta::FromSeconds(
+ MediaSessionController::kMinimumDurationForContentSecs + 1);
+ }
+
+ // Returns a duration too short for a media session instance.
+ base::TimeDelta DurationTooShort() {
+ return base::TimeDelta::FromSeconds(
+ MediaSessionController::kMinimumDurationForContentSecs);
+ }
+
+ template <typename T>
+ bool ReceivedMessagePlayPause() {
+ const IPC::Message* msg = test_sink().GetUniqueMessageMatching(T::ID);
+ if (!msg)
+ return false;
+
+ base::Tuple<int> result;
+ if (!T::Read(msg, &result))
+ return false;
+
+ EXPECT_EQ(id_.second, base::get<0>(result));
+ test_sink().ClearMessages();
+ return id_.second == base::get<0>(result);
+ }
+
+ template <typename T>
+ bool ReceivedMessageVolumeMultiplierUpdate(double expected_multiplier) {
+ const IPC::Message* msg = test_sink().GetUniqueMessageMatching(T::ID);
+ if (!msg)
+ return false;
+
+ base::Tuple<int, double> result;
+ if (!T::Read(msg, &result))
+ return false;
+
+ EXPECT_EQ(id_.second, base::get<0>(result));
+ if (id_.second != base::get<0>(result))
+ return false;
+
+ EXPECT_EQ(expected_multiplier, base::get<1>(result));
+ test_sink().ClearMessages();
+ return expected_multiplier == base::get<1>(result);
+ }
+
+ WebContentsObserver::MediaPlayerId id_;
+ std::unique_ptr<MediaSessionController> controller_;
+};
+
+TEST_F(MediaSessionControllerTest, NoAudioNoSession) {
+ ASSERT_TRUE(controller_->Initialize(false, false, DurationJustRight()));
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+}
+
+TEST_F(MediaSessionControllerTest, IsRemoteNoSession) {
+ ASSERT_TRUE(controller_->Initialize(true, true, DurationJustRight()));
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+}
+
+TEST_F(MediaSessionControllerTest, TooShortNoControllableSession) {
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationTooShort()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+}
+
+TEST_F(MediaSessionControllerTest, BasicControls) {
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+
+ // Verify suspend notifies the renderer and maintains its session.
+ Suspend();
+ EXPECT_TRUE(ReceivedMessagePlayPause<MediaPlayerDelegateMsg_Pause>());
+
+ // Likewise verify the resume behavior.
+ Resume();
+ EXPECT_TRUE(ReceivedMessagePlayPause<MediaPlayerDelegateMsg_Play>());
+
+ // Verify destruction of the controller removes its session.
+ controller_.reset();
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+}
+
+TEST_F(MediaSessionControllerTest, VolumeMultiplier) {
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+
+ // Upon creation of the MediaSession the default multiplier will be sent.
+ EXPECT_TRUE(ReceivedMessageVolumeMultiplierUpdate<
+ MediaPlayerDelegateMsg_UpdateVolumeMultiplier>(1.0));
+
+ // Verify a different volume multiplier is sent.
+ const double kTestMultiplier = 0.5;
+ SetVolumeMultiplier(kTestMultiplier);
+ EXPECT_TRUE(ReceivedMessageVolumeMultiplierUpdate<
+ MediaPlayerDelegateMsg_UpdateVolumeMultiplier>(kTestMultiplier));
+}
+
+TEST_F(MediaSessionControllerTest, ControllerSidePause) {
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+
+ // Verify pause behavior.
+ controller_->OnPlaybackPaused();
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+
+ // Verify the next Initialize() call restores the session.
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+}
+
+TEST_F(MediaSessionControllerTest, Reinitialize) {
+ ASSERT_TRUE(controller_->Initialize(false, false, DurationJustRight()));
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+
+ // Create a transient type session.
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationTooShort()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+ const int current_player_id = controller_->get_player_id_for_testing();
+
+ // Reinitialize the session as a content type.
+ ASSERT_TRUE(controller_->Initialize(true, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+ // Player id should not change when there's an active session.
+ EXPECT_EQ(current_player_id, controller_->get_player_id_for_testing());
+
+ // Verify suspend notifies the renderer and maintains its session.
+ Suspend();
+ EXPECT_TRUE(ReceivedMessagePlayPause<MediaPlayerDelegateMsg_Pause>());
+
+ // Likewise verify the resume behavior.
+ Resume();
+ EXPECT_TRUE(ReceivedMessagePlayPause<MediaPlayerDelegateMsg_Play>());
+
+ // Attempt to switch to no audio player, which should do nothing.
+ // TODO(dalecurtis): Delete this test once we're no longer using WMPA and
+ // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626
+ ASSERT_TRUE(controller_->Initialize(false, false, DurationJustRight()));
+ EXPECT_FALSE(media_session()->IsSuspended());
+ EXPECT_TRUE(media_session()->IsControllable());
+ EXPECT_EQ(current_player_id, controller_->get_player_id_for_testing());
+
+ // Switch to a remote player, which should release the session.
+ ASSERT_TRUE(controller_->Initialize(true, true, DurationJustRight()));
+ EXPECT_TRUE(media_session()->IsSuspended());
+ EXPECT_FALSE(media_session()->IsControllable());
+ EXPECT_EQ(current_player_id, controller_->get_player_id_for_testing());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_controllers_manager.cc b/chromium/content/browser/media/session/media_session_controllers_manager.cc
new file mode 100644
index 00000000000..426f3ceb325
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_controllers_manager.cc
@@ -0,0 +1,94 @@
+// 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 "content/browser/media/session/media_session_controllers_manager.h"
+
+#include "base/command_line.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/browser/media/session/media_session_controller.h"
+#include "content/browser/media/session/media_session_observer.h"
+#include "media/base/media_switches.h"
+
+namespace content {
+
+namespace {
+
+bool IsDefaultMediaSessionEnabled() {
+#if defined(OS_ANDROID)
+ return true;
+#else
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableDefaultMediaSession);
+#endif
+}
+
+} // anonymous namespace
+
+MediaSessionControllersManager::MediaSessionControllersManager(
+ MediaWebContentsObserver* media_web_contents_observer)
+ : media_web_contents_observer_(media_web_contents_observer) {
+}
+
+MediaSessionControllersManager::~MediaSessionControllersManager() = default;
+
+void MediaSessionControllersManager::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ if (!IsDefaultMediaSessionEnabled())
+ return;
+
+ for (auto it = controllers_map_.begin(); it != controllers_map_.end();) {
+ if (it->first.first == render_frame_host)
+ it = controllers_map_.erase(it);
+ else
+ ++it;
+ }
+}
+
+bool MediaSessionControllersManager::RequestPlay(const MediaPlayerId& id,
+ bool has_audio, bool is_remote, base::TimeDelta duration) {
+ if (!IsDefaultMediaSessionEnabled())
+ return true;
+
+ // Since we don't remove session instances on pause, there may be an existing
+ // instance for this playback attempt.
+ //
+ // In this case, try to reinitialize it with the new settings. If they are
+ // the same, this is a no-op. If the reinitialize fails, destroy the
+ // controller. A later playback attempt will create a new controller.
+ auto it = controllers_map_.find(id);
+ if (it != controllers_map_.end()) {
+ if (it->second->Initialize(has_audio, is_remote, duration))
+ return true;
+ controllers_map_.erase(it);
+ return false;
+ }
+
+ std::unique_ptr<MediaSessionController> controller(
+ new MediaSessionController(id, media_web_contents_observer_));
+
+ if (!controller->Initialize(has_audio, is_remote, duration))
+ return false;
+
+ controllers_map_[id] = std::move(controller);
+ return true;
+}
+
+void MediaSessionControllersManager::OnPause(const MediaPlayerId& id) {
+ if (!IsDefaultMediaSessionEnabled())
+ return;
+
+ auto it = controllers_map_.find(id);
+ if (it == controllers_map_.end())
+ return;
+
+ it->second->OnPlaybackPaused();
+}
+
+void MediaSessionControllersManager::OnEnd(const MediaPlayerId& id) {
+ if (!IsDefaultMediaSessionEnabled())
+ return;
+ controllers_map_.erase(id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_controllers_manager.h b/chromium/content/browser/media/session/media_session_controllers_manager.h
new file mode 100644
index 00000000000..f89898ac231
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_controllers_manager.h
@@ -0,0 +1,63 @@
+// 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 CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLERS_MANAGER_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLERS_MANAGER_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "content/public/browser/web_contents_observer.h" // For MediaPlayerId.
+
+namespace content {
+
+class MediaSessionController;
+class MediaWebContentsObserver;
+class RenderFrameHost;
+
+// MediaSessionControllersManager is a delegate of MediaWebContentsObserver that
+// handles MediaSessionController instances.
+class MediaSessionControllersManager {
+ public:
+ using MediaPlayerId = WebContentsObserver::MediaPlayerId;
+
+ explicit MediaSessionControllersManager(
+ MediaWebContentsObserver* media_web_contents_observer);
+ ~MediaSessionControllersManager();
+
+ // Clear all the MediaSessionController associated with the given
+ // |render_frame_host|.
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host);
+
+ // Called before a player starts playing. It will be added to the media
+ // session and will have a controller associated with it.
+ // Returns whether the player was added to the session and can start playing.
+ bool RequestPlay(const MediaPlayerId& id,
+ bool has_audio,
+ bool is_remote,
+ base::TimeDelta duration);
+
+ // Called when the given player |id| has paused.
+ void OnPause(const MediaPlayerId& id);
+
+ // Called when the given player |id| has ended.
+ void OnEnd(const MediaPlayerId& id);
+
+ private:
+ // Weak pointer because |this| is owned by |media_web_contents_observer_|.
+ MediaWebContentsObserver* const media_web_contents_observer_;
+
+ using ControllersMap =
+ std::map<MediaPlayerId, std::unique_ptr<MediaSessionController>>;
+ ControllersMap controllers_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSessionControllersManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLERS_MANAGER_H_
diff --git a/chromium/content/browser/media/session/media_session_delegate.h b/chromium/content/browser/media/session/media_session_delegate.h
new file mode 100644
index 00000000000..bc61e043d31
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate.h
@@ -0,0 +1,26 @@
+// 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 CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_H_
+
+#include "content/browser/media/session/media_session.h"
+
+namespace content {
+
+// MediaSessionDelegate is an interface abstracting audio focus handling for the
+// MediaSession class.
+class MediaSessionDelegate {
+ public:
+ // Factory method returning an implementation of MediaSessionDelegate.
+ static std::unique_ptr<MediaSessionDelegate> Create(
+ MediaSession* media_session);
+
+ virtual bool RequestAudioFocus(MediaSession::Type type) = 0;
+ virtual void AbandonAudioFocus() = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_H_
diff --git a/chromium/content/browser/media/session/media_session_delegate_android.cc b/chromium/content/browser/media/session/media_session_delegate_android.cc
new file mode 100644
index 00000000000..ddcd2865a45
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate_android.cc
@@ -0,0 +1,95 @@
+// 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 "content/browser/media/session/media_session_delegate_android.h"
+
+#include "base/android/context_utils.h"
+#include "base/android/jni_android.h"
+#include "jni/MediaSessionDelegate_jni.h"
+
+namespace content {
+
+// static
+bool MediaSessionDelegateAndroid::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+MediaSessionDelegateAndroid::MediaSessionDelegateAndroid(
+ MediaSession* media_session)
+ : media_session_(media_session) {
+}
+
+MediaSessionDelegateAndroid::~MediaSessionDelegateAndroid() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+ Java_MediaSessionDelegate_tearDown(env, j_media_session_delegate_.obj());
+}
+
+void MediaSessionDelegateAndroid::Initialize() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+ j_media_session_delegate_.Reset(Java_MediaSessionDelegate_create(
+ env,
+ base::android::GetApplicationContext(),
+ reinterpret_cast<intptr_t>(this)));
+}
+
+bool MediaSessionDelegateAndroid::RequestAudioFocus(MediaSession::Type type) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+ return Java_MediaSessionDelegate_requestAudioFocus(
+ env, j_media_session_delegate_.obj(),
+ type == MediaSession::Type::Transient);
+}
+
+void MediaSessionDelegateAndroid::AbandonAudioFocus() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+ Java_MediaSessionDelegate_abandonAudioFocus(
+ env, j_media_session_delegate_.obj());
+}
+
+void MediaSessionDelegateAndroid::OnSuspend(
+ JNIEnv*, const JavaParamRef<jobject>&, jboolean temporary) {
+ // TODO(mlamouri): this check makes it so that if a MediaSession is paused and
+ // then loses audio focus, it will still stay in the Suspended state.
+ // See https://crbug.com/539998
+ if (!media_session_->IsActive())
+ return;
+
+ if (temporary) {
+ media_session_->Suspend(MediaSession::SuspendType::SYSTEM);
+ } else {
+ media_session_->Stop(MediaSession::SuspendType::SYSTEM);
+ }
+}
+
+void MediaSessionDelegateAndroid::OnResume(
+ JNIEnv*, const JavaParamRef<jobject>&) {
+ if (!media_session_->IsReallySuspended())
+ return;
+
+ media_session_->Resume(MediaSession::SuspendType::SYSTEM);
+}
+
+void MediaSessionDelegateAndroid::OnSetVolumeMultiplier(
+ JNIEnv*, jobject, jdouble volume_multiplier) {
+ media_session_->SetVolumeMultiplier(volume_multiplier);
+}
+
+void MediaSessionDelegateAndroid::RecordSessionDuck(
+ JNIEnv*, const JavaParamRef<jobject>&) {
+ media_session_->RecordSessionDuck();
+}
+
+// static
+std::unique_ptr<MediaSessionDelegate> MediaSessionDelegate::Create(
+ MediaSession* media_session) {
+ MediaSessionDelegateAndroid* delegate =
+ new MediaSessionDelegateAndroid(media_session);
+ delegate->Initialize();
+ return std::unique_ptr<MediaSessionDelegate>(delegate);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_delegate_android.h b/chromium/content/browser/media/session/media_session_delegate_android.h
new file mode 100644
index 00000000000..99d5b1a1094
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate_android.h
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_ANDROID_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "content/browser/media/session/media_session_delegate.h"
+
+namespace content {
+
+// MediaSessionDelegateAndroid handles the audio focus at a system level on
+// Android. It is also proxying the JNI calls.
+class MediaSessionDelegateAndroid : public MediaSessionDelegate {
+ public:
+ static bool Register(JNIEnv* env);
+
+ explicit MediaSessionDelegateAndroid(MediaSession* media_session);
+ ~MediaSessionDelegateAndroid();
+
+ void Initialize();
+
+ bool RequestAudioFocus(MediaSession::Type type) override;
+ void AbandonAudioFocus() override;
+
+ // Called when the Android system requests the MediaSession to be suspended.
+ // Called by Java through JNI.
+ void OnSuspend(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jboolean temporary);
+
+ // Called when the Android system requests the MediaSession to be resumed.
+ // Called by Java through JNI.
+ void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+ // Called when the Android system requests the MediaSession to duck.
+ // Called by Java through JNI.
+ void OnSetVolumeMultiplier(JNIEnv* env, jobject obj,
+ jdouble volume_multiplier);
+
+ // Called when the Android system requests the MediaSession to duck.
+ // Called by Java through JNI.
+ void RecordSessionDuck(JNIEnv* env,
+ const base::android::JavaParamRef<jobject> &obj);
+
+ private:
+ // Weak pointer because |this| is owned by |media_session_|.
+ MediaSession* media_session_;
+ base::android::ScopedJavaGlobalRef<jobject> j_media_session_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSessionDelegateAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_DELEGATE_ANDROID_H_
diff --git a/chromium/content/browser/media/session/media_session_delegate_android_browsertest.cc b/chromium/content/browser/media/session/media_session_delegate_android_browsertest.cc
new file mode 100644
index 00000000000..cfc844c406a
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate_android_browsertest.cc
@@ -0,0 +1,65 @@
+// 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 "base/command_line.h"
+#include "base/run_loop.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/browser/media/session/mock_media_session_observer.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+
+class MediaSessionDelegateAndroidBrowserTest : public ContentBrowserTest {};
+
+// MAYBE_OnAudioFocusChangeAfterDtorCrash will hit a DCHECK before the crash, it
+// is the only way found to actually reproduce the crash so as a result, the
+// test will only run on builds without DCHECK's.
+// TODO(mlamouri): the test is flaky on one bot. It is disabled until the cause
+// is found.
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define MAYBE_OnAudioFocusChangeAfterDtorCrash \
+ DISABLED_OnAudioFocusChangeAfterDtorCrash
+#else
+#define MAYBE_OnAudioFocusChangeAfterDtorCrash \
+ DISABLED_OnAudioFocusChangeAfterDtorCrash
+#endif
+
+IN_PROC_BROWSER_TEST_F(MediaSessionDelegateAndroidBrowserTest,
+ MAYBE_OnAudioFocusChangeAfterDtorCrash) {
+ scoped_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
+
+ MediaSession* media_session = MediaSession::Get(shell()->web_contents());
+ ASSERT_TRUE(media_session);
+
+ WebContents* other_web_contents = CreateBrowser()->web_contents();
+ MediaSession* other_media_session = MediaSession::Get(other_web_contents);
+ ASSERT_TRUE(other_media_session);
+
+ media_session_observer->StartNewPlayer();
+ media_session->AddPlayer(media_session_observer.get(), 0,
+ MediaSession::Type::Content);
+ EXPECT_TRUE(media_session->IsActive());
+ EXPECT_FALSE(other_media_session->IsActive());
+
+ media_session_observer->StartNewPlayer();
+ other_media_session->AddPlayer(media_session_observer.get(), 1,
+ MediaSession::Type::Content);
+ EXPECT_TRUE(media_session->IsActive());
+ EXPECT_TRUE(other_media_session->IsActive());
+
+ shell()->CloseAllWindows();
+
+ // Give some time to the AudioFocusManager to send an audioFocusChange message
+ // to the listeners. If the bug is still present, it will crash.
+ {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(1));
+ run_loop.Run();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_delegate_default.cc b/chromium/content/browser/media/session/media_session_delegate_default.cc
new file mode 100644
index 00000000000..688ce53d14f
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate_default.cc
@@ -0,0 +1,62 @@
+// 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 "content/browser/media/session/media_session_delegate.h"
+
+#include "base/command_line.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "media/base/media_switches.h"
+
+namespace content {
+
+namespace {
+
+// MediaSessionDelegateDefault is the default implementation of
+// MediaSessionDelegate which only handles audio focus between WebContents.
+class MediaSessionDelegateDefault : public MediaSessionDelegate {
+ public:
+ explicit MediaSessionDelegateDefault(MediaSession* media_session);
+
+ // MediaSessionDelegate implementation.
+ bool RequestAudioFocus(MediaSession::Type type) override;
+ void AbandonAudioFocus() override;
+
+ private:
+ // Weak pointer because |this| is owned by |media_session_|.
+ MediaSession* media_session_;
+};
+
+} // anonymous namespace
+
+MediaSessionDelegateDefault::MediaSessionDelegateDefault(
+ MediaSession* media_session)
+ : media_session_(media_session) {
+}
+
+bool MediaSessionDelegateDefault::RequestAudioFocus(MediaSession::Type) {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableDefaultMediaSession)) {
+ return true;
+ }
+
+ for (WebContentsImpl* web_contents : WebContentsImpl::GetAllWebContents()) {
+ MediaSession* media_session = MediaSession::Get(web_contents);
+ if (media_session == media_session_ || !media_session->IsActive())
+ continue;
+ media_session->Suspend(MediaSession::SuspendType::SYSTEM);
+ }
+ return true;
+}
+
+void MediaSessionDelegateDefault::AbandonAudioFocus() {
+}
+
+// static
+std::unique_ptr<MediaSessionDelegate> MediaSessionDelegate::Create(
+ MediaSession* media_session) {
+ return std::unique_ptr<MediaSessionDelegate>(
+ new MediaSessionDelegateDefault(media_session));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_delegate_default_browsertest.cc b/chromium/content/browser/media/session/media_session_delegate_default_browsertest.cc
new file mode 100644
index 00000000000..cc269269ded
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_delegate_default_browsertest.cc
@@ -0,0 +1,49 @@
+// 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 "base/command_line.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/browser/media/session/mock_media_session_observer.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "media/base/media_switches.h"
+
+namespace content {
+
+class MediaSessionDelegateDefaultBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kEnableDefaultMediaSession);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(MediaSessionDelegateDefaultBrowserTest,
+ ActiveWebContentsPauseOthers) {
+ std::unique_ptr<MockMediaSessionObserver> media_session_observer(
+ new MockMediaSessionObserver);
+
+ MediaSession* media_session = MediaSession::Get(shell()->web_contents());
+ ASSERT_TRUE(media_session);
+
+ WebContents* other_web_contents = CreateBrowser()->web_contents();
+ MediaSession* other_media_session = MediaSession::Get(other_web_contents);
+ ASSERT_TRUE(other_media_session);
+
+ media_session_observer->StartNewPlayer();
+ media_session->AddPlayer(
+ media_session_observer.get(), 0, MediaSession::Type::Content);
+ EXPECT_TRUE(media_session->IsActive());
+ EXPECT_FALSE(other_media_session->IsActive());
+
+ media_session_observer->StartNewPlayer();
+ other_media_session->AddPlayer(
+ media_session_observer.get(), 1, MediaSession::Type::Content);
+ EXPECT_FALSE(media_session->IsActive());
+ EXPECT_TRUE(other_media_session->IsActive());
+
+ media_session->Stop(MediaSession::SuspendType::UI);
+ other_media_session->Stop(MediaSession::SuspendType::UI);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/android/media_session_observer.h b/chromium/content/browser/media/session/media_session_observer.h
index 6316ab6043c..4d9f4d498c2 100644
--- a/chromium/content/browser/media/android/media_session_observer.h
+++ b/chromium/content/browser/media/session/media_session_observer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_OBSERVER_H_
-#define CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_OBSERVER_H_
+#ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_OBSERVER_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_OBSERVER_H_
namespace content {
@@ -17,8 +17,13 @@ class MediaSessionObserver {
// The given |player_id| has been resumed by the MediaSession.
virtual void OnResume(int player_id) = 0;
+
+ // The given |player_id| has been set a new volume multiplier by
+ // the MediaSession.
+ virtual void OnSetVolumeMultiplier(int player_id,
+ double volume_multiplier) = 0;
};
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_OBSERVER_H_
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_OBSERVER_H_
diff --git a/chromium/content/browser/media/android/media_session_uma_helper.cc b/chromium/content/browser/media/session/media_session_uma_helper.cc
index 35e79dd9d5d..17a43b03a1f 100644
--- a/chromium/content/browser/media/android/media_session_uma_helper.cc
+++ b/chromium/content/browser/media/session/media_session_uma_helper.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/android/media_session_uma_helper.h"
+#include "content/browser/media/session/media_session_uma_helper.h"
#include <utility>
@@ -59,7 +59,7 @@ void MediaSessionUmaHelper::OnSessionInactive() {
}
void MediaSessionUmaHelper::SetClockForTest(
- scoped_ptr<base::Clock> testing_clock) {
+ std::unique_ptr<base::Clock> testing_clock) {
clock_ = std::move(testing_clock);
}
diff --git a/chromium/content/browser/media/android/media_session_uma_helper.h b/chromium/content/browser/media/session/media_session_uma_helper.h
index 69fbaa9363f..290c3b94a4c 100644
--- a/chromium/content/browser/media/android/media_session_uma_helper.h
+++ b/chromium/content/browser/media/session/media_session_uma_helper.h
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_UMA_HELPER_H_
-#define CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_UMA_HELPER_H_
+#ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_UMA_HELPER_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_UMA_HELPER_H_
+
+#include <memory>
-#include "base/memory/scoped_ptr.h"
#include "base/time/clock.h"
#include "content/common/content_export.h"
@@ -24,6 +25,7 @@ class CONTENT_EXPORT MediaSessionUmaHelper {
SystemPermanent = 1,
UI = 2,
CONTENT = 3,
+ SystemTransientDuck = 4,
Count // Leave at the end.
};
@@ -39,14 +41,14 @@ class CONTENT_EXPORT MediaSessionUmaHelper {
void OnSessionSuspended();
void OnSessionInactive();
- void SetClockForTest(scoped_ptr<base::Clock> testing_clock);
+ void SetClockForTest(std::unique_ptr<base::Clock> testing_clock);
private:
base::TimeDelta total_active_time_;
base::Time current_active_time_;
- scoped_ptr<base::Clock> clock_;
+ std::unique_ptr<base::Clock> clock_;
};
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_SESSION_UMA_HELPER_H_
+#endif // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_UMA_HELPER_H_
diff --git a/chromium/content/browser/media/android/media_session_uma_helper_unittest.cc b/chromium/content/browser/media/session/media_session_uma_helper_unittest.cc
index c4b3fc3d7d0..de9b2df2e76 100644
--- a/chromium/content/browser/media/android/media_session_uma_helper_unittest.cc
+++ b/chromium/content/browser/media/session/media_session_uma_helper_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/android/media_session_uma_helper.h"
+#include "content/browser/media/session/media_session_uma_helper.h"
#include "base/metrics/histogram_samples.h"
#include "base/test/histogram_tester.h"
@@ -24,7 +24,7 @@ class MediaSessionUmaHelperTest : public testing::Test {
clock_ = new base::SimpleTestClock();
clock_->SetNow(base::Time::Now());
media_session_uma_helper_.SetClockForTest(
- scoped_ptr<base::SimpleTestClock>(clock_));
+ std::unique_ptr<base::SimpleTestClock>(clock_));
}
void TearDown() override {
@@ -37,7 +37,7 @@ class MediaSessionUmaHelperTest : public testing::Test {
return media_session_uma_helper_;
};
- scoped_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart(
+ std::unique_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart(
const std::string& name) {
return histogram_tester_.GetHistogramSamplesSinceCreation(name);
}
@@ -57,13 +57,13 @@ TEST_F(MediaSessionUmaHelperTest, CreateAndKillDoesNothing) {
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.Suspended"));
EXPECT_EQ(0, samples->TotalCount());
}
{
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -73,7 +73,7 @@ TEST_F(MediaSessionUmaHelperTest, SuspendRegisterImmediately) {
media_session_uma_helper().RecordSessionSuspended(
MediaSessionSuspendedSource::SystemTransient);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.Suspended"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(0)); // System Transient
@@ -89,7 +89,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleSuspend) {
media_session_uma_helper().RecordSessionSuspended(
MediaSessionSuspendedSource::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.Suspended"));
EXPECT_EQ(3, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(0)); // System Transient
@@ -111,7 +111,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleSuspendSame) {
media_session_uma_helper().RecordSessionSuspended(
MediaSessionSuspendedSource::UI);
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.Suspended"));
EXPECT_EQ(6, samples->TotalCount());
EXPECT_EQ(2, samples->GetCount(0)); // System Transient
@@ -123,7 +123,7 @@ TEST_F(MediaSessionUmaHelperTest, ActivationNotTerminatedDoesNotCommit) {
media_session_uma_helper().OnSessionActive();
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -134,7 +134,7 @@ TEST_F(MediaSessionUmaHelperTest, SuspendActivationNotTerminatedDoesNotCommit) {
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
media_session_uma_helper().OnSessionSuspended();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(0, samples->TotalCount());
}
@@ -145,7 +145,7 @@ TEST_F(MediaSessionUmaHelperTest, FullActivation) {
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
media_session_uma_helper().OnSessionInactive();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -163,7 +163,7 @@ TEST_F(MediaSessionUmaHelperTest, ActivationCycleWithSuspend) {
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
media_session_uma_helper().OnSessionInactive();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(2000));
@@ -187,7 +187,7 @@ TEST_F(MediaSessionUmaHelperTest, ActivationCycleWithMultipleSuspend) {
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
media_session_uma_helper().OnSessionInactive();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(3000));
@@ -222,7 +222,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleActivations) {
clock()->Advance(base::TimeDelta::FromMilliseconds(1000));
media_session_uma_helper().OnSessionInactive();
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(2000));
@@ -243,7 +243,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleActivationCalls) {
// Calling OnSessionActive() multiple times reset the start time of the
// session.
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(500));
@@ -265,7 +265,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleSuspendCalls_WhileSuspended) {
// If the session is already suspended, OnSessionSuspended() calls are
// ignored.
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -287,7 +287,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleSuspendCalls_WhileInactive) {
// If the session is already inactive, OnSessionSuspended() calls are
// ignored.
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(1000));
@@ -306,7 +306,7 @@ TEST_F(MediaSessionUmaHelperTest, MultipleInactiveCalls) {
media_session_uma_helper().OnSessionInactive();
// If the session is already inactive, OnSessionInactive() calls are ignored.
- scoped_ptr<base::HistogramSamples> samples(
+ std::unique_ptr<base::HistogramSamples> samples(
GetHistogramSamplesSinceTestStart("Media.Session.ActiveTime"));
EXPECT_EQ(1, samples->TotalCount());
EXPECT_EQ(1, samples->GetCount(3000));
diff --git a/chromium/content/browser/media/session/media_session_visibility_browsertest.cc b/chromium/content/browser/media/session/media_session_visibility_browsertest.cc
new file mode 100644
index 00000000000..f83cd858081
--- /dev/null
+++ b/chromium/content/browser/media/session/media_session_visibility_browsertest.cc
@@ -0,0 +1,266 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "content/browser/media/session/media_session.h"
+#include "content/public/browser/web_contents.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 "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+#include "media/base/media_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+static const char kStartPlayerScript[] =
+ "document.getElementById('long-video').play()";
+static const char kPausePlayerScript[] =
+ "document.getElementById('long-video').pause()";
+}
+
+
+// Base class of MediaSession visibility tests. The class is intended
+// to be used to run tests under different configurations. Tests
+// should inheret from this class, set up their own command line per
+// their configuration, and use macro INCLUDE_TEST_FROM_BASE_CLASS to
+// include required tests. See
+// media_session_visibility_browsertest_instances.cc for examples.
+class MediaSessionVisibilityBrowserTest
+ : public ContentBrowserTest {
+ public:
+ MediaSessionVisibilityBrowserTest() = default;
+ ~MediaSessionVisibilityBrowserTest() override = default;
+
+ void SetUpOnMainThread() override {
+ ContentBrowserTest::SetUpOnMainThread();
+ web_contents_ = shell()->web_contents();
+ media_session_ = MediaSession::Get(web_contents_);
+
+ media_session_state_loop_runners_[MediaSession::State::ACTIVE] =
+ new MessageLoopRunner();
+ media_session_state_loop_runners_[MediaSession::State::SUSPENDED] =
+ new MessageLoopRunner();
+ media_session_state_loop_runners_[MediaSession::State::INACTIVE] =
+ new MessageLoopRunner();
+ media_session_state_callback_subscription_ =
+ media_session_->RegisterMediaSessionStateChangedCallbackForTest(
+ base::Bind(&MediaSessionVisibilityBrowserTest::
+ OnMediaSessionStateChanged,
+ base::Unretained(this)));
+ }
+
+ void TearDownOnMainThread() override {
+ // Unsubscribe the callback subscription before tearing down, so that the
+ // CallbackList in MediaSession will be empty when it is destroyed.
+ media_session_state_callback_subscription_.reset();
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(
+ switches::kDisableGestureRequirementForMediaPlayback);
+#if !defined(OS_ANDROID)
+ command_line->AppendSwitch(
+ switches::kEnableDefaultMediaSession);
+#endif // !defined(OS_ANDROID)
+ }
+
+ void LoadTestPage() {
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(GetTestUrl("media/session", "media-session.html"));
+ navigation_observer.Wait();
+ }
+
+ void RunScript(const std::string& script) {
+ ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(), script));
+ }
+
+ void ClearMediaSessionStateLoopRunners() {
+ for (auto& state_loop_runner : media_session_state_loop_runners_)
+ state_loop_runner.second = new MessageLoopRunner();
+ }
+
+ void OnMediaSessionStateChanged(MediaSession::State state) {
+ ASSERT_TRUE(media_session_state_loop_runners_.count(state));
+ media_session_state_loop_runners_[state]->Quit();
+ }
+
+ // TODO(zqzhang): This method is shared with
+ // MediaRouterIntegrationTests. Move it into a general place.
+ void Wait(base::TimeDelta timeout) {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), timeout);
+ run_loop.Run();
+ }
+
+ void WaitForMediaSessionState(MediaSession::State state) {
+ ASSERT_TRUE(media_session_state_loop_runners_.count(state));
+ media_session_state_loop_runners_[state]->Run();
+ }
+
+ protected:
+ void TestSessionInactiveWhenHiddenAfterContentPause() {
+ LoadTestPage();
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kStartPlayerScript);
+ WaitForMediaSessionState(MediaSession::State::ACTIVE);
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kPausePlayerScript);
+ WaitForMediaSessionState(MediaSession::State::SUSPENDED);
+
+ ClearMediaSessionStateLoopRunners();
+ web_contents_->WasHidden();
+ WaitForMediaSessionState(MediaSession::State::INACTIVE);
+ }
+
+ void TestSessionInactiveWhenHiddenWhilePlaying() {
+ LoadTestPage();
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kStartPlayerScript);
+ WaitForMediaSessionState(MediaSession::State::ACTIVE);
+
+ ClearMediaSessionStateLoopRunners();
+ web_contents_->WasHidden();
+ WaitForMediaSessionState(MediaSession::State::INACTIVE);
+ }
+
+ void TestSessionSuspendedWhenHiddenAfterContentPause() {
+ LoadTestPage();
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kStartPlayerScript);
+ WaitForMediaSessionState(MediaSession::State::ACTIVE);
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kPausePlayerScript);
+ WaitForMediaSessionState(MediaSession::State::SUSPENDED);
+
+ // Wait for 1 second and check the MediaSession state.
+ // No better solution till now.
+ web_contents_->WasHidden();
+ Wait(base::TimeDelta::FromSeconds(1));
+ ASSERT_EQ(media_session_->audio_focus_state_,
+ MediaSession::State::SUSPENDED);
+ }
+
+ void TestSessionActiveWhenHiddenWhilePlaying() {
+ LoadTestPage();
+
+ ClearMediaSessionStateLoopRunners();
+ RunScript(kStartPlayerScript);
+ WaitForMediaSessionState(MediaSession::State::ACTIVE);
+
+ // Wait for 1 second and check the MediaSession state.
+ // No better solution till now.
+ web_contents_->WasHidden();
+ Wait(base::TimeDelta::FromSeconds(1));
+ ASSERT_EQ(media_session_->audio_focus_state_,
+ MediaSession::State::ACTIVE);
+ }
+
+ WebContents* web_contents_;
+ MediaSession* media_session_;
+ // MessageLoopRunners for waiting MediaSession state to change. Note that the
+ // MessageLoopRunners can accept Quit() before calling Run(), thus the state
+ // change can still be captured before waiting. For example, the MediaSession
+ // might go active immediately after calling HTMLMediaElement.play(). A test
+ // can listen to the state change before calling play(), and then wait for the
+ // state change after play().
+ std::map<MediaSession::State, scoped_refptr<MessageLoopRunner> >
+ media_session_state_loop_runners_;
+ std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription>
+ media_session_state_callback_subscription_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaSessionVisibilityBrowserTest);
+};
+
+// Helper macro to include tests from the base class.
+#define INCLUDE_TEST_FROM_BASE_CLASS(test_fixture, test_name) \
+ IN_PROC_BROWSER_TEST_F(test_fixture, test_name) { \
+ test_name(); \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Configuration instances.
+
+// UnifiedPipeline + SuspendOnHide
+class MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide :
+ public MediaSessionVisibilityBrowserTest {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ MediaSessionVisibilityBrowserTest::SetUpCommandLine(command_line);
+#if !defined(OS_ANDROID)
+ command_line->AppendSwitch(switches::kEnableMediaSuspend);
+#endif // defined(OS_ANDROID)
+ }
+};
+
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide,
+ TestSessionInactiveWhenHiddenAfterContentPause)
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide,
+ TestSessionInactiveWhenHiddenWhilePlaying)
+
+// UnifiedPipeline + NosuspendOnHide
+class MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide :
+ public MediaSessionVisibilityBrowserTest {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ MediaSessionVisibilityBrowserTest::SetUpCommandLine(command_line);
+#if defined(OS_ANDROID)
+ command_line->AppendSwitch(switches::kDisableMediaSuspend);
+#endif // defined(OS_ANDROID)
+ }
+};
+
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide,
+ TestSessionSuspendedWhenHiddenAfterContentPause)
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide,
+ TestSessionActiveWhenHiddenWhilePlaying)
+
+#if defined(OS_ANDROID)
+// AndroidPipeline + SuspendOnHide
+class MediaSessionVisibilityBrowserTest_AndroidPipeline_SuspendOnHide :
+ public MediaSessionVisibilityBrowserTest {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ MediaSessionVisibilityBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kDisableUnifiedMediaPipeline);
+ }
+};
+
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_AndroidPipeline_SuspendOnHide,
+ TestSessionInactiveWhenHiddenAfterContentPause)
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_AndroidPipeline_SuspendOnHide,
+ TestSessionInactiveWhenHiddenWhilePlaying)
+
+// AndroidPipeline + NosuspendOnHide
+class MediaSessionVisibilityBrowserTest_AndroidPipeline_NosuspendOnHide :
+ public MediaSessionVisibilityBrowserTest {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ MediaSessionVisibilityBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kDisableUnifiedMediaPipeline);
+ command_line->AppendSwitch(switches::kDisableMediaSuspend);
+ }
+};
+
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_AndroidPipeline_NosuspendOnHide,
+ TestSessionSuspendedWhenHiddenAfterContentPause)
+INCLUDE_TEST_FROM_BASE_CLASS(
+ MediaSessionVisibilityBrowserTest_AndroidPipeline_NosuspendOnHide,
+ TestSessionActiveWhenHiddenWhilePlaying)
+
+#endif // defined(OS_ANDROID)
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/mock_media_session_observer.cc b/chromium/content/browser/media/session/mock_media_session_observer.cc
new file mode 100644
index 00000000000..edc213a1090
--- /dev/null
+++ b/chromium/content/browser/media/session/mock_media_session_observer.cc
@@ -0,0 +1,70 @@
+// 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 "content/browser/media/session/mock_media_session_observer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+MockMediaSessionObserver::MockMediaSessionObserver() = default;
+
+MockMediaSessionObserver::~MockMediaSessionObserver() = default;
+
+void MockMediaSessionObserver::OnSuspend(int player_id) {
+ EXPECT_GE(player_id, 0);
+ EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
+
+ ++received_suspend_calls_;
+ players_[player_id].is_playing_ = false;
+}
+
+void MockMediaSessionObserver::OnResume(int player_id) {
+ EXPECT_GE(player_id, 0);
+ EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
+
+ ++received_resume_calls_;
+ players_[player_id].is_playing_ = true;
+}
+
+void MockMediaSessionObserver::OnSetVolumeMultiplier(
+ int player_id, double volume_multiplier) {
+ EXPECT_GE(player_id, 0);
+ EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
+
+ EXPECT_GE(volume_multiplier, 0.0f);
+ EXPECT_LE(volume_multiplier, 1.0f);
+
+ players_[player_id].volume_multiplier_ = volume_multiplier;
+}
+
+int MockMediaSessionObserver::StartNewPlayer() {
+ players_.push_back(MockPlayer(true, 1.0f));
+ return players_.size() - 1;
+}
+
+bool MockMediaSessionObserver::IsPlaying(size_t player_id) {
+ EXPECT_GT(players_.size(), player_id);
+ return players_[player_id].is_playing_;
+}
+
+double MockMediaSessionObserver::GetVolumeMultiplier(size_t player_id) {
+ EXPECT_GT(players_.size(), player_id);
+ return players_[player_id].volume_multiplier_;
+}
+
+void MockMediaSessionObserver::SetPlaying(size_t player_id, bool playing) {
+ EXPECT_GT(players_.size(), player_id);
+ players_[player_id].is_playing_ = playing;
+}
+
+int MockMediaSessionObserver::received_suspend_calls() const {
+ return received_suspend_calls_;
+}
+
+int MockMediaSessionObserver::received_resume_calls() const {
+ return received_resume_calls_;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/mock_media_session_observer.h b/chromium/content/browser/media/session/mock_media_session_observer.h
new file mode 100644
index 00000000000..03913bced06
--- /dev/null
+++ b/chromium/content/browser/media/session/mock_media_session_observer.h
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <vector>
+
+#include "content/browser/media/session/media_session_observer.h"
+
+namespace content {
+
+// MockMediaSessionObserver is a mock implementation of MediaSessionObserver to
+// be used in tests.
+class MockMediaSessionObserver : public MediaSessionObserver {
+ public:
+ MockMediaSessionObserver();
+ ~MockMediaSessionObserver() override;
+
+ // Implements MediaSessionObserver.
+ void OnSuspend(int player_id) override;
+ void OnResume(int player_id) override;
+ void OnSetVolumeMultiplier(int player_id, double volume_multiplier) override;
+
+ // Simulate that a new player started.
+ // Returns the player_id.
+ int StartNewPlayer();
+
+ // Returns whether |player_id| is playing.
+ bool IsPlaying(size_t player_id);
+
+ // Returns the volume multiplier of |player_id|.
+ double GetVolumeMultiplier(size_t player_id);
+
+ // Simulate a play state change for |player_id|.
+ void SetPlaying(size_t player_id, bool playing);
+
+ int received_suspend_calls() const;
+ int received_resume_calls() const;
+
+ private:
+ // Internal representation of the players to keep track of their statuses.
+ struct MockPlayer {
+ public:
+ MockPlayer(bool is_playing = true, double volume_multiplier = 1.0f)
+ : is_playing_(is_playing),
+ volume_multiplier_(volume_multiplier) {}
+ bool is_playing_;
+ double volume_multiplier_;
+ };
+
+ // Basic representation of the players. The position in the vector is the
+ // player_id. The value of the vector is the playing status and volume.
+ std::vector<MockPlayer> players_;
+
+ int received_resume_calls_ = 0;
+ int received_suspend_calls_ = 0;
+};
+
+} // namespace content
diff --git a/chromium/content/browser/media/webrtc/OWNERS b/chromium/content/browser/media/webrtc/OWNERS
new file mode 100644
index 00000000000..43cd73bcb81
--- /dev/null
+++ b/chromium/content/browser/media/webrtc/OWNERS
@@ -0,0 +1,5 @@
+perkj@chromium.org
+tommi@chromium.org
+
+# For WebRTC browser tests, etc.
+per-file *webrtc*browsertest*=phoglund@chromium.org
diff --git a/chromium/content/browser/media/webrtc_audio_debug_recordings_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc
index f42aed10011..5fe344d8ab4 100644
--- a/chromium/content/browser/media/webrtc_audio_debug_recordings_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc
@@ -8,7 +8,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
@@ -59,7 +59,7 @@ base::FilePath GetExpectedInputAudioFileName(const base::FilePath& base_file,
return base_file.AddExtension(IntToStringType(render_process_id))
.AddExtension(FILE_PATH_LITERAL("source_input"))
.AddExtension(IntToStringType(kExpectedStreamId))
- .AddExtension(FILE_PATH_LITERAL("pcm"));
+ .AddExtension(FILE_PATH_LITERAL("wav"));
}
} // namespace
diff --git a/chromium/content/browser/media/webrtc_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_browsertest.cc
index 7dd174f7f13..7dd174f7f13 100644
--- a/chromium/content/browser/media/webrtc_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_browsertest.cc
diff --git a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc
index 0645511ffd3..73c8dc97351 100644
--- a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc
@@ -6,12 +6,13 @@
#include "base/command_line.h"
#include "base/json/json_reader.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/strings/stringprintf.h"
#include "base/test/trace_event_analyzer.h"
#include "base/trace_event/trace_event_impl.h"
#include "base/values.h"
#include "build/build_config.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -146,7 +147,7 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
// would stop both this code and the browser underneath.
StopTracing();
- scoped_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer());
+ std::unique_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer());
analyzer->AssociateBeginEndEvents();
trace_analyzer::TraceEventVector events;
DCHECK(measure_filter.size());
@@ -204,7 +205,7 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
int error_code;
std::string error_message;
- scoped_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
+ std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
&error_message);
diff --git a/chromium/content/browser/media/webrtc_identity_store.cc b/chromium/content/browser/media/webrtc/webrtc_identity_store.cc
index 2ada2a15f40..0dc62e4ecda 100644
--- a/chromium/content/browser/media/webrtc_identity_store.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_identity_store.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
#include <stddef.h>
#include <stdint.h>
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "base/rand_util.h"
#include "base/threading/worker_pool.h"
-#include "content/browser/media/webrtc_identity_store_backend.h"
+#include "content/browser/media/webrtc/webrtc_identity_store_backend.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/rsa_private_key.h"
#include "net/base/net_errors.h"
@@ -43,7 +43,7 @@ static void GenerateIdentityWorker(const std::string& common_name,
result->error = net::OK;
int serial_number = base::RandInt(0, std::numeric_limits<int>::max());
- scoped_ptr<crypto::RSAPrivateKey> key;
+ std::unique_ptr<crypto::RSAPrivateKey> key;
base::Time now = base::Time::Now();
bool success = net::x509_util::CreateKeyAndSelfSignedCert(
"CN=" + common_name,
diff --git a/chromium/content/browser/media/webrtc_identity_store.h b/chromium/content/browser/media/webrtc/webrtc_identity_store.h
index c788d0dd70d..360171d0f90 100644
--- a/chromium/content/browser/media/webrtc_identity_store.h
+++ b/chromium/content/browser/media/webrtc/webrtc_identity_store.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
#include <string>
#include <vector>
@@ -123,4 +123,4 @@ class CONTENT_EXPORT WebRTCIdentityStore
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.cc b/chromium/content/browser/media/webrtc/webrtc_identity_store_backend.cc
index 76d4827d121..dc247b7a3a7 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_identity_store_backend.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 "content/browser/media/webrtc_identity_store_backend.h"
+#include "content/browser/media/webrtc/webrtc_identity_store_backend.h"
#include <stddef.h>
#include <stdint.h>
@@ -175,7 +175,7 @@ class WebRTCIdentityStoreBackend::SqlLiteStorage
// The file path of the DB. Empty if temporary.
base::FilePath path_;
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
- scoped_ptr<sql::Connection> db_;
+ std::unique_ptr<sql::Connection> db_;
// Batched DB operations pending to commit.
PendingOperationList pending_operations_;
@@ -210,7 +210,7 @@ bool WebRTCIdentityStoreBackend::FindIdentity(
DCHECK_EQ(state_, NOT_STARTED);
// Kick off loading the DB.
- scoped_ptr<IdentityMap> out_map(new IdentityMap());
+ std::unique_ptr<IdentityMap> out_map(new IdentityMap());
base::Closure task(
base::Bind(&SqlLiteStorage::Load, sql_lite_storage_, out_map.get()));
// |out_map| will be NULL after this call.
@@ -346,7 +346,8 @@ void WebRTCIdentityStoreBackend::SetValidityPeriodForTesting(
WebRTCIdentityStoreBackend::~WebRTCIdentityStoreBackend() {}
-void WebRTCIdentityStoreBackend::OnLoaded(scoped_ptr<IdentityMap> out_map) {
+void WebRTCIdentityStoreBackend::OnLoaded(
+ std::unique_ptr<IdentityMap> out_map) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (state_ != LOADING)
@@ -514,7 +515,7 @@ void WebRTCIdentityStoreBackend::SqlLiteStorage::BatchOperation(
static const size_t kCommitAfterBatchSize = 512;
// We do a full copy of the cert here, and hopefully just here.
- scoped_ptr<PendingOperation> operation(
+ std::unique_ptr<PendingOperation> operation(
new PendingOperation(type, origin, identity_name, identity));
pending_operations_.push_back(operation.release());
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.h b/chromium/content/browser/media/webrtc/webrtc_identity_store_backend.h
index 906f71a6e34..e0948b7f7e4 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.h
+++ b/chromium/content/browser/media/webrtc/webrtc_identity_store_backend.h
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
#include <map>
+#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
class GURL;
@@ -102,8 +102,7 @@ class WebRTCIdentityStoreBackend
~WebRTCIdentityStoreBackend();
- void OnLoaded(scoped_ptr<IdentityMap> out_map);
-
+ void OnLoaded(std::unique_ptr<IdentityMap> out_map);
// Identities expires after |validity_period_|.
base::TimeDelta validity_period_;
@@ -120,4 +119,4 @@ class WebRTCIdentityStoreBackend
};
}
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
diff --git a/chromium/content/browser/media/webrtc_identity_store_unittest.cc b/chromium/content/browser/media/webrtc/webrtc_identity_store_unittest.cc
index 025e2f3231b..710861c3746 100644
--- a/chromium/content/browser/media/webrtc_identity_store_unittest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_identity_store_unittest.cc
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
+
+#include <memory>
+
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
#include "base/test/sequenced_worker_pool_owner.h"
-#include "content/browser/media/webrtc_identity_store.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_errors.h"
@@ -84,7 +86,7 @@ class WebRtcIdentityStoreTest : public testing::Test {
protected:
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_;
+ std::unique_ptr<base::SequencedWorkerPoolOwner> pool_owner_;
scoped_refptr<WebRTCIdentityStore> webrtc_identity_store_;
};
@@ -384,7 +386,7 @@ TEST_F(WebRtcIdentityStoreTest, HandleDBErrors) {
RunUntilIdle();
// Verifies the corrupted table was razed.
- scoped_ptr<sql::Connection> db(new sql::Connection());
+ std::unique_ptr<sql::Connection> db(new sql::Connection());
EXPECT_TRUE(db->Open(db_path));
EXPECT_EQ(0U, sql::test::CountSQLTables(db.get()));
diff --git a/chromium/content/browser/media/webrtc_internals.cc b/chromium/content/browser/media/webrtc/webrtc_internals.cc
index 40aa91baaec..1ebc884a5cb 100644
--- a/chromium/content/browser/media/webrtc_internals.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_internals.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include <stddef.h>
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
#include "content/browser/web_contents/web_contents_view.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -39,10 +39,37 @@ static base::ListValue* EnsureLogList(base::DictionaryValue* dict) {
} // namespace
-WebRTCInternals::WebRTCInternals()
+WebRTCInternals::PendingUpdate::PendingUpdate(
+ const std::string& command,
+ std::unique_ptr<base::Value> value)
+ : command_(command), value_(std::move(value)) {}
+
+WebRTCInternals::PendingUpdate::PendingUpdate(PendingUpdate&& other)
+ : command_(std::move(other.command_)),
+ value_(std::move(other.value_)) {}
+
+WebRTCInternals::PendingUpdate::~PendingUpdate() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+const std::string& WebRTCInternals::PendingUpdate::command() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return command_;
+}
+
+const base::Value* WebRTCInternals::PendingUpdate::value() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return value_.get();
+}
+
+WebRTCInternals::WebRTCInternals() : WebRTCInternals(500) {}
+
+WebRTCInternals::WebRTCInternals(int aggregate_updates_ms)
: audio_debug_recordings_(false),
event_log_recordings_(false),
- selecting_event_log_(false) {
+ selecting_event_log_(false),
+ aggregate_updates_ms_(aggregate_updates_ms),
+ weak_factory_(this) {
// TODO(grunell): Shouldn't all the webrtc_internals* files be excluded from the
// build if WebRTC is disabled?
#if defined(ENABLE_WEBRTC)
@@ -82,9 +109,6 @@ void WebRTCInternals::OnAddPeerConnection(int render_process_id,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::DictionaryValue* dict = new base::DictionaryValue();
- if (!dict)
- return;
-
dict->SetInteger("rid", render_process_id);
dict->SetInteger("pid", static_cast<int>(pid));
dict->SetInteger("lid", lid);
@@ -95,7 +119,7 @@ void WebRTCInternals::OnAddPeerConnection(int render_process_id,
CreateOrReleasePowerSaveBlocker();
if (observers_.might_have_observers())
- SendUpdate("addPeerConnection", dict);
+ SendUpdate("addPeerConnection", dict->CreateDeepCopy());
if (render_process_id_set_.insert(render_process_id).second) {
RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
@@ -122,10 +146,10 @@ void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
CreateOrReleasePowerSaveBlocker();
if (observers_.might_have_observers()) {
- base::DictionaryValue id;
- id.SetInteger("pid", static_cast<int>(pid));
- id.SetInteger("lid", lid);
- SendUpdate("removePeerConnection", &id);
+ std::unique_ptr<base::DictionaryValue> id(new base::DictionaryValue());
+ id->SetInteger("pid", static_cast<int>(pid));
+ id->SetInteger("lid", lid);
+ SendUpdate("removePeerConnection", std::move(id));
}
break;
}
@@ -163,12 +187,13 @@ void WebRTCInternals::OnUpdatePeerConnection(
log->Append(log_entry);
if (observers_.might_have_observers()) {
- base::DictionaryValue update;
- update.SetInteger("pid", static_cast<int>(pid));
- update.SetInteger("lid", lid);
- update.MergeDictionary(log_entry);
+ std::unique_ptr<base::DictionaryValue> update(
+ new base::DictionaryValue());
+ update->SetInteger("pid", static_cast<int>(pid));
+ update->SetInteger("lid", lid);
+ update->MergeDictionary(log_entry);
- SendUpdate("updatePeerConnection", &update);
+ SendUpdate("updatePeerConnection", std::move(update));
}
return;
}
@@ -179,17 +204,13 @@ void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
if (!observers_.might_have_observers())
return;
- base::DictionaryValue dict;
- dict.SetInteger("pid", static_cast<int>(pid));
- dict.SetInteger("lid", lid);
-
- base::ListValue* list = value.DeepCopy();
- if (!list)
- return;
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("pid", static_cast<int>(pid));
+ dict->SetInteger("lid", lid);
- dict.Set("reports", list);
+ dict->Set("reports", value.CreateDeepCopy());
- SendUpdate("addStats", &dict);
+ SendUpdate("addStats", std::move(dict));
}
void WebRTCInternals::OnGetUserMedia(int rid,
@@ -213,7 +234,7 @@ void WebRTCInternals::OnGetUserMedia(int rid,
get_user_media_requests_.Append(dict);
if (observers_.might_have_observers())
- SendUpdate("addGetUserMedia", dict);
+ SendUpdate("addGetUserMedia", dict->CreateDeepCopy());
if (render_process_id_set_.insert(rid).second) {
RenderProcessHost* host = RenderProcessHost::FromID(rid);
@@ -222,12 +243,12 @@ void WebRTCInternals::OnGetUserMedia(int rid,
}
}
-void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
+void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver* observer) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.AddObserver(observer);
}
-void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
+void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver* observer) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
observers_.RemoveObserver(observer);
@@ -251,8 +272,8 @@ void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
void WebRTCInternals::EnableAudioDebugRecordings(
content::WebContents* web_contents) {
-#if defined(ENABLE_WEBRTC)
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+#if defined(ENABLE_WEBRTC)
#if defined(OS_ANDROID)
EnableAudioDebugRecordingsOnAllRenderProcessHosts();
#else
@@ -273,8 +294,8 @@ void WebRTCInternals::EnableAudioDebugRecordings(
}
void WebRTCInternals::DisableAudioDebugRecordings() {
-#if defined(ENABLE_WEBRTC)
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+#if defined(ENABLE_WEBRTC)
audio_debug_recordings_ = false;
// Tear down the dialog since the user has unchecked the audio debug
@@ -343,21 +364,20 @@ const base::FilePath& WebRTCInternals::GetEventLogRecordingsFilePath() const {
return event_log_recordings_file_path_;
}
-void WebRTCInternals::ResetForTesting() {
+void WebRTCInternals::SendUpdate(const string& command,
+ std::unique_ptr<base::Value> value) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- observers_.Clear();
- peer_connection_data_.Clear();
- CreateOrReleasePowerSaveBlocker();
- get_user_media_requests_.Clear();
- audio_debug_recordings_ = false;
-}
-
-void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
DCHECK(observers_.might_have_observers());
- FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
- observers_,
- OnUpdate(command, value));
+ bool queue_was_empty = pending_updates_.empty();
+ pending_updates_.push(PendingUpdate(command, std::move(value)));
+
+ if (queue_was_empty) {
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebRTCInternals::ProcessPendingUpdates,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(aggregate_updates_ms_));
+ }
}
void WebRTCInternals::RenderProcessHostDestroyed(RenderProcessHost* host) {
@@ -412,10 +432,11 @@ void WebRTCInternals::OnRendererExit(int render_process_id) {
record->GetInteger("lid", &lid);
record->GetInteger("pid", &pid);
- base::DictionaryValue update;
- update.SetInteger("lid", lid);
- update.SetInteger("pid", pid);
- SendUpdate("removePeerConnection", &update);
+ std::unique_ptr<base::DictionaryValue> update(
+ new base::DictionaryValue());
+ update->SetInteger("lid", lid);
+ update->SetInteger("pid", pid);
+ SendUpdate("removePeerConnection", std::move(update));
}
peer_connection_data_.Remove(i, NULL);
}
@@ -439,9 +460,9 @@ void WebRTCInternals::OnRendererExit(int render_process_id) {
}
if (found_any && observers_.might_have_observers()) {
- base::DictionaryValue update;
- update.SetInteger("rid", render_process_id);
- SendUpdate("removeGetUserMediaForRenderer", &update);
+ std::unique_ptr<base::DictionaryValue> update(new base::DictionaryValue());
+ update->SetInteger("rid", render_process_id);
+ SendUpdate("removeGetUserMediaForRenderer", std::move(update));
}
}
@@ -487,4 +508,15 @@ void WebRTCInternals::CreateOrReleasePowerSaveBlocker() {
}
}
+void WebRTCInternals::ProcessPendingUpdates() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ while (!pending_updates_.empty()) {
+ const auto& update = pending_updates_.front();
+ FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
+ observers_,
+ OnUpdate(update.command(), update.value()));
+ pending_updates_.pop();
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/webrtc_internals.h b/chromium/content/browser/media/webrtc/webrtc_internals.h
index f6470008dd4..e319313df2d 100644
--- a/chromium/content/browser/media/webrtc_internals.h
+++ b/chromium/content/browser/media/webrtc/webrtc_internals.h
@@ -2,15 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
+
+#include <memory>
+#include <queue>
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/process/process.h"
+#include "base/threading/thread_checker.h"
#include "base/values.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_process_host_observer.h"
@@ -81,8 +85,8 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
const std::string& video_constraints);
// Methods for adding or removing WebRTCInternalsUIObserver.
- void AddObserver(WebRTCInternalsUIObserver *observer);
- void RemoveObserver(WebRTCInternalsUIObserver *observer);
+ void AddObserver(WebRTCInternalsUIObserver* observer);
+ void RemoveObserver(WebRTCInternalsUIObserver* observer);
// Sends all update data to |observer|.
void UpdateObserver(WebRTCInternalsUIObserver* observer);
@@ -100,7 +104,14 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
bool IsEventLogRecordingsEnabled() const;
const base::FilePath& GetEventLogRecordingsFilePath() const;
- void ResetForTesting();
+ protected:
+ // Constructor/Destructor are protected to allow tests to derive from the
+ // class and do per-instance testing without having to use the global
+ // instance.
+ // The default ctor sets |aggregate_updates_ms| to 500ms.
+ WebRTCInternals();
+ explicit WebRTCInternals(int aggregate_updates_ms);
+ ~WebRTCInternals() override;
private:
friend struct base::DefaultLazyInstanceTraits<WebRTCInternals>;
@@ -113,10 +124,8 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
FRIEND_TEST_ALL_PREFIXES(WebRtcInternalsTest,
AudioDebugRecordingsFileSelectionCanceled);
- WebRTCInternals();
- ~WebRTCInternals() override;
-
- void SendUpdate(const std::string& command, base::Value* value);
+ void SendUpdate(const std::string& command,
+ std::unique_ptr<base::Value> value);
// RenderProcessHostObserver implementation.
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
@@ -145,6 +154,12 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
// application for power-saving.
void CreateOrReleasePowerSaveBlocker();
+ // Called on a timer to deliver updates to javascript.
+ // We throttle and bulk together updates to avoid DOS like scenarios where
+ // a page uses a lot of peerconnection instances with many event
+ // notifications.
+ void ProcessPendingUpdates();
+
base::ObserverList<WebRTCInternalsUIObserver> observers_;
// |peer_connection_data_| is a list containing all the PeerConnection
@@ -187,12 +202,43 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
// While |peer_connection_data_| is non-empty, hold an instance of
// PowerSaveBlocker. This prevents the application from being suspended while
// remoting.
- scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+ std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
// Set of render process hosts that |this| is registered as an observer on.
base::hash_set<int> render_process_id_set_;
+
+ // Used to bulk up updates that we send to javascript.
+ // The class owns the value/dictionary and command name of an update.
+ // For each update, a PendingUpdate is stored in the |pending_updates_| queue
+ // and deleted as soon as the update has been delivered.
+ // The class is moveble and not copyable to avoid copying while still allowing
+ // us to use an stl container without needing scoped_ptr or similar.
+ // The class is single threaded, so all operations must occur on the same
+ // thread.
+ class PendingUpdate {
+ public:
+ PendingUpdate(const std::string& command,
+ std::unique_ptr<base::Value> value);
+ PendingUpdate(PendingUpdate&& other);
+ ~PendingUpdate();
+
+ const std::string& command() const;
+ const base::Value* value() const;
+
+ private:
+ base::ThreadChecker thread_checker_;
+ std::string command_;
+ std::unique_ptr<base::Value> value_;
+ DISALLOW_COPY_AND_ASSIGN(PendingUpdate);
+ };
+
+ std::queue<PendingUpdate> pending_updates_;
+ const int aggregate_updates_ms_;
+
+ // Weak factory for this object that we use for bulking up updates.
+ base::WeakPtrFactory<WebRTCInternals> weak_factory_;
};
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
diff --git a/chromium/content/browser/media/webrtc_internals_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_internals_browsertest.cc
index a266d03a7f5..854bf09c9fa 100644
--- a/chromium/content/browser/media/webrtc_internals_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_browsertest.cc
@@ -236,7 +236,7 @@ class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
"window.domAutomationController.send("
"JSON.stringify(userMediaRequests));",
&json_requests));
- scoped_ptr<base::Value> value_requests =
+ std::unique_ptr<base::Value> value_requests =
base::JSONReader::Read(json_requests);
EXPECT_EQ(base::Value::TYPE_LIST, value_requests->GetType());
@@ -786,7 +786,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcInternalsBrowserTest, CreatePageDump) {
"window.domAutomationController.send("
"JSON.stringify(peerConnectionDataStore));",
&dump_json));
- scoped_ptr<base::Value> dump = base::JSONReader::Read(dump_json);
+ std::unique_ptr<base::Value> dump = base::JSONReader::Read(dump_json);
VerifyPageDumpStructure(dump.get(),
2 /*peer_connection_number*/,
2 /*update_number*/,
diff --git a/chromium/content/browser/media/webrtc_internals_message_handler.cc b/chromium/content/browser/media/webrtc/webrtc_internals_message_handler.cc
index 33a69effdc9..eaaea95a73d 100644
--- a/chromium/content/browser/media/webrtc_internals_message_handler.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_message_handler.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/webrtc_internals_message_handler.h"
+#include "content/browser/media/webrtc/webrtc_internals_message_handler.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/common/media/peer_connection_tracker_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
diff --git a/chromium/content/browser/media/webrtc_internals_message_handler.h b/chromium/content/browser/media/webrtc/webrtc_internals_message_handler.h
index 1b42f219a1d..82e242eea9d 100644
--- a/chromium/content/browser/media/webrtc_internals_message_handler.h
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_message_handler.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
#include "content/public/browser/web_ui_message_handler.h"
namespace base {
@@ -49,4 +49,4 @@ class WebRTCInternalsMessageHandler : public WebUIMessageHandler,
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
diff --git a/chromium/content/browser/media/webrtc_internals_ui.cc b/chromium/content/browser/media/webrtc/webrtc_internals_ui.cc
index 67970305741..c08c9f2fdfa 100644
--- a/chromium/content/browser/media/webrtc_internals_ui.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_ui.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/media/webrtc_internals_ui.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui.h"
-#include "content/browser/media/webrtc_internals_message_handler.h"
+#include "content/browser/media/webrtc/webrtc_internals_message_handler.h"
#include "content/grit/content_resources.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
diff --git a/chromium/content/browser/media/webrtc_internals_ui.h b/chromium/content/browser/media/webrtc/webrtc_internals_ui.h
index 541af020e49..2347ff9f6a3 100644
--- a/chromium/content/browser/media/webrtc_internals_ui.h
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_ui.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
#include "base/macros.h"
#include "content/public/browser/web_ui_controller.h"
@@ -21,4 +21,4 @@ class WebRTCInternalsUI : public WebUIController {
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
diff --git a/chromium/content/browser/media/webrtc_internals_ui_observer.h b/chromium/content/browser/media/webrtc/webrtc_internals_ui_observer.h
index 31082b6181f..e7dfed1f1d9 100644
--- a/chromium/content/browser/media/webrtc_internals_ui_observer.h
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_ui_observer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
#include <string>
@@ -26,4 +26,4 @@ class WebRTCInternalsUIObserver {
} // namespace content
-#endif // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#endif // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
diff --git a/chromium/content/browser/media/webrtc_internals_unittest.cc b/chromium/content/browser/media/webrtc/webrtc_internals_unittest.cc
index 197107fadad..f3b048f5dff 100644
--- a/chromium/content/browser/media/webrtc_internals_unittest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_internals_unittest.cc
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/memory/scoped_ptr.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
+
+#include <memory>
+
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/values.h"
-#include "content/browser/media/webrtc_internals.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,13 +23,10 @@ static const std::string kUrl = "u";
class MockWebRtcInternalsProxy : public WebRTCInternalsUIObserver {
public:
- void OnUpdate(const std::string& command, const base::Value* value) override {
- command_ = command;
- if (value)
- value_.reset(value->DeepCopy());
- }
+ MockWebRtcInternalsProxy() : loop_(nullptr) {}
+ explicit MockWebRtcInternalsProxy(base::RunLoop* loop) : loop_(loop) {}
- std::string command() {
+ const std::string& command() const {
return command_;
}
@@ -35,15 +35,32 @@ class MockWebRtcInternalsProxy : public WebRTCInternalsUIObserver {
}
private:
- std::string command_;
- scoped_ptr<base::Value> value_;
+ void OnUpdate(const std::string& command, const base::Value* value) override {
+ command_ = command;
+ value_.reset(value ? value->DeepCopy() : nullptr);
+ if (loop_)
+ loop_->Quit();
+ }
+
+ std::string command_;
+ std::unique_ptr<base::Value> value_;
+ base::RunLoop* loop_;
+};
+
+// Derived class for testing only. Allows the tests to have their own instance
+// for testing and control the period for which WebRTCInternals will bulk up
+// updates (changes down from 500ms to 1ms).
+class WebRTCInternalsForTest : public NON_EXPORTED_BASE(WebRTCInternals) {
+ public:
+ WebRTCInternalsForTest() : WebRTCInternals(1) {}
+ ~WebRTCInternalsForTest() override {}
};
+} // namespace
+
class WebRtcInternalsTest : public testing::Test {
public:
- WebRtcInternalsTest() : io_thread_(BrowserThread::UI, &io_loop_) {
- WebRTCInternals::GetInstance()->ResetForTesting();
- }
+ WebRtcInternalsTest() : io_thread_(BrowserThread::UI, &io_loop_) {}
protected:
void VerifyString(const base::DictionaryValue* dict,
@@ -90,30 +107,41 @@ class WebRtcInternalsTest : public testing::Test {
TestBrowserThread io_thread_;
};
-} // namespace
-
TEST_F(WebRtcInternalsTest, AddRemoveObserver) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(
- new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.AddObserver(&observer);
+
+ webrtc_internals.RemoveObserver(&observer);
+ // The observer should not get notified of this activity.
+ webrtc_internals.OnAddPeerConnection(
0, 3, 4, kUrl, kRtcConfiguration, kContraints);
- EXPECT_EQ("", observer->command());
- WebRTCInternals::GetInstance()->OnRemovePeerConnection(3, 4);
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(5));
+ loop.Run();
+
+ EXPECT_EQ("", observer.command());
+
+ webrtc_internals.OnRemovePeerConnection(3, 4);
}
TEST_F(WebRtcInternalsTest, SendAddPeerConnectionUpdate) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(
- new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
- EXPECT_EQ("addPeerConnection", observer->command());
+
+ loop.Run();
+
+ ASSERT_EQ("addPeerConnection", observer.command());
base::DictionaryValue* dict = NULL;
- EXPECT_TRUE(observer->value()->GetAsDictionary(&dict));
+ EXPECT_TRUE(observer.value()->GetAsDictionary(&dict));
VerifyInt(dict, "pid", 1);
VerifyInt(dict, "lid", 2);
@@ -121,44 +149,51 @@ TEST_F(WebRtcInternalsTest, SendAddPeerConnectionUpdate) {
VerifyString(dict, "rtcConfiguration", kRtcConfiguration);
VerifyString(dict, "constraints", kContraints);
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
- WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
+ webrtc_internals.RemoveObserver(&observer);
+ webrtc_internals.OnRemovePeerConnection(1, 2);
}
TEST_F(WebRtcInternalsTest, SendRemovePeerConnectionUpdate) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(
- new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
- WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
- EXPECT_EQ("removePeerConnection", observer->command());
+ webrtc_internals.OnRemovePeerConnection(1, 2);
+
+ loop.Run();
+
+ ASSERT_EQ("removePeerConnection", observer.command());
base::DictionaryValue* dict = NULL;
- EXPECT_TRUE(observer->value()->GetAsDictionary(&dict));
+ EXPECT_TRUE(observer.value()->GetAsDictionary(&dict));
VerifyInt(dict, "pid", 1);
VerifyInt(dict, "lid", 2);
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
+ webrtc_internals.RemoveObserver(&observer);
}
TEST_F(WebRtcInternalsTest, SendUpdatePeerConnectionUpdate) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(
- new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.OnAddPeerConnection(
0, 1, 2, kUrl, kRtcConfiguration, kContraints);
const std::string update_type = "fakeType";
const std::string update_value = "fakeValue";
- WebRTCInternals::GetInstance()->OnUpdatePeerConnection(
+ webrtc_internals.OnUpdatePeerConnection(
1, 2, update_type, update_value);
- EXPECT_EQ("updatePeerConnection", observer->command());
+ loop.Run();
+
+ ASSERT_EQ("updatePeerConnection", observer.command());
base::DictionaryValue* dict = NULL;
- EXPECT_TRUE(observer->value()->GetAsDictionary(&dict));
+ EXPECT_TRUE(observer.value()->GetAsDictionary(&dict));
VerifyInt(dict, "pid", 1);
VerifyInt(dict, "lid", 2);
@@ -169,28 +204,32 @@ TEST_F(WebRtcInternalsTest, SendUpdatePeerConnectionUpdate) {
EXPECT_TRUE(dict->GetString("time", &time));
EXPECT_FALSE(time.empty());
- WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
+ webrtc_internals.OnRemovePeerConnection(1, 2);
+ webrtc_internals.RemoveObserver(&observer);
}
TEST_F(WebRtcInternalsTest, AddGetUserMedia) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
// Add one observer before "getUserMedia".
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
+ webrtc_internals.AddObserver(&observer);
const int rid = 1;
const int pid = 2;
const std::string audio_constraint = "aaa";
const std::string video_constraint = "vvv";
- WebRTCInternals::GetInstance()->OnGetUserMedia(
+ webrtc_internals.OnGetUserMedia(
rid, pid, kUrl, true, true, audio_constraint, video_constraint);
- EXPECT_EQ("addGetUserMedia", observer->command());
+ loop.Run();
+
+ ASSERT_EQ("addGetUserMedia", observer.command());
VerifyGetUserMediaData(
- observer->value(), rid, pid, kUrl, audio_constraint, video_constraint);
+ observer.value(), rid, pid, kUrl, audio_constraint, video_constraint);
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
+ webrtc_internals.RemoveObserver(&observer);
}
TEST_F(WebRtcInternalsTest, SendAllUpdateWithGetUserMedia) {
@@ -198,19 +237,20 @@ TEST_F(WebRtcInternalsTest, SendAllUpdateWithGetUserMedia) {
const int pid = 2;
const std::string audio_constraint = "aaa";
const std::string video_constraint = "vvv";
- WebRTCInternals::GetInstance()->OnGetUserMedia(
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.OnGetUserMedia(
rid, pid, kUrl, true, true, audio_constraint, video_constraint);
- scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
+ MockWebRtcInternalsProxy observer;
// Add one observer after "getUserMedia".
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->UpdateObserver(observer.get());
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.UpdateObserver(&observer);
- EXPECT_EQ("addGetUserMedia", observer->command());
+ EXPECT_EQ("addGetUserMedia", observer.command());
VerifyGetUserMediaData(
- observer->value(), rid, pid, kUrl, audio_constraint, video_constraint);
+ observer.value(), rid, pid, kUrl, audio_constraint, video_constraint);
- WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
+ webrtc_internals.RemoveObserver(&observer);
}
TEST_F(WebRtcInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
@@ -218,20 +258,23 @@ TEST_F(WebRtcInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
const std::string update_type = "fakeType";
const std::string update_value = "fakeValue";
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ WebRTCInternalsForTest webrtc_internals;
+
+ webrtc_internals.OnAddPeerConnection(
rid, pid, lid, kUrl, kRtcConfiguration, kContraints);
- WebRTCInternals::GetInstance()->OnUpdatePeerConnection(
+ webrtc_internals.OnUpdatePeerConnection(
pid, lid, update_type, update_value);
- scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
+ MockWebRtcInternalsProxy observer;
+ webrtc_internals.AddObserver(&observer);
- WebRTCInternals::GetInstance()->UpdateObserver(observer.get());
+ webrtc_internals.UpdateObserver(&observer);
- EXPECT_EQ("updateAllPeerConnections", observer->command());
+ EXPECT_EQ("updateAllPeerConnections", observer.command());
+ ASSERT_TRUE(observer.value());
base::ListValue* list = NULL;
- EXPECT_TRUE(observer->value()->GetAsList(&list));
+ EXPECT_TRUE(observer.value()->GetAsList(&list));
EXPECT_EQ(1U, list->GetSize());
base::DictionaryValue* dict = NULL;
@@ -258,19 +301,25 @@ TEST_F(WebRtcInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
TEST_F(WebRtcInternalsTest, OnAddStats) {
const int rid = 0, pid = 1, lid = 2;
- scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->OnAddPeerConnection(
+ base::RunLoop loop;
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.OnAddPeerConnection(
rid, pid, lid, kUrl, kRtcConfiguration, kContraints);
base::ListValue list;
list.AppendString("xxx");
list.AppendString("yyy");
- WebRTCInternals::GetInstance()->OnAddStats(pid, lid, list);
+ webrtc_internals.OnAddStats(pid, lid, list);
+
+ loop.Run();
+
+ EXPECT_EQ("addStats", observer.command());
+ ASSERT_TRUE(observer.value());
- EXPECT_EQ("addStats", observer->command());
base::DictionaryValue* dict = NULL;
- EXPECT_TRUE(observer->value()->GetAsDictionary(&dict));
+ EXPECT_TRUE(observer.value()->GetAsDictionary(&dict));
VerifyInt(dict, "pid", pid);
VerifyInt(dict, "lid", lid);
@@ -278,11 +327,18 @@ TEST_F(WebRtcInternalsTest, OnAddStats) {
}
TEST_F(WebRtcInternalsTest, AudioDebugRecordingsFileSelectionCanceled) {
- scoped_ptr<MockWebRtcInternalsProxy> observer(new MockWebRtcInternalsProxy());
- WebRTCInternals::GetInstance()->AddObserver(observer.get());
- WebRTCInternals::GetInstance()->FileSelectionCanceled(NULL);
- EXPECT_EQ("audioDebugRecordingsFileSelectionCancelled", observer->command());
- EXPECT_EQ(NULL, observer->value());
+ base::RunLoop loop;
+
+ MockWebRtcInternalsProxy observer(&loop);
+ WebRTCInternalsForTest webrtc_internals;
+
+ webrtc_internals.AddObserver(&observer);
+ webrtc_internals.FileSelectionCanceled(nullptr);
+
+ loop.Run();
+
+ EXPECT_EQ("audioDebugRecordingsFileSelectionCancelled", observer.command());
+ EXPECT_EQ(nullptr, observer.value());
}
} // namespace content
diff --git a/chromium/content/browser/media/webrtc_ip_permissions_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_ip_permissions_browsertest.cc
index 9b05019e40f..9b05019e40f 100644
--- a/chromium/content/browser/media/webrtc_ip_permissions_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_ip_permissions_browsertest.cc
diff --git a/chromium/content/browser/media/webrtc_media_recorder_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc
index 00f8454dee2..00f8454dee2 100644
--- a/chromium/content/browser/media/webrtc_media_recorder_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc
diff --git a/chromium/content/browser/media/webrtc_webcam_browsertest.cc b/chromium/content/browser/media/webrtc/webrtc_webcam_browsertest.cc
index 32eeb111532..32eeb111532 100644
--- a/chromium/content/browser/media/webrtc_webcam_browsertest.cc
+++ b/chromium/content/browser/media/webrtc/webrtc_webcam_browsertest.cc
diff --git a/chromium/content/browser/memory/memory_message_filter.cc b/chromium/content/browser/memory/memory_message_filter.cc
index 110f8396aae..9ab2adbd18c 100644
--- a/chromium/content/browser/memory/memory_message_filter.cc
+++ b/chromium/content/browser/memory/memory_message_filter.cc
@@ -4,7 +4,7 @@
#include "content/browser/memory/memory_message_filter.h"
-#include "content/browser/memory/memory_pressure_controller.h"
+#include "content/browser/memory/memory_pressure_controller_impl.h"
#include "content/common/memory_messages.h"
namespace content {
@@ -27,11 +27,12 @@ MemoryMessageFilter::MemoryMessageFilter(
MemoryMessageFilter::~MemoryMessageFilter() {}
void MemoryMessageFilter::OnFilterAdded(IPC::Sender* sender) {
- MemoryPressureController::GetInstance()->OnMemoryMessageFilterAdded(this);
+ MemoryPressureControllerImpl::GetInstance()->OnMemoryMessageFilterAdded(this);
}
void MemoryMessageFilter::OnChannelClosing() {
- MemoryPressureController::GetInstance()->OnMemoryMessageFilterRemoved(this);
+ MemoryPressureControllerImpl::GetInstance()
+ ->OnMemoryMessageFilterRemoved(this);
}
bool MemoryMessageFilter::OnMessageReceived(const IPC::Message& message) {
diff --git a/chromium/content/browser/memory/memory_message_filter.h b/chromium/content/browser/memory/memory_message_filter.h
index ad13662477e..5241b9cc556 100644
--- a/chromium/content/browser/memory/memory_message_filter.h
+++ b/chromium/content/browser/memory/memory_message_filter.h
@@ -36,7 +36,7 @@ class CONTENT_EXPORT MemoryMessageFilter : public BrowserMessageFilter {
base::MemoryPressureListener::MemoryPressureLevel level);
protected:
- friend class MemoryPressureController;
+ friend class MemoryPressureControllerImpl;
~MemoryMessageFilter() override;
@@ -46,7 +46,7 @@ class CONTENT_EXPORT MemoryMessageFilter : public BrowserMessageFilter {
private:
// The untyped process host and ProcessType associated with this filter
// instance. The process host is stored as untyped because it is only used as
- // a key in MemoryPressureController; at no point is it ever deferenced to
+ // a key in MemoryPressureControllerImpl; at no point is it ever deferenced to
// invoke any members on a process host.
const void* process_host_;
ProcessType process_type_;
diff --git a/chromium/content/browser/memory/memory_pressure_controller.cc b/chromium/content/browser/memory/memory_pressure_controller_impl.cc
index 11cdbe53714..1026783e468 100644
--- a/chromium/content/browser/memory/memory_pressure_controller.cc
+++ b/chromium/content/browser/memory/memory_pressure_controller_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 "content/browser/memory/memory_pressure_controller.h"
+#include "content/browser/memory/memory_pressure_controller_impl.h"
#include "base/bind.h"
#include "content/browser/memory/memory_message_filter.h"
@@ -10,11 +10,11 @@
namespace content {
-MemoryPressureController::MemoryPressureController() {}
+MemoryPressureControllerImpl::MemoryPressureControllerImpl() {}
-MemoryPressureController::~MemoryPressureController() {}
+MemoryPressureControllerImpl::~MemoryPressureControllerImpl() {}
-void MemoryPressureController::OnMemoryMessageFilterAdded(
+void MemoryPressureControllerImpl::OnMemoryMessageFilterAdded(
MemoryMessageFilter* filter) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -32,7 +32,7 @@ void MemoryPressureController::OnMemoryMessageFilterAdded(
filter->SendSetPressureNotificationsSuppressed(true);
}
-void MemoryPressureController::OnMemoryMessageFilterRemoved(
+void MemoryPressureControllerImpl::OnMemoryMessageFilterRemoved(
MemoryMessageFilter* filter) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -45,20 +45,21 @@ void MemoryPressureController::OnMemoryMessageFilterRemoved(
}
// static
-MemoryPressureController* MemoryPressureController::GetInstance() {
+MemoryPressureControllerImpl* MemoryPressureControllerImpl::GetInstance() {
return base::Singleton<
- MemoryPressureController,
- base::LeakySingletonTraits<MemoryPressureController>>::get();
+ MemoryPressureControllerImpl,
+ base::LeakySingletonTraits<MemoryPressureControllerImpl>>::get();
}
-void MemoryPressureController::SetPressureNotificationsSuppressedInAllProcesses(
+void
+MemoryPressureControllerImpl::SetPressureNotificationsSuppressedInAllProcesses(
bool suppressed) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
// Note that passing base::Unretained(this) is safe here because the
// controller is a leaky singleton.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&MemoryPressureController::
+ base::Bind(&MemoryPressureControllerImpl::
SetPressureNotificationsSuppressedInAllProcesses,
base::Unretained(this), suppressed));
return;
@@ -72,7 +73,7 @@ void MemoryPressureController::SetPressureNotificationsSuppressedInAllProcesses(
filter_pair.second->SendSetPressureNotificationsSuppressed(suppressed);
}
-void MemoryPressureController::SimulatePressureNotificationInAllProcesses(
+void MemoryPressureControllerImpl::SimulatePressureNotificationInAllProcesses(
base::MemoryPressureListener::MemoryPressureLevel level) {
DCHECK_NE(level, base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
@@ -81,7 +82,7 @@ void MemoryPressureController::SimulatePressureNotificationInAllProcesses(
// controller is a leaky singleton.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&MemoryPressureController::
+ base::Bind(&MemoryPressureControllerImpl::
SimulatePressureNotificationInAllProcesses,
base::Unretained(this), level));
return;
@@ -95,19 +96,19 @@ void MemoryPressureController::SimulatePressureNotificationInAllProcesses(
filter_pair.second->SendSimulatePressureNotification(level);
}
-void MemoryPressureController::SendPressureNotification(
+void MemoryPressureControllerImpl::SendPressureNotification(
const BrowserChildProcessHost* child_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
SendPressureNotificationImpl(child_process_host, level);
}
-void MemoryPressureController::SendPressureNotification(
+void MemoryPressureControllerImpl::SendPressureNotification(
const RenderProcessHost* render_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
SendPressureNotificationImpl(render_process_host, level);
}
-void MemoryPressureController::SendPressureNotificationImpl(
+void MemoryPressureControllerImpl::SendPressureNotificationImpl(
const void* child_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
@@ -117,7 +118,7 @@ void MemoryPressureController::SendPressureNotificationImpl(
// a map; at no point is it dereferenced.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&MemoryPressureController::SendPressureNotificationImpl,
+ base::Bind(&MemoryPressureControllerImpl::SendPressureNotificationImpl,
base::Unretained(this), child_process_host, level));
return;
}
diff --git a/chromium/content/browser/memory/memory_pressure_controller.h b/chromium/content/browser/memory/memory_pressure_controller_impl.h
index f81540957d7..95d58d250d6 100644
--- a/chromium/content/browser/memory/memory_pressure_controller.h
+++ b/chromium/content/browser/memory/memory_pressure_controller_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_H_
-#define CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_H_
+#ifndef CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_IMPL_H_
+#define CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_IMPL_H_
#include <map>
@@ -19,33 +19,55 @@ class BrowserChildProcessHost;
class MemoryMessageFilter;
class RenderProcessHost;
-class CONTENT_EXPORT MemoryPressureController {
+// Controller for memory pressure IPC messages. Each child process owns and
+// registers a MemoryMessageFilter, which can be used to both suppress and
+// simulate memory pressure messages across processes. This controller
+// coordinates suppressing and simulation of messages, as well as allows for
+// messages to be forwarded to individual processes. This allows the browser
+// process to control what memory pressure messages are seen in child processes.
+// For more details see content/browser/memory/memory_message_filter.h and
+// content/child/memory/child_memory_message_filter.h.
+class CONTENT_EXPORT MemoryPressureControllerImpl {
public:
+ // This method can be called from any thread.
+ static MemoryPressureControllerImpl* GetInstance();
+
// These methods must be called on the IO thread.
void OnMemoryMessageFilterAdded(MemoryMessageFilter* filter);
void OnMemoryMessageFilterRemoved(MemoryMessageFilter* filter);
// These methods can be called from any thread.
+
+ // Suppresses all memory pressure messages from passing through all attached
+ // MemoryMessageFilters. Any messages sent through a "suppressed" filter will
+ // be ignored on the receiving end.
void SetPressureNotificationsSuppressedInAllProcesses(bool suppressed);
+
+ // Simulates memory pressure in all processes by invoking
+ // SimulatePressureNotification on all attached MemoryMessageFilters. These
+ // messages will be received even if suppression is enabled.
void SimulatePressureNotificationInAllProcesses(
base::MemoryPressureListener::MemoryPressureLevel level);
+
+ // Sends a memory pressure notification to the specified browser child process
+ // via its attached MemoryMessageFilter.
void SendPressureNotification(
const BrowserChildProcessHost* child_process_host,
base::MemoryPressureListener::MemoryPressureLevel level);
+
+ // Sends a memory pressure notification to the specified renderer process via
+ // its attached MemoryMessageFilter.
void SendPressureNotification(
const RenderProcessHost* render_process_host,
base::MemoryPressureListener::MemoryPressureLevel level);
- // This method can be called from any thread.
- static MemoryPressureController* GetInstance();
-
protected:
- virtual ~MemoryPressureController();
+ virtual ~MemoryPressureControllerImpl();
private:
- friend struct base::DefaultSingletonTraits<MemoryPressureController>;
+ friend struct base::DefaultSingletonTraits<MemoryPressureControllerImpl>;
- MemoryPressureController();
+ MemoryPressureControllerImpl();
// Implementation of the various SendPressureNotification methods.
void SendPressureNotificationImpl(
@@ -58,9 +80,9 @@ class CONTENT_EXPORT MemoryPressureController {
MemoryMessageFilterMap;
MemoryMessageFilterMap memory_message_filters_;
- DISALLOW_COPY_AND_ASSIGN(MemoryPressureController);
+ DISALLOW_COPY_AND_ASSIGN(MemoryPressureControllerImpl);
};
} // namespace content
-#endif // CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_H_
+#endif // CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_IMPL_H_
diff --git a/chromium/content/browser/memory/memory_pressure_controller_browsertest.cc b/chromium/content/browser/memory/memory_pressure_controller_impl_browsertest.cc
index 5b08a665373..d688fd16a47 100644
--- a/chromium/content/browser/memory/memory_pressure_controller_browsertest.cc
+++ b/chromium/content/browser/memory/memory_pressure_controller_impl_browsertest.cc
@@ -5,7 +5,7 @@
#include "base/bind.h"
#include "base/memory/memory_pressure_listener.h"
#include "content/browser/memory/memory_message_filter.h"
-#include "content/browser/memory/memory_pressure_controller.h"
+#include "content/browser/memory/memory_pressure_controller_impl.h"
#include "content/common/memory_messages.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
@@ -89,7 +89,7 @@ class MemoryMessageFilterForTesting : public MemoryMessageFilter {
~MemoryMessageFilterForTesting() override {}
};
-class MemoryPressureControllerBrowserTest : public ContentBrowserTest {
+class MemoryPressureControllerImplBrowserTest : public ContentBrowserTest {
public:
MOCK_METHOD1(OnMemoryPressure,
void(base::MemoryPressureListener::MemoryPressureLevel level));
@@ -97,14 +97,14 @@ class MemoryPressureControllerBrowserTest : public ContentBrowserTest {
protected:
void SetPressureNotificationsSuppressedInAllProcessesAndWait(
bool suppressed) {
- MemoryPressureController::GetInstance()
+ MemoryPressureControllerImpl::GetInstance()
->SetPressureNotificationsSuppressedInAllProcesses(suppressed);
RunAllPendingInMessageLoop(BrowserThread::IO);
}
void SimulatePressureNotificationInAllProcessesAndWait(
base::MemoryPressureListener::MemoryPressureLevel level) {
- MemoryPressureController::GetInstance()
+ MemoryPressureControllerImpl::GetInstance()
->SimulatePressureNotificationInAllProcesses(level);
RunAllPendingInMessageLoop(BrowserThread::IO);
}
@@ -112,7 +112,7 @@ class MemoryPressureControllerBrowserTest : public ContentBrowserTest {
void SendPressureNotificationAndWait(
const void* fake_process_host,
base::MemoryPressureListener::MemoryPressureLevel level) {
- MemoryPressureController::GetInstance()->SendPressureNotification(
+ MemoryPressureControllerImpl::GetInstance()->SendPressureNotification(
reinterpret_cast<const RenderProcessHost*>(fake_process_host), level);
RunAllPendingInMessageLoop(BrowserThread::IO);
}
@@ -123,7 +123,7 @@ const auto MEMORY_PRESSURE_LEVEL_MODERATE =
const auto MEMORY_PRESSURE_LEVEL_CRITICAL =
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
-IN_PROC_BROWSER_TEST_F(MemoryPressureControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(MemoryPressureControllerImplBrowserTest,
SetPressureNotificationsSuppressedInAllProcesses) {
scoped_refptr<MemoryMessageFilterForTesting> filter1(
new MemoryMessageFilterForTesting);
@@ -212,13 +212,13 @@ IN_PROC_BROWSER_TEST_F(MemoryPressureControllerBrowserTest,
testing::Mock::VerifyAndClearExpectations(this);
}
-IN_PROC_BROWSER_TEST_F(MemoryPressureControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(MemoryPressureControllerImplBrowserTest,
SimulatePressureNotificationInAllProcesses) {
scoped_refptr<MemoryMessageFilterForTesting> filter(
new MemoryMessageFilterForTesting);
scoped_ptr<base::MemoryPressureListener> listener(
new base::MemoryPressureListener(
- base::Bind(&MemoryPressureControllerBrowserTest::OnMemoryPressure,
+ base::Bind(&MemoryPressureControllerImplBrowserTest::OnMemoryPressure,
base::Unretained(this))));
NavigateToURL(shell(), GetTestUrl("", "title.html"));
diff --git a/chromium/content/browser/message_port_service.cc b/chromium/content/browser/message_port_service.cc
index 21fc76d40bc..5ced952a457 100644
--- a/chromium/content/browser/message_port_service.cc
+++ b/chromium/content/browser/message_port_service.cc
@@ -198,10 +198,6 @@ void MessagePortService::PostMessageTo(
}
entangled_port.queued_messages.push_back(
std::make_pair(message, sent_message_ports));
-
- if (entangled_port.delegate)
- entangled_port.delegate->MessageWasHeld(entangled_port.route_id);
-
return;
}
@@ -295,6 +291,13 @@ void MessagePortService::HoldMessages(int message_port_id) {
message_ports_[message_port_id].hold_messages_for_destination = true;
}
+bool MessagePortService::AreMessagesHeld(int message_port_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!message_ports_.count(message_port_id))
+ return false;
+ return message_ports_[message_port_id].hold_messages_for_destination;
+}
+
void MessagePortService::ClosePort(int message_port_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!message_ports_.count(message_port_id)) {
diff --git a/chromium/content/browser/message_port_service.h b/chromium/content/browser/message_port_service.h
index c3aeadb50a3..b46a7fa36b1 100644
--- a/chromium/content/browser/message_port_service.h
+++ b/chromium/content/browser/message_port_service.h
@@ -67,6 +67,9 @@ class CONTENT_EXPORT MessagePortService {
// clean up the port.
void HoldMessages(int message_port_id);
+ // Returns true if messages for a message port are on hold.
+ bool AreMessagesHeld(int message_port_id);
+
// Closes and cleans up the message port.
void ClosePort(int message_port_id);
diff --git a/chromium/content/browser/mojo/OWNERS b/chromium/content/browser/mojo/OWNERS
deleted file mode 100644
index 570120fdbb9..00000000000
--- a/chromium/content/browser/mojo/OWNERS
+++ /dev/null
@@ -1,13 +0,0 @@
-# Changes to the renderer capability filter require a security review to avoid
-# exposing new sandbox escapes and undesirable services.
-per-file renderer_capability_filter.cc=set noparent
-per-file renderer_capability_filter.cc=dcheng@chromium.org
-per-file renderer_capability_filter.cc=inferno@chromium.org
-per-file renderer_capability_filter.cc=jln@chromium.org
-per-file renderer_capability_filter.cc=jschuh@chromium.org
-per-file renderer_capability_filter.cc=kenrb@chromium.org
-per-file renderer_capability_filter.cc=mkwst@chromium.org
-per-file renderer_capability_filter.cc=nasko@chromium.org
-per-file renderer_capability_filter.cc=palmer@chromium.org
-per-file renderer_capability_filter.cc=tsepez@chromium.org
-per-file renderer_capability_filter.cc=wfh@chromium.org
diff --git a/chromium/content/browser/mojo/constants.cc b/chromium/content/browser/mojo/constants.cc
new file mode 100644
index 00000000000..cbb79379eeb
--- /dev/null
+++ b/chromium/content/browser/mojo/constants.cc
@@ -0,0 +1,19 @@
+// 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 "content/browser/mojo/constants.h"
+
+namespace content {
+
+// The default application name the browser identifies as when connecting to
+// the shell. This must match the name in
+// src/content/public/app/mojo/content_browser_manifest.json.
+const char kBrowserMojoApplicationName[] = "exe:content_browser";
+
+// The default application name used to identify render processes when
+// connecting them to the shell. This must match the name in
+// src/content/public/app/mojo/content_renderer_manifest.json.
+const char kRendererMojoApplicationName[] = "exe:content_renderer";
+
+} // namespace content
diff --git a/chromium/content/browser/mojo/constants.h b/chromium/content/browser/mojo/constants.h
new file mode 100644
index 00000000000..ed6120a5c33
--- /dev/null
+++ b/chromium/content/browser/mojo/constants.h
@@ -0,0 +1,15 @@
+// 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 CONTENT_BROWSER_MOJO_CONSTANTS_H_
+#define CONTENT_BROWSER_MOJO_CONSTANTS_H_
+
+namespace content {
+
+extern const char kBrowserMojoApplicationName[];
+extern const char kRendererMojoApplicationName[];
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MOJO_CONSTANTS_H_
diff --git a/chromium/content/browser/mojo/mojo_app_connection_impl.cc b/chromium/content/browser/mojo/mojo_app_connection_impl.cc
index 2f55450eb12..b2941e2a5dc 100644
--- a/chromium/content/browser/mojo/mojo_app_connection_impl.cc
+++ b/chromium/content/browser/mojo/mojo_app_connection_impl.cc
@@ -9,39 +9,41 @@
#include "base/bind.h"
#include "content/browser/mojo/mojo_shell_context.h"
-#include "mojo/shell/capability_filter.h"
namespace content {
const char kBrowserMojoAppUrl[] = "system:content_browser";
namespace {
-void OnGotContentHandlerID(uint32_t content_handler_id) {}
+void OnGotInstanceID(mojo::shell::mojom::ConnectResult result,
+ const std::string& user_id, uint32_t remote_id) {}
} // namespace
// static
scoped_ptr<MojoAppConnection> MojoAppConnection::Create(
- const GURL& url,
- const GURL& requestor_url) {
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name) {
return scoped_ptr<MojoAppConnection>(
- new MojoAppConnectionImpl(url, requestor_url));
+ new MojoAppConnectionImpl(user_id, name, requestor_name));
}
-MojoAppConnectionImpl::MojoAppConnectionImpl(const GURL& url,
- const GURL& requestor_url) {
+MojoAppConnectionImpl::MojoAppConnectionImpl(
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name) {
MojoShellContext::ConnectToApplication(
- url, requestor_url, mojo::GetProxy(&services_),
- mojo::ServiceProviderPtr(), mojo::shell::GetPermissiveCapabilityFilter(),
- base::Bind(&OnGotContentHandlerID));
+ user_id, name, requestor_name, mojo::GetProxy(&interfaces_),
+ mojo::shell::mojom::InterfaceProviderPtr(), base::Bind(&OnGotInstanceID));
}
MojoAppConnectionImpl::~MojoAppConnectionImpl() {
}
-void MojoAppConnectionImpl::ConnectToService(
- const std::string& service_name,
+void MojoAppConnectionImpl::GetInterface(
+ const std::string& interface_name,
mojo::ScopedMessagePipeHandle handle) {
- services_->ConnectToService(service_name, std::move(handle));
+ interfaces_->GetInterface(interface_name, std::move(handle));
}
} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_app_connection_impl.h b/chromium/content/browser/mojo/mojo_app_connection_impl.h
index 3cdfc591818..5ed747b2c5f 100644
--- a/chromium/content/browser/mojo/mojo_app_connection_impl.h
+++ b/chromium/content/browser/mojo/mojo_app_connection_impl.h
@@ -7,24 +7,26 @@
#include "base/macros.h"
#include "content/public/browser/mojo_app_connection.h"
-#include "mojo/shell/public/interfaces/service_provider.mojom.h"
-
-class GURL;
+#include "mojo/shell/public/interfaces/interface_provider.mojom.h"
namespace content {
// Implementation of the app connection mechanism provided to browser code.
class MojoAppConnectionImpl : public MojoAppConnection {
public:
- MojoAppConnectionImpl(const GURL& url, const GURL& requestor_url);
+ // Takes a BrowserContext and derives a mojo userid from it for this
+ // connection.
+ MojoAppConnectionImpl(const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name);
~MojoAppConnectionImpl() override;
private:
// MojoAppConnection:
- void ConnectToService(const std::string& service_name,
- mojo::ScopedMessagePipeHandle handle) override;
+ void GetInterface(const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle) override;
- mojo::ServiceProviderPtr services_;
+ mojo::shell::mojom::InterfaceProviderPtr interfaces_;
DISALLOW_COPY_AND_ASSIGN(MojoAppConnectionImpl);
};
diff --git a/chromium/content/browser/mojo/mojo_application_host.cc b/chromium/content/browser/mojo/mojo_application_host.cc
index 12895d5c353..c1103e15bbb 100644
--- a/chromium/content/browser/mojo/mojo_application_host.cc
+++ b/chromium/content/browser/mojo/mojo_application_host.cc
@@ -10,24 +10,15 @@
#include "content/common/mojo/mojo_messages.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_sender.h"
-#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
namespace content {
namespace {
-base::PlatformFile PlatformFileFromScopedPlatformHandle(
- mojo::embedder::ScopedPlatformHandle handle) {
-#if defined(OS_POSIX)
- return handle.release().fd;
-#elif defined(OS_WIN)
- return handle.release().handle;
-#endif
-}
-
-class ApplicationSetupImpl : public ApplicationSetup {
+class ApplicationSetupImpl : public mojom::ApplicationSetup {
public:
ApplicationSetupImpl(ServiceRegistryImpl* service_registry,
- mojo::InterfaceRequest<ApplicationSetup> request)
+ mojo::InterfaceRequest<mojom::ApplicationSetup> request)
: binding_(this, std::move(request)),
service_registry_(service_registry) {}
@@ -35,25 +26,24 @@ class ApplicationSetupImpl : public ApplicationSetup {
}
private:
- // ApplicationSetup implementation.
- void ExchangeServiceProviders(
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr exposed_services) override {
+ // mojom::ApplicationSetup implementation.
+ void ExchangeInterfaceProviders(
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services) override {
service_registry_->Bind(std::move(services));
service_registry_->BindRemoteServiceProvider(std::move(exposed_services));
}
- mojo::Binding<ApplicationSetup> binding_;
+ mojo::Binding<mojom::ApplicationSetup> binding_;
ServiceRegistryImpl* service_registry_;
};
} // namespace
-MojoApplicationHost::MojoApplicationHost()
- : did_activate_(false) {
+MojoApplicationHost::MojoApplicationHost() : did_activate_(false) {
#if defined(OS_ANDROID)
- service_registry_android_.reset(
- new ServiceRegistryAndroid(&service_registry_));
+ service_registry_android_ =
+ ServiceRegistryAndroid::Create(&service_registry_);
#endif
}
@@ -63,7 +53,7 @@ MojoApplicationHost::~MojoApplicationHost() {
bool MojoApplicationHost::Init() {
DCHECK(!client_handle_.is_valid()) << "Already initialized!";
- mojo::embedder::PlatformChannelPair channel_pair;
+ mojo::edk::PlatformChannelPair channel_pair;
scoped_refptr<base::TaskRunner> io_task_runner;
if (io_task_runner_override_) {
@@ -74,18 +64,13 @@ bool MojoApplicationHost::Init() {
->task_runner();
}
- mojo::ScopedMessagePipeHandle message_pipe = channel_init_.Init(
- PlatformFileFromScopedPlatformHandle(channel_pair.PassServerHandle()),
- io_task_runner);
- if (!message_pipe.is_valid())
- return false;
-
// Forward this to the client once we know its process handle.
client_handle_ = channel_pair.PassClientHandle();
-
+ mojo::ScopedMessagePipeHandle pipe = channel_init_.Init(
+ channel_pair.PassServerHandle().release().handle, io_task_runner);
application_setup_.reset(new ApplicationSetupImpl(
&service_registry_,
- mojo::MakeRequest<ApplicationSetup>(std::move(message_pipe))));
+ mojo::MakeRequest<mojom::ApplicationSetup>(std::move(pipe))));
return true;
}
@@ -94,14 +79,9 @@ void MojoApplicationHost::Activate(IPC::Sender* sender,
DCHECK(!did_activate_);
DCHECK(client_handle_.is_valid());
- base::PlatformFile client_file =
- PlatformFileFromScopedPlatformHandle(std::move(client_handle_));
+ base::PlatformFile client_file = client_handle_.release().handle;
did_activate_ = sender->Send(new MojoMsg_Activate(
- IPC::GetFileHandleForProcess(client_file, process_handle, true)));
-}
-
-void MojoApplicationHost::WillDestroySoon() {
- channel_init_.WillDestroySoon();
+ IPC::GetPlatformFileForTransit(client_file, true)));
}
void MojoApplicationHost::OverrideIOTaskRunnerForTest(
@@ -109,4 +89,5 @@ void MojoApplicationHost::OverrideIOTaskRunnerForTest(
io_task_runner_override_ = io_task_runner;
}
+
} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_application_host.h b/chromium/content/browser/mojo/mojo_application_host.h
index 0ed8ec917ba..3f3387accea 100644
--- a/chromium/content/browser/mojo/mojo_application_host.h
+++ b/chromium/content/browser/mojo/mojo_application_host.h
@@ -12,10 +12,11 @@
#include "content/common/application_setup.mojom.h"
#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/service_registry_impl.h"
-#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/public/cpp/system/message_pipe.h"
#if defined(OS_ANDROID)
-#include "content/browser/mojo/service_registry_android.h"
+#include "content/public/browser/android/service_registry_android.h"
#endif
namespace IPC {
@@ -40,8 +41,6 @@ class CONTENT_EXPORT MojoApplicationHost {
bool Init();
void Activate(IPC::Sender* sender, base::ProcessHandle process_handle);
- void WillDestroySoon();
-
ServiceRegistry* service_registry() { return &service_registry_; }
#if defined(OS_ANDROID)
@@ -55,11 +54,11 @@ class CONTENT_EXPORT MojoApplicationHost {
private:
ChannelInit channel_init_;
- mojo::embedder::ScopedPlatformHandle client_handle_;
+ mojo::edk::ScopedPlatformHandle client_handle_;
bool did_activate_;
- scoped_ptr<ApplicationSetup> application_setup_;
+ scoped_ptr<mojom::ApplicationSetup> application_setup_;
ServiceRegistryImpl service_registry_;
scoped_refptr<base::TaskRunner> io_task_runner_override_;
diff --git a/chromium/content/browser/mojo/mojo_child_connection.cc b/chromium/content/browser/mojo/mojo_child_connection.cc
new file mode 100644
index 00000000000..164ba0b027b
--- /dev/null
+++ b/chromium/content/browser/mojo/mojo_child_connection.cc
@@ -0,0 +1,137 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/mojo/mojo_child_connection.h"
+
+#include <stdint.h>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "content/browser/mojo/constants.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_process_host_observer.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "ipc/ipc_sender.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/shell/public/cpp/connector.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+#include "mojo/shell/public/interfaces/shell_client.mojom.h"
+
+namespace content {
+namespace {
+
+const char kMojoRenderProcessHostConnection[] =
+ "mojo_render_process_host_connection";
+
+class RenderProcessHostConnection : public base::SupportsUserData::Data {
+ public:
+ explicit RenderProcessHostConnection(scoped_ptr<mojo::Connection> connection)
+ : connection_(std::move(connection)) {}
+ ~RenderProcessHostConnection() override {}
+
+ mojo::Connection* get() const { return connection_.get(); }
+
+ private:
+ scoped_ptr<mojo::Connection> connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderProcessHostConnection);
+};
+
+void SetMojoConnection(RenderProcessHost* render_process_host,
+ scoped_ptr<mojo::Connection> connection) {
+ render_process_host->SetUserData(
+ kMojoRenderProcessHostConnection,
+ new RenderProcessHostConnection(std::move(connection)));
+}
+
+class PIDSender : public RenderProcessHostObserver {
+ public:
+ PIDSender(
+ RenderProcessHost* host,
+ mojo::shell::mojom::PIDReceiverPtr pid_receiver)
+ : host_(host),
+ pid_receiver_(std::move(pid_receiver)) {
+ pid_receiver_.set_connection_error_handler([this]() { delete this; });
+ DCHECK(!host_->IsReady());
+ host_->AddObserver(this);
+ }
+ ~PIDSender() override {
+ if (host_)
+ host_->RemoveObserver(this);
+ }
+
+ private:
+ // Overridden from RenderProcessHostObserver:
+ void RenderProcessReady(RenderProcessHost* host) override {
+ pid_receiver_->SetPID(base::GetProcId(host->GetHandle()));
+ delete this;
+ }
+
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override {
+ DCHECK_EQ(host_, host);
+ host_ = nullptr;
+ }
+
+ RenderProcessHost* host_;
+ mojo::shell::mojom::PIDReceiverPtr pid_receiver_;
+
+ DISALLOW_COPY_AND_ASSIGN(PIDSender);
+};
+
+} // namespace
+
+std::string MojoConnectToChild(int child_process_id,
+ int instance_id,
+ RenderProcessHost* render_process_host) {
+ // Generate a token and create a pipe which is bound to it. This pipe is
+ // passed to the shell if one is available.
+ std::string pipe_token = mojo::edk::GenerateRandomToken();
+ mojo::ScopedMessagePipeHandle shell_client_pipe =
+ mojo::edk::CreateParentMessagePipe(pipe_token);
+
+ // Some process types get created before the main message loop. In this case
+ // the shell request pipe will simply be closed, and the child can detect
+ // this.
+ if (!MojoShellConnection::Get())
+ return pipe_token;
+
+ mojo::shell::mojom::ShellClientPtr client;
+ client.Bind(mojo::InterfacePtrInfo<mojo::shell::mojom::ShellClient>(
+ std::move(shell_client_pipe), 0u));
+ mojo::shell::mojom::PIDReceiverPtr pid_receiver;
+ mojo::shell::mojom::PIDReceiverRequest pid_receiver_request =
+ GetProxy(&pid_receiver);
+ // PIDSender manages its own lifetime.
+ new PIDSender(render_process_host, std::move(pid_receiver));
+
+ mojo::Identity target(kRendererMojoApplicationName,
+ mojo::shell::mojom::kInheritUserID,
+ base::StringPrintf("%d_%d", child_process_id,
+ instance_id));
+ mojo::Connector::ConnectParams params(target);
+ params.set_client_process_connection(std::move(client),
+ std::move(pid_receiver_request));
+ scoped_ptr<mojo::Connection> connection =
+ MojoShellConnection::Get()->GetConnector()->Connect(&params);
+
+ // Store the connection on the RPH so client code can access it later via
+ // GetMojoConnection().
+ SetMojoConnection(render_process_host, std::move(connection));
+
+ return pipe_token;
+}
+
+mojo::Connection* GetMojoConnection(RenderProcessHost* render_process_host) {
+ RenderProcessHostConnection* connection =
+ static_cast<RenderProcessHostConnection*>(
+ render_process_host->GetUserData(kMojoRenderProcessHostConnection));
+ return connection ? connection->get() : nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_child_connection.h b/chromium/content/browser/mojo/mojo_child_connection.h
new file mode 100644
index 00000000000..2270ce72c34
--- /dev/null
+++ b/chromium/content/browser/mojo/mojo_child_connection.h
@@ -0,0 +1,36 @@
+// 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 CONTENT_BROWSER_MOJO_MOJO_CHILD_CONNECTION_H_
+#define CONTENT_BROWSER_MOJO_MOJO_CHILD_CONNECTION_H_
+
+#include <string>
+
+#include "base/process/process_handle.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
+namespace mojo {
+class Connection;
+}
+
+namespace content {
+
+class RenderProcessHost;
+
+// Establish a mojo::Connection to the child process, using a pipe created for
+// that purpose. Returns a token that should be passed to the child process and
+// exchanged for a pipe there. That pipe can in turn be passed to
+// MojoShellConnectionImpl::BindToMessagePipe() to initialize the child's
+// shell connection.
+std::string MojoConnectToChild(int child_process_id,
+ int instance_id,
+ RenderProcessHost* render_process_host);
+
+// Returns a mojo connection to the provided render process host. This
+// connection was opened when MojoConnectToChild() was called.
+mojo::Connection* GetMojoConnection(RenderProcessHost* render_process_host);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MOJO_MOJO_CHILD_CONNECTION_H_
diff --git a/chromium/content/browser/mojo/mojo_shell_client_host.cc b/chromium/content/browser/mojo/mojo_shell_client_host.cc
deleted file mode 100644
index 326afebb051..00000000000
--- a/chromium/content/browser/mojo/mojo_shell_client_host.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/mojo/mojo_shell_client_host.h"
-
-#include <stdint.h>
-#include <utility>
-
-#include "base/macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "content/common/mojo/mojo_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_process_host_observer.h"
-#include "content/public/common/mojo_shell_connection.h"
-#include "ipc/ipc_sender.h"
-#include "mojo/converters/network/network_type_converters.h"
-#include "mojo/shell/public/cpp/application_impl.h"
-#include "mojo/shell/public/interfaces/application_manager.mojom.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
-#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
-#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace content {
-namespace {
-
-const char kMojoShellInstanceURL[] = "mojo_shell_instance_url";
-const char kMojoPlatformFile[] = "mojo_platform_file";
-
-void DidCreateChannel(mojo::embedder::ChannelInfo* info) {}
-
-base::PlatformFile PlatformFileFromScopedPlatformHandle(
- mojo::embedder::ScopedPlatformHandle handle) {
-#if defined(OS_POSIX)
- return handle.release().fd;
-#elif defined(OS_WIN)
- return handle.release().handle;
-#endif
-}
-
-class InstanceURL : public base::SupportsUserData::Data {
- public:
- InstanceURL(const std::string& instance_url) : instance_url_(instance_url) {}
- ~InstanceURL() override {}
-
- std::string get() const { return instance_url_; }
-
- private:
- std::string instance_url_;
-
- DISALLOW_COPY_AND_ASSIGN(InstanceURL);
-};
-
-class InstanceShellHandle : public base::SupportsUserData::Data {
- public:
- InstanceShellHandle(base::PlatformFile shell_handle)
- : shell_handle_(shell_handle) {}
- ~InstanceShellHandle() override {}
-
- base::PlatformFile get() const { return shell_handle_; }
-
- private:
- base::PlatformFile shell_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(InstanceShellHandle);
-};
-
-void SetMojoApplicationInstanceURL(RenderProcessHost* render_process_host,
- const std::string& instance_url) {
- render_process_host->SetUserData(kMojoShellInstanceURL,
- new InstanceURL(instance_url));
-}
-
-void SetMojoPlatformFile(RenderProcessHost* render_process_host,
- base::PlatformFile platform_file) {
- render_process_host->SetUserData(kMojoPlatformFile,
- new InstanceShellHandle(platform_file));
-}
-
-void CallRegisterProcessWithBroker(base::ProcessId pid,
- MojoHandle client_pipe) {
- mojo::shell::mojom::ApplicationManagerPtr application_manager;
- MojoShellConnection::Get()->GetApplication()->ConnectToService(
- "mojo:shell", &application_manager);
- application_manager->RegisterProcessWithBroker(
- static_cast<uint32_t>(pid),
- mojo::ScopedHandle(mojo::Handle(client_pipe)));
-}
-
-class PIDSender : public RenderProcessHostObserver {
- public:
- PIDSender(
- RenderProcessHost* host,
- mojo::shell::mojom::PIDReceiverPtr pid_receiver)
- : host_(host),
- pid_receiver_(std::move(pid_receiver)) {
- pid_receiver_.set_connection_error_handler([this]() { delete this; });
- DCHECK(!host_->IsReady());
- host_->AddObserver(this);
- }
- ~PIDSender() override {
- if (host_)
- host_->RemoveObserver(this);
- }
-
- private:
- // Overridden from RenderProcessHostObserver:
- void RenderProcessReady(RenderProcessHost* host) override {
- pid_receiver_->SetPID(base::GetProcId(host->GetHandle()));
- delete this;
- }
-
- void RenderProcessHostDestroyed(RenderProcessHost* host) override {
- DCHECK_EQ(host_, host);
- host_ = nullptr;
- }
-
- RenderProcessHost* host_;
- mojo::shell::mojom::PIDReceiverPtr pid_receiver_;
-
- DISALLOW_COPY_AND_ASSIGN(PIDSender);
-};
-
-} // namespace
-
-void RegisterChildWithExternalShell(int child_process_id,
- RenderProcessHost* render_process_host) {
- // Some process types get created before the main message loop.
- if (!MojoShellConnection::Get())
- return;
-
- // Create the channel to be shared with the target process.
- mojo::embedder::HandlePassingInformation handle_passing_info;
- mojo::embedder::PlatformChannelPair platform_channel_pair;
-
- // Give one end to the shell so that it can create an instance.
- mojo::embedder::ScopedPlatformHandle platform_channel =
- platform_channel_pair.PassServerHandle();
- mojo::ScopedMessagePipeHandle handle(mojo::embedder::CreateChannel(
- std::move(platform_channel), base::Bind(&DidCreateChannel),
- base::ThreadTaskRunnerHandle::Get()));
- mojo::shell::mojom::ApplicationManagerPtr application_manager;
- MojoShellConnection::Get()->GetApplication()->ConnectToService(
- "mojo:shell", &application_manager);
- // The content of the URL/qualifier we pass is actually meaningless, it's only
- // important that they're unique per process.
- // TODO(beng): We need to specify a restrictive CapabilityFilter here that
- // matches the needs of the target process. Figure out where that
- // specification is best determined (not here, this is a common
- // chokepoint for all process types) and how to wire it through.
- // http://crbug.com/555393
- std::string url =
- base::StringPrintf("exe:chrome_renderer%d", child_process_id);
-
- mojo::shell::mojom::PIDReceiverPtr pid_receiver;
- mojo::InterfaceRequest<mojo::shell::mojom::PIDReceiver> request =
- GetProxy(&pid_receiver);
- new PIDSender(render_process_host, std::move(pid_receiver));
-
- application_manager->CreateInstanceForHandle(
- mojo::ScopedHandle(mojo::Handle(handle.release().value())),
- url,
- CreateCapabilityFilterForRenderer(),
- std::move(request));
-
- // Send the other end to the child via Chrome IPC.
- base::PlatformFile client_file = PlatformFileFromScopedPlatformHandle(
- platform_channel_pair.PassClientHandle());
- SetMojoPlatformFile(render_process_host, client_file);
-
- // Store the URL on the RPH so client code can access it later via
- // GetMojoApplicationInstanceURL().
- SetMojoApplicationInstanceURL(render_process_host, url);
-}
-
-std::string GetMojoApplicationInstanceURL(
- RenderProcessHost* render_process_host) {
- InstanceURL* instance_url = static_cast<InstanceURL*>(
- render_process_host->GetUserData(kMojoShellInstanceURL));
- return instance_url ? instance_url->get() : std::string();
-}
-
-void SendExternalMojoShellHandleToChild(
- base::ProcessHandle process_handle,
- RenderProcessHost* render_process_host) {
- InstanceShellHandle* client_file = static_cast<InstanceShellHandle*>(
- render_process_host->GetUserData(kMojoPlatformFile));
- if (!client_file)
- return;
- render_process_host->Send(new MojoMsg_BindExternalMojoShellHandle(
- IPC::GetFileHandleForProcess(client_file->get(), process_handle, true)));
-}
-
-mojo::embedder::ScopedPlatformHandle RegisterProcessWithBroker(
- base::ProcessId pid) {
- mojo::embedder::PlatformChannelPair platform_channel_pair;
-
- MojoHandle platform_handle_wrapper;
- MojoResult rv = mojo::embedder::CreatePlatformHandleWrapper(
- platform_channel_pair.PassServerHandle(), &platform_handle_wrapper);
- CHECK_EQ(rv, MOJO_RESULT_OK);
-
- if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- CallRegisterProcessWithBroker(pid, platform_handle_wrapper);
- } else {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(CallRegisterProcessWithBroker, pid,
- platform_handle_wrapper));
- }
-
- return platform_channel_pair.PassClientHandle();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_shell_client_host.h b/chromium/content/browser/mojo/mojo_shell_client_host.h
deleted file mode 100644
index 5624643a8e7..00000000000
--- a/chromium/content/browser/mojo/mojo_shell_client_host.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MOJO_MOJO_SHELL_CLIENT_HOST_H_
-#define CONTENT_BROWSER_MOJO_MOJO_SHELL_CLIENT_HOST_H_
-
-#include <string>
-
-#include "base/process/process_handle.h"
-#include "mojo/shell/public/interfaces/shell.mojom.h"
-#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace content {
-
-class RenderProcessHost;
-
-// Creates a communication channel between the external Mojo shell and the
-// child. The server handle of this channel is shared with the external shell
-// via Mojo IPC. |child_process_id| is used to uniquify the child in the
-// external shell's instance map.
-void RegisterChildWithExternalShell(int child_process_id,
- RenderProcessHost* render_process_host);
-
-// Returns the URL associated with an instance corresponding to the renderer
-// process in the external shell. This URL can be passed to
-// ConnectToApplication() to open a new connection to this renderer.
-std::string GetMojoApplicationInstanceURL(
- RenderProcessHost* render_process_host);
-
-// Shares a client handle to the Mojo Shell with the child via Chrome IPC.
-void SendExternalMojoShellHandleToChild(base::ProcessHandle process_handle,
- RenderProcessHost* render_process_host);
-
-// Constructs a Capability Filter for the renderer's application instance in the
-// external shell. This contains the restrictions imposed on what applications
-// and interfaces the renderer can see. The implementation lives in
-// renderer_capability_filter.cc so that it can be subject to specific security
-// review.
-mojo::CapabilityFilterPtr CreateCapabilityFilterForRenderer();
-
-// Used for the broker in the new EDK.
-mojo::embedder::ScopedPlatformHandle RegisterProcessWithBroker(
- base::ProcessId pid);
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MOJO_MOJO_SHELL_CLIENT_HOST_H_
diff --git a/chromium/content/browser/mojo/mojo_shell_context.cc b/chromium/content/browser/mojo/mojo_shell_context.cc
index 199744d3cb6..55ef2985255 100644
--- a/chromium/content/browser/mojo/mojo_shell_context.cc
+++ b/chromium/content/browser/mojo/mojo_shell_context.cc
@@ -6,34 +6,41 @@
#include <utility>
+#include "base/bind.h"
+#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
+#include "components/profile_service/profile_app.h"
#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/browser/mojo/constants.h"
+#include "content/common/gpu_process_launch_causes.h"
+#include "content/common/mojo/current_thread_loader.h"
+#include "content/common/mojo/mojo_shell_connection_impl.h"
+#include "content/common/mojo/static_loader.h"
#include "content/common/process_control.mojom.h"
+#include "content/grit/content_resources.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
#include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/service_registry.h"
-#include "mojo/common/url_type_converters.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/string.h"
-#include "mojo/shell/application_loader.h"
-#include "mojo/shell/connect_to_application_params.h"
-#include "mojo/shell/identity.h"
-#include "mojo/shell/package_manager/package_manager_impl.h"
-#include "mojo/shell/public/cpp/application_delegate.h"
-#include "mojo/shell/static_application_loader.h"
-
-#if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) || \
- defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
-#include "media/mojo/services/mojo_media_application.h"
-#endif
+#include "mojo/services/catalog/factory.h"
+#include "mojo/services/catalog/manifest_provider.h"
+#include "mojo/services/catalog/store.h"
+#include "mojo/shell/connect_params.h"
+#include "mojo/shell/loader.h"
+#include "mojo/shell/native_runner.h"
+#include "mojo/shell/public/cpp/identity.h"
+#include "mojo/shell/public/cpp/shell_client.h"
+#include "mojo/shell/public/interfaces/connector.mojom.h"
+#include "mojo/shell/runner/host/in_process_native_runner.h"
namespace content {
@@ -43,7 +50,7 @@ namespace {
const MojoShellContext::StaticApplicationMap* g_applications_for_test;
void StartUtilityProcessOnIOThread(
- mojo::InterfaceRequest<ProcessControl> request,
+ mojo::InterfaceRequest<mojom::ProcessControl> request,
const base::string16& process_name,
bool use_sandbox) {
UtilityProcessHost* process_host =
@@ -51,55 +58,53 @@ void StartUtilityProcessOnIOThread(
process_host->SetName(process_name);
if (!use_sandbox)
process_host->DisableSandbox();
- process_host->StartMojoMode();
+ process_host->Start();
ServiceRegistry* services = process_host->GetServiceRegistry();
services->ConnectToRemoteService(std::move(request));
}
-void OnApplicationLoaded(const GURL& url, bool success) {
+void OnApplicationLoaded(const std::string& name, bool success) {
if (!success)
- LOG(ERROR) << "Failed to launch Mojo application for " << url.spec();
+ LOG(ERROR) << "Failed to launch Mojo application for " << name;
}
// The default loader to use for all applications. This does nothing but drop
// the Application request.
-class DefaultApplicationLoader : public mojo::shell::ApplicationLoader {
+class DefaultLoader : public mojo::shell::Loader {
public:
- DefaultApplicationLoader() {}
- ~DefaultApplicationLoader() override {}
+ DefaultLoader() {}
+ ~DefaultLoader() override {}
private:
- // mojo::shell::ApplicationLoader:
- void Load(
- const GURL& url,
- mojo::InterfaceRequest<mojo::Application> application_request) override {}
+ // mojo::shell::Loader:
+ void Load(const std::string& name,
+ mojo::shell::mojom::ShellClientRequest request) override {}
- DISALLOW_COPY_AND_ASSIGN(DefaultApplicationLoader);
+ DISALLOW_COPY_AND_ASSIGN(DefaultLoader);
};
// This launches a utility process and forwards the Load request the
-// ProcessControl service there. The utility process is sandboxed iff
+// mojom::ProcessControl service there. The utility process is sandboxed iff
// |use_sandbox| is true.
-class UtilityProcessLoader : public mojo::shell::ApplicationLoader {
+class UtilityProcessLoader : public mojo::shell::Loader {
public:
UtilityProcessLoader(const base::string16& process_name, bool use_sandbox)
: process_name_(process_name), use_sandbox_(use_sandbox) {}
~UtilityProcessLoader() override {}
private:
- // mojo::shell::ApplicationLoader:
- void Load(
- const GURL& url,
- mojo::InterfaceRequest<mojo::Application> application_request) override {
- ProcessControlPtr process_control;
+ // mojo::shell::Loader:
+ void Load(const std::string& name,
+ mojo::shell::mojom::ShellClientRequest request) override {
+ mojom::ProcessControlPtr process_control;
auto process_request = mojo::GetProxy(&process_control);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&StartUtilityProcessOnIOThread,
base::Passed(&process_request),
process_name_, use_sandbox_));
- process_control->LoadApplication(url.spec(), std::move(application_request),
- base::Bind(&OnApplicationLoaded, url));
+ process_control->LoadApplication(name, std::move(request),
+ base::Bind(&OnApplicationLoaded, name));
}
const base::string16 process_name_;
@@ -108,8 +113,10 @@ class UtilityProcessLoader : public mojo::shell::ApplicationLoader {
DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader);
};
-// Request ProcessControl from GPU process host. Must be called on IO thread.
-void RequestGpuProcessControl(mojo::InterfaceRequest<ProcessControl> request) {
+// Request mojom::ProcessControl from GPU process host. Must be called on IO
+// thread.
+void RequestGpuProcessControl(
+ mojo::InterfaceRequest<mojom::ProcessControl> request) {
BrowserChildProcessHostDelegate* process_host =
GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
CAUSE_FOR_GPU_LAUNCH_MOJO_SETUP);
@@ -120,37 +127,72 @@ void RequestGpuProcessControl(mojo::InterfaceRequest<ProcessControl> request) {
// TODO(xhwang): It's possible that |process_host| is non-null, but the actual
// process is dead. In that case, |request| will be dropped and application
- // load requests through ProcessControl will also fail. Make sure we handle
+ // load requests through mojom::ProcessControl will also fail. Make sure we
+ // handle
// these cases correctly.
process_host->GetServiceRegistry()->ConnectToRemoteService(
std::move(request));
}
// Forwards the load request to the GPU process.
-class GpuProcessLoader : public mojo::shell::ApplicationLoader {
+class GpuProcessLoader : public mojo::shell::Loader {
public:
GpuProcessLoader() {}
~GpuProcessLoader() override {}
private:
- // mojo::shell::ApplicationLoader:
- void Load(
- const GURL& url,
- mojo::InterfaceRequest<mojo::Application> application_request) override {
- ProcessControlPtr process_control;
+ // mojo::shell::Loader:
+ void Load(const std::string& name,
+ mojo::shell::mojom::ShellClientRequest request) override {
+ mojom::ProcessControlPtr process_control;
auto process_request = mojo::GetProxy(&process_control);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&RequestGpuProcessControl, base::Passed(&process_request)));
- process_control->LoadApplication(url.spec(), std::move(application_request),
- base::Bind(&OnApplicationLoaded, url));
+ process_control->LoadApplication(name, std::move(request),
+ base::Bind(&OnApplicationLoaded, name));
}
DISALLOW_COPY_AND_ASSIGN(GpuProcessLoader);
};
+std::string GetStringResource(int id) {
+ return GetContentClient()->GetDataResource(
+ id, ui::ScaleFactor::SCALE_FACTOR_NONE).as_string();
+}
+
} // namespace
+// A ManifestProvider which resolves application names to builtin manifest
+// resources for the catalog service to consume.
+class MojoShellContext::BuiltinManifestProvider
+ : public catalog::ManifestProvider {
+ public:
+ BuiltinManifestProvider() {}
+ ~BuiltinManifestProvider() override {}
+
+ private:
+ // catalog::ManifestProvider:
+ bool GetApplicationManifest(const base::StringPiece& name,
+ std::string* manifest_contents) override {
+ if (name == "mojo:catalog") {
+ *manifest_contents = GetStringResource(IDR_MOJO_CATALOG_MANIFEST);
+ return true;
+ } else if (name == kBrowserMojoApplicationName) {
+ *manifest_contents = GetStringResource(IDR_MOJO_CONTENT_BROWSER_MANIFEST);
+ return true;
+ } else if (name == kRendererMojoApplicationName) {
+ *manifest_contents =
+ GetStringResource(IDR_MOJO_CONTENT_RENDERER_MANIFEST);
+ return true;
+ }
+
+ return false;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider);
+};
+
// Thread-safe proxy providing access to the shell context from any thread.
class MojoShellContext::Proxy {
public:
@@ -161,17 +203,17 @@ class MojoShellContext::Proxy {
~Proxy() {}
void ConnectToApplication(
- const GURL& url,
- const GURL& requestor_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> request,
- mojo::ServiceProviderPtr exposed_services,
- const mojo::shell::CapabilityFilter& filter,
- const mojo::Shell::ConnectToApplicationCallback& callback) {
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name,
+ mojo::shell::mojom::InterfaceProviderRequest request,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback) {
if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
if (shell_context_) {
shell_context_->ConnectToApplicationOnOwnThread(
- url, requestor_url, std::move(request), std::move(exposed_services),
- filter, callback);
+ user_id, name, requestor_name, std::move(request),
+ std::move(exposed_services), callback);
}
} else {
// |shell_context_| outlives the main MessageLoop, so it's safe for it to
@@ -179,9 +221,9 @@ class MojoShellContext::Proxy {
task_runner_->PostTask(
FROM_HERE,
base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread,
- base::Unretained(shell_context_), url, requestor_url,
- base::Passed(&request), base::Passed(&exposed_services),
- filter, callback));
+ base::Unretained(shell_context_), user_id, name,
+ requestor_name, base::Passed(&request),
+ base::Passed(&exposed_services), callback));
}
}
@@ -201,18 +243,23 @@ void MojoShellContext::SetApplicationsForTest(
g_applications_for_test = apps;
}
-MojoShellContext::MojoShellContext() {
+MojoShellContext::MojoShellContext(
+ scoped_refptr<base::SingleThreadTaskRunner> file_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread) {
proxy_.Get().reset(new Proxy(this));
- // Construct with an empty filepath since mojo: urls can't be registered now
- // the url scheme registry is locked.
- scoped_ptr<mojo::shell::PackageManagerImpl> package_manager(
- new mojo::shell::PackageManagerImpl(base::FilePath(), nullptr));
- application_manager_.reset(
- new mojo::shell::ApplicationManager(std::move(package_manager)));
-
- application_manager_->set_default_loader(
- scoped_ptr<mojo::shell::ApplicationLoader>(new DefaultApplicationLoader));
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
+ scoped_ptr<mojo::shell::NativeRunnerFactory> native_runner_factory(
+ new mojo::shell::InProcessNativeRunnerFactory(
+ BrowserThread::GetBlockingPool()));
+ manifest_provider_.reset(new BuiltinManifestProvider);
+ catalog_.reset(new catalog::Factory(file_task_runner.get(), nullptr,
+ manifest_provider_.get()));
+ shell_.reset(new mojo::shell::Shell(std::move(native_runner_factory),
+ catalog_->TakeShellClient()));
+ shell_->set_default_loader(
+ scoped_ptr<mojo::shell::Loader>(new DefaultLoader));
StaticApplicationMap apps;
GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps);
@@ -223,10 +270,8 @@ MojoShellContext::MojoShellContext() {
apps[entry.first] = entry.second;
}
for (const auto& entry : apps) {
- application_manager_->SetLoaderForURL(
- scoped_ptr<mojo::shell::ApplicationLoader>(
- new mojo::shell::StaticApplicationLoader(entry.second)),
- entry.first);
+ shell_->SetLoaderForName(
+ make_scoped_ptr(new StaticLoader(entry.second)), entry.first);
}
ContentBrowserClient::OutOfProcessMojoApplicationMap sandboxed_apps;
@@ -234,8 +279,8 @@ MojoShellContext::MojoShellContext() {
->browser()
->RegisterOutOfProcessMojoApplications(&sandboxed_apps);
for (const auto& app : sandboxed_apps) {
- application_manager_->SetLoaderForURL(
- scoped_ptr<mojo::shell::ApplicationLoader>(
+ shell_->SetLoaderForName(
+ make_scoped_ptr(
new UtilityProcessLoader(app.second, true /* use_sandbox */)),
app.first);
}
@@ -245,59 +290,65 @@ MojoShellContext::MojoShellContext() {
->browser()
->RegisterUnsandboxedOutOfProcessMojoApplications(&unsandboxed_apps);
for (const auto& app : unsandboxed_apps) {
- application_manager_->SetLoaderForURL(
- scoped_ptr<mojo::shell::ApplicationLoader>(
+ shell_->SetLoaderForName(
+ make_scoped_ptr(
new UtilityProcessLoader(app.second, false /* use_sandbox */)),
app.first);
}
-#if (ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
- application_manager_->SetLoaderForURL(
- scoped_ptr<mojo::shell::ApplicationLoader>(
- new mojo::shell::StaticApplicationLoader(
- base::Bind(&media::MojoMediaApplication::CreateApp))),
- GURL("mojo:media"));
-#elif(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
- application_manager_->SetLoaderForURL(
- scoped_ptr<mojo::shell::ApplicationLoader>(new GpuProcessLoader()),
- GURL("mojo:media"));
+#if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
+ shell_->SetLoaderForName(make_scoped_ptr(new GpuProcessLoader), "mojo:media");
#endif
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kMojoLocalStorage)) {
+ base::Callback<scoped_ptr<mojo::ShellClient>()> profile_callback =
+ base::Bind(&profile::CreateProfileApp, file_thread, db_thread);
+ shell_->SetLoaderForName(
+ make_scoped_ptr(new CurrentThreadLoader(profile_callback)),
+ "mojo:profile");
+ }
+
+ if (!IsRunningInMojoShell()) {
+ MojoShellConnection::Create(
+ shell_->InitInstanceForEmbedder(kBrowserMojoApplicationName),
+ false /* is_external */);
+ }
}
MojoShellContext::~MojoShellContext() {
+ if (!IsRunningInMojoShell())
+ MojoShellConnectionImpl::Destroy();
}
// static
void MojoShellContext::ConnectToApplication(
- const GURL& url,
- const GURL& requestor_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> request,
- mojo::ServiceProviderPtr exposed_services,
- const mojo::shell::CapabilityFilter& filter,
- const mojo::Shell::ConnectToApplicationCallback& callback) {
- proxy_.Get()->ConnectToApplication(url, requestor_url, std::move(request),
- std::move(exposed_services), filter,
- callback);
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name,
+ mojo::shell::mojom::InterfaceProviderRequest request,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback) {
+ proxy_.Get()->ConnectToApplication(user_id, name, requestor_name,
+ std::move(request),
+ std::move(exposed_services), callback);
}
void MojoShellContext::ConnectToApplicationOnOwnThread(
- const GURL& url,
- const GURL& requestor_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> request,
- mojo::ServiceProviderPtr exposed_services,
- const mojo::shell::CapabilityFilter& filter,
- const mojo::Shell::ConnectToApplicationCallback& callback) {
- scoped_ptr<mojo::shell::ConnectToApplicationParams> params(
- new mojo::shell::ConnectToApplicationParams);
- params->set_source(
- mojo::shell::Identity(requestor_url, std::string(),
- mojo::shell::GetPermissiveCapabilityFilter()));
- params->SetTarget(mojo::shell::Identity(url, std::string(), filter));
- params->set_services(std::move(request));
- params->set_exposed_services(std::move(exposed_services));
- params->set_on_application_end(base::Bind(&base::DoNothing));
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name,
+ mojo::shell::mojom::InterfaceProviderRequest request,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback) {
+ scoped_ptr<mojo::shell::ConnectParams> params(new mojo::shell::ConnectParams);
+ mojo::Identity source_id(requestor_name, user_id);
+ params->set_source(source_id);
+ params->set_target(mojo::Identity(name, user_id));
+ params->set_remote_interfaces(std::move(request));
+ params->set_local_interfaces(std::move(exposed_services));
params->set_connect_callback(callback);
- application_manager_->ConnectToApplication(std::move(params));
+ shell_->Connect(std::move(params));
}
} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_shell_context.h b/chromium/content/browser/mojo/mojo_shell_context.h
index e45ab88433f..959fd933af7 100644
--- a/chromium/content/browser/mojo/mojo_shell_context.h
+++ b/chromium/content/browser/mojo/mojo_shell_context.h
@@ -12,14 +12,17 @@
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "content/common/content_export.h"
-#include "mojo/shell/application_manager.h"
-#include "mojo/shell/public/interfaces/shell.mojom.h"
+#include "mojo/shell/public/interfaces/connector.mojom.h"
+#include "mojo/shell/shell.h"
-class GURL;
+namespace catalog {
+class Factory;
+}
namespace mojo {
-class ApplicationDelegate;
+class ShellClient;
}
namespace content {
@@ -29,40 +32,44 @@ namespace content {
class CONTENT_EXPORT MojoShellContext {
public:
using StaticApplicationMap =
- std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+ std::map<std::string, base::Callback<scoped_ptr<mojo::ShellClient>()>>;
- MojoShellContext();
+ MojoShellContext(scoped_refptr<base::SingleThreadTaskRunner> file_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread);
~MojoShellContext();
- // Connects an application at |url| and gets a handle to its exposed services.
- // This is only intended for use in browser code that's not part of some Mojo
- // application. May be called from any thread. |requestor_url| is given to
- // the target application as the requestor's URL upon connection.
+ // Connects an application at |name| and gets a handle to its exposed
+ // services. This is only intended for use in browser code that's not part of
+ // some Mojo application. May be called from any thread. |requestor_name| is
+ // given to the target application as the requestor's name upon connection.
static void ConnectToApplication(
- const GURL& url,
- const GURL& requestor_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> request,
- mojo::ServiceProviderPtr exposed_services,
- const mojo::shell::CapabilityFilter& filter,
- const mojo::Shell::ConnectToApplicationCallback& callback);
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name,
+ mojo::shell::mojom::InterfaceProviderRequest request,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback);
static void SetApplicationsForTest(const StaticApplicationMap* apps);
private:
+ class BuiltinManifestProvider;
class Proxy;
friend class Proxy;
void ConnectToApplicationOnOwnThread(
- const GURL& url,
- const GURL& requestor_url,
- mojo::InterfaceRequest<mojo::ServiceProvider> request,
- mojo::ServiceProviderPtr exposed_services,
- const mojo::shell::CapabilityFilter& filter,
- const mojo::Shell::ConnectToApplicationCallback& callback);
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& requestor_name,
+ mojo::shell::mojom::InterfaceProviderRequest request,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services,
+ const mojo::shell::mojom::Connector::ConnectCallback& callback);
static base::LazyInstance<scoped_ptr<Proxy>> proxy_;
- scoped_ptr<mojo::shell::ApplicationManager> application_manager_;
+ scoped_ptr<BuiltinManifestProvider> manifest_provider_;
+ scoped_ptr<catalog::Factory> catalog_;
+ scoped_ptr<mojo::shell::Shell> shell_;
DISALLOW_COPY_AND_ASSIGN(MojoShellContext);
};
diff --git a/chromium/content/browser/mojo/renderer_capability_filter.cc b/chromium/content/browser/mojo/renderer_capability_filter.cc
deleted file mode 100644
index 01a8e626dd7..00000000000
--- a/chromium/content/browser/mojo/renderer_capability_filter.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <utility>
-
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "content/browser/mojo/mojo_shell_client_host.h"
-
-namespace content {
-
-mojo::CapabilityFilterPtr CreateCapabilityFilterForRenderer() {
- // See https://goo.gl/gkBtCR for a description of what this is and what to
- // think about when changing it.
- mojo::CapabilityFilterPtr filter(mojo::CapabilityFilter::New());
- mojo::Array<mojo::String> window_manager_interfaces;
- window_manager_interfaces.push_back(mus::mojom::Gpu::Name_);
- filter->filter.insert("mojo:mus", std::move(window_manager_interfaces));
- return filter;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/mojo/service_registrar_android.cc b/chromium/content/browser/mojo/service_registrar_android.cc
index e29d7f328c3..cd0cfacf818 100644
--- a/chromium/content/browser/mojo/service_registrar_android.cc
+++ b/chromium/content/browser/mojo/service_registrar_android.cc
@@ -6,7 +6,7 @@
#include "base/android/context_utils.h"
#include "base/android/jni_android.h"
-#include "content/browser/mojo/service_registry_android.h"
+#include "content/public/browser/android/service_registry_android.h"
#include "jni/ServiceRegistrar_jni.h"
namespace content {
diff --git a/chromium/content/browser/mojo/service_registry_android.h b/chromium/content/browser/mojo/service_registry_android.h
deleted file mode 100644
index 17d2cb07bdc..00000000000
--- a/chromium/content/browser/mojo/service_registry_android.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MOJO_SERVICE_REGISTRY_ANDROID_H_
-#define CONTENT_BROWSER_MOJO_SERVICE_REGISTRY_ANDROID_H_
-
-#include <jni.h>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class ServiceRegistryImpl;
-
-// Android wrapper over ServiceRegistryImpl, allowing the browser services in
-// Java to register with ServiceRegistry.java (and abstracting away the JNI
-// calls).
-class CONTENT_EXPORT ServiceRegistryAndroid {
- public:
- static bool Register(JNIEnv* env);
-
- explicit ServiceRegistryAndroid(ServiceRegistryImpl* service_registry);
- virtual ~ServiceRegistryAndroid();
-
- // Methods called from Java.
- void AddService(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& j_service_registry,
- const base::android::JavaParamRef<jobject>& j_manager,
- const base::android::JavaParamRef<jobject>& j_factory,
- const base::android::JavaParamRef<jstring>& j_name);
- void RemoveService(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& j_service_registry,
- const base::android::JavaParamRef<jstring>& j_name);
- void ConnectToRemoteService(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& j_service_registry,
- const base::android::JavaParamRef<jstring>& j_name,
- jint handle);
-
- const base::android::ScopedJavaGlobalRef<jobject>& GetObj() { return obj_; }
-
- private:
- ServiceRegistryImpl* service_registry_;
- base::android::ScopedJavaGlobalRef<jobject> obj_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceRegistryAndroid);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MOJO_SERVICE_REGISTRY_ANDROID_H_
diff --git a/chromium/content/browser/mojo_shell_browsertest.cc b/chromium/content/browser/mojo_shell_browsertest.cc
index b291961a077..9777e624052 100644
--- a/chromium/content/browser/mojo_shell_browsertest.cc
+++ b/chromium/content/browser/mojo_shell_browsertest.cc
@@ -7,26 +7,35 @@
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/browser/mojo/mojo_shell_context.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/mojo_app_connection.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/test_mojo_app.h"
#include "content/public/test/test_mojo_service.mojom.h"
+#include "content/shell/browser/shell.h"
#include "url/gurl.h"
namespace content {
-const char kInProcessTestMojoAppUrl[] = "system:content_in_process_test_app";
+const char kInProcessTestMojoAppName[] = "system:content_in_process_test_app";
class MojoShellTest : public ContentBrowserTest {
public:
MojoShellTest() {
- test_apps_[GURL(kInProcessTestMojoAppUrl)] = base::Bind(&CreateTestApp);
+ test_apps_[kInProcessTestMojoAppName] = base::Bind(&CreateTestApp);
MojoShellContext::SetApplicationsForTest(&test_apps_);
}
+ protected:
+ std::string GetUserId() {
+ return BrowserContext::GetMojoUserIdFor(
+ shell()->web_contents()->GetBrowserContext());
+ }
+
private:
- static scoped_ptr<mojo::ApplicationDelegate> CreateTestApp() {
- return scoped_ptr<mojo::ApplicationDelegate>(new TestMojoApp);
+ static scoped_ptr<mojo::ShellClient> CreateTestApp() {
+ return scoped_ptr<mojo::ShellClient>(new TestMojoApp);
}
MojoShellContext::StaticApplicationMap test_apps_;
@@ -35,10 +44,10 @@ class MojoShellTest : public ContentBrowserTest {
};
IN_PROC_BROWSER_TEST_F(MojoShellTest, TestBrowserConnection) {
- auto test_app = MojoAppConnection::Create(GURL(kInProcessTestMojoAppUrl),
- GURL(kBrowserMojoAppUrl));
- TestMojoServicePtr test_service;
- test_app->ConnectToService(&test_service);
+ auto test_app = MojoAppConnection::Create(
+ GetUserId(), kInProcessTestMojoAppName, kBrowserMojoAppUrl);
+ mojom::TestMojoServicePtr test_service;
+ test_app->GetInterface(&test_service);
base::RunLoop run_loop;
test_service->DoSomething(run_loop.QuitClosure());
@@ -49,10 +58,10 @@ IN_PROC_BROWSER_TEST_F(MojoShellTest, TestUtilityConnection) {
// With no loader registered at this URL, the shell should spawn a utility
// process and connect us to it. content_shell's utility process always hosts
// a TestMojoApp at |kTestMojoAppUrl|.
- auto test_app = MojoAppConnection::Create(GURL(kTestMojoAppUrl),
- GURL(kBrowserMojoAppUrl));
- TestMojoServicePtr test_service;
- test_app->ConnectToService(&test_service);
+ auto test_app = MojoAppConnection::Create(GetUserId(), kTestMojoAppUrl,
+ kBrowserMojoAppUrl);
+ mojom::TestMojoServicePtr test_service;
+ test_app->GetInterface(&test_service);
base::RunLoop run_loop;
test_service->DoSomething(run_loop.QuitClosure());
diff --git a/chromium/content/browser/navigator_connect/OWNERS b/chromium/content/browser/navigator_connect/OWNERS
deleted file mode 100644
index 1b10b3436d9..00000000000
--- a/chromium/content/browser/navigator_connect/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mek@chromium.org
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc
deleted file mode 100644
index c393c4bf45a..00000000000
--- a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
-
-#include <stdint.h>
-
-#include "base/stl_util.h"
-#include "content/browser/message_port_service.h"
-#include "content/browser/navigator_connect/service_port_service_impl.h"
-#include "content/browser/service_worker/service_worker_context_wrapper.h"
-#include "content/common/service_worker/service_worker_utils.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigator_connect_service_factory.h"
-#include "content/public/common/navigator_connect_client.h"
-#include "mojo/common/url_type_converters.h"
-
-namespace content {
-
-struct NavigatorConnectContextImpl::Port {
- // ID of this port.
- int id;
- // ID of the port this port is connected to.
- int entangled_id;
-
- // Service url and client origin describing this connection. These fields will
- // always be the same as the same fields for the entangled port.
- GURL target_url;
- GURL client_origin;
-
- // Set to nullptr when the ServicePortService goes away.
- ServicePortServiceImpl* service = nullptr;
-
- // If this port is associated with a service worker, these fields store that
- // information.
- int64_t service_worker_registration_id = kInvalidServiceWorkerRegistrationId;
- GURL service_worker_registration_origin;
-};
-
-NavigatorConnectContextImpl::NavigatorConnectContextImpl(
- const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
- : service_worker_context_(service_worker_context), next_port_id_(0) {}
-
-NavigatorConnectContextImpl::~NavigatorConnectContextImpl() {
-}
-
-void NavigatorConnectContextImpl::AddFactory(
- scoped_ptr<NavigatorConnectServiceFactory> factory) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this,
- base::Passed(&factory)));
-}
-
-void NavigatorConnectContextImpl::AddFactoryOnIOThread(
- scoped_ptr<NavigatorConnectServiceFactory> factory) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- service_factories_.push_back(factory.release());
-}
-
-void NavigatorConnectContextImpl::Connect(
- const GURL& target_url,
- const GURL& origin,
- ServicePortServiceImpl* service_port_service,
- const ConnectCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Create a new message channel.
- int client_port_id = next_port_id_++;
- int service_port_id = next_port_id_++;
-
- Port& client_port = ports_[client_port_id];
- client_port.id = client_port_id;
- client_port.entangled_id = service_port_id;
- client_port.target_url = target_url;
- client_port.client_origin = origin;
- client_port.service = service_port_service;
-
- Port& service_port = ports_[service_port_id];
- service_port.id = service_port_id;
- service_port.entangled_id = client_port_id;
- service_port.target_url = target_url;
- service_port.client_origin = origin;
-
- // Find the right service worker to service this connection.
- service_worker_context_->FindReadyRegistrationForDocument(
- target_url,
- base::Bind(&NavigatorConnectContextImpl::GotServiceWorkerRegistration,
- this, callback, client_port_id, service_port_id));
-}
-
-void NavigatorConnectContextImpl::PostMessage(
- int sender_port_id,
- const MessagePortMessage& message,
- const std::vector<TransferredMessagePort>& sent_message_ports) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ports_.find(sender_port_id) != ports_.end());
- DCHECK(message.message_as_value.empty());
-
- const Port& sender_port = ports_[sender_port_id];
- DCHECK(ports_.find(sender_port.entangled_id) != ports_.end());
- const Port& port = ports_[sender_port.entangled_id];
-
- if (port.service_worker_registration_id !=
- kInvalidServiceWorkerRegistrationId) {
- // Port is associated with service worker, dispatch message event via
- // ServiceWorkerVersion.
-
- // Hold messages on transferred message ports. Actual delivery of the
- // message by the service can be asynchronous. When a message is delivered,
- // WebMessagePortChannelImpl instances will be constructed which send
- // MessagePortHostMsg_ReleaseMessages to release messages.
- for (const auto& sent_port : sent_message_ports)
- MessagePortService::GetInstance()->HoldMessages(sent_port.id);
-
- service_worker_context_->FindReadyRegistrationForId(
- port.service_worker_registration_id,
- port.service_worker_registration_origin,
- base::Bind(&NavigatorConnectContextImpl::DeliverMessage, this, port.id,
- message.message_as_string, sent_message_ports));
- return;
- }
-
- if (!port.service) {
- // TODO(mek): Figure out what to do in this situation.
- return;
- }
- port.service->PostMessageToClient(port.id, message, sent_message_ports);
-}
-
-void NavigatorConnectContextImpl::GotServiceWorkerRegistration(
- const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- ServiceWorkerStatusCode status,
- const scoped_refptr<ServiceWorkerRegistration>& registration) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ports_.find(client_port_id) != ports_.end());
- DCHECK(ports_.find(service_port_id) != ports_.end());
-
- if (status != SERVICE_WORKER_OK) {
- // No service worker found, reject connection attempt.
- OnConnectError(callback, client_port_id, service_port_id, status);
- return;
- }
-
- ServiceWorkerVersion* active_version = registration->active_version();
- DCHECK(active_version);
-
- Port& service_port = ports_[service_port_id];
- service_port.service_worker_registration_id = registration->id();
- service_port.service_worker_registration_origin =
- registration->pattern().GetOrigin();
-
- active_version->RunAfterStartWorker(
- base::Bind(&NavigatorConnectContextImpl::OnConnectError, this, callback,
- client_port_id, service_port_id),
- base::Bind(&NavigatorConnectContextImpl::DispatchConnectEvent, this,
- callback, client_port_id, service_port_id, registration,
- make_scoped_refptr(active_version)));
-}
-
-void NavigatorConnectContextImpl::DispatchConnectEvent(
- const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
- const scoped_refptr<ServiceWorkerVersion>& worker) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ContainsKey(ports_, client_port_id));
- DCHECK(ContainsKey(ports_, service_port_id));
-
- const Port& service_port = ports_[service_port_id];
- int request_id = worker->StartRequest(
- ServiceWorkerMetrics::EventType::SERVICE_PORT_CONNECT,
- base::Bind(&NavigatorConnectContextImpl::OnConnectError, this, callback,
- client_port_id, service_port_id));
- base::WeakPtr<ServicePortDispatcher> dispatcher =
- worker->GetMojoServiceForRequest<ServicePortDispatcher>(request_id);
- dispatcher->Connect(
- mojo::String::From(service_port.target_url),
- mojo::String::From(service_port.client_origin), service_port_id,
- base::Bind(&NavigatorConnectContextImpl::OnConnectResult, this, callback,
- client_port_id, service_port_id, service_worker_registration,
- worker, request_id));
-}
-
-void NavigatorConnectContextImpl::ServicePortServiceDestroyed(
- ServicePortServiceImpl* service_port_service) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- for (auto& port : ports_) {
- if (port.second.service != service_port_service)
- continue;
- port.second.service = nullptr;
- // TODO(mek): Should actually inform other side of connections that the
- // connection was closed, or in the case of service workers somehow keep
- // track of the connection.
- }
-}
-
-void NavigatorConnectContextImpl::OnConnectError(
- const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- ServiceWorkerStatusCode status) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Destroy ports since connection failed.
- ports_.erase(service_port_id);
- ports_.erase(client_port_id);
- callback.Run(MSG_ROUTING_NONE, false);
-}
-
-void NavigatorConnectContextImpl::OnConnectResult(
- const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
- const scoped_refptr<ServiceWorkerVersion>& worker,
- int request_id,
- ServicePortConnectResult result,
- const mojo::String& name,
- const mojo::String& data) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (!worker->FinishRequest(request_id))
- return;
-
- if (result != SERVICE_PORT_CONNECT_RESULT_ACCEPT) {
- OnConnectError(callback, client_port_id, service_port_id,
- SERVICE_WORKER_ERROR_FAILED);
- return;
- }
-
- // TODO(mek): Might have to do something else if the client connection got
- // severed while the service side connection was being set up.
- callback.Run(client_port_id, true);
-}
-
-void NavigatorConnectContextImpl::DeliverMessage(
- int port_id,
- const base::string16& message,
- const std::vector<TransferredMessagePort>& sent_message_ports,
- ServiceWorkerStatusCode service_worker_status,
- const scoped_refptr<ServiceWorkerRegistration>&
- service_worker_registration) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ports_.find(port_id) != ports_.end());
-
- if (service_worker_status != SERVICE_WORKER_OK) {
- // TODO(mek): Do something when no service worker was found.
- return;
- }
-
- ServiceWorkerVersion* active_version =
- service_worker_registration->active_version();
- DCHECK(active_version);
-
- const Port& port = ports_[port_id];
- NavigatorConnectClient client(port.target_url, port.client_origin, port_id);
- active_version->DispatchCrossOriginMessageEvent(
- client, message, sent_message_ports,
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h b/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h
deleted file mode 100644
index 5337a338203..00000000000
--- a/chromium/content/browser/navigator_connect/navigator_connect_context_impl.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
-#define CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
-
-#include <map>
-#include "base/callback_forward.h"
-#include "base/memory/scoped_vector.h"
-#include "base/strings/string16.h"
-#include "content/common/service_port_service.mojom.h"
-#include "content/common/service_worker/service_worker_status_code.h"
-#include "content/public/browser/navigator_connect_context.h"
-
-class GURL;
-
-namespace content {
-
-struct MessagePortMessage;
-class NavigatorConnectService;
-class NavigatorConnectServiceFactory;
-struct NavigatorConnectClient;
-class ServicePortServiceImpl;
-class ServiceWorkerContextWrapper;
-class ServiceWorkerRegistration;
-class ServiceWorkerVersion;
-struct TransferredMessagePort;
-
-// Tracks all active navigator.services connections, as well as available
-// service factories. Delegates connection requests to the correct factory and
-// passes messages on to the correct service.
-// One instance of this class exists per StoragePartition.
-// TODO(mek): Clean up connections, fire of closed events when connections die.
-// TODO(mek): Update service side API to be fully ServicePort based.
-// TODO(mek): Make ServicePorts that live in a service worker be able to survive
-// the worker being restarted.
-// TODO(mek): Add back ability for service ports to be backed by native code.
-class NavigatorConnectContextImpl : public NavigatorConnectContext {
- public:
- using ConnectCallback =
- base::Callback<void(int message_port_id, bool success)>;
-
- explicit NavigatorConnectContextImpl(
- const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
-
- // Called when a new connection request comes in from a client. Finds the
- // correct service factory and passes the connection request off to there.
- // Can call the callback before this method call returns.
- void Connect(const GURL& target_url,
- const GURL& origin,
- ServicePortServiceImpl* service_port_service,
- const ConnectCallback& callback);
-
- // Called when a message is sent to a ServicePort. The |sender_port_id| is the
- // id of the port the message is sent from, this will look up what other port
- // the port is entangled with and deliver the message to that port.
- void PostMessage(
- int sender_port_id,
- const MessagePortMessage& message,
- const std::vector<TransferredMessagePort>& sent_message_ports);
-
- // Called by a ServicePortServiceImpl instance when it is about to be
- // destroyed to inform this class that all its connections are no longer
- // valid.
- void ServicePortServiceDestroyed(
- ServicePortServiceImpl* service_port_service);
-
- // NavigatorConnectContext implementation.
- void AddFactory(scoped_ptr<NavigatorConnectServiceFactory> factory) override;
-
- private:
- ~NavigatorConnectContextImpl() override;
-
- void AddFactoryOnIOThread(scoped_ptr<NavigatorConnectServiceFactory> factory);
-
- // Callback called when a ServiceWorkerRegistration has been located (or
- // has failed to be located) for a connection attempt.
- void GotServiceWorkerRegistration(
- const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- ServiceWorkerStatusCode status,
- const scoped_refptr<ServiceWorkerRegistration>& registration);
-
- void DispatchConnectEvent(const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- const scoped_refptr<ServiceWorkerRegistration>&
- service_worker_registration,
- const scoped_refptr<ServiceWorkerVersion>& worker);
-
- // Callback called when dispatching a connect event failed.
- void OnConnectError(const ConnectCallback& calback,
- int client_port_id,
- int service_port_id,
- ServiceWorkerStatusCode status);
-
- // Callback called with the response to a connect event.
- void OnConnectResult(const ConnectCallback& callback,
- int client_port_id,
- int service_port_id,
- const scoped_refptr<ServiceWorkerRegistration>&
- service_worker_registration,
- const scoped_refptr<ServiceWorkerVersion>& worker,
- int request_id,
- ServicePortConnectResult result,
- const mojo::String& name,
- const mojo::String& data);
-
- // Callback called when a ServiceWorkerRegistration has been located to
- // deliver a message to.
- void DeliverMessage(
- int port_id,
- const base::string16& message,
- const std::vector<TransferredMessagePort>& sent_message_ports,
- ServiceWorkerStatusCode status,
- const scoped_refptr<ServiceWorkerRegistration>& registration);
-
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
-
- // List of factories to try to handle URLs.
- ScopedVector<NavigatorConnectServiceFactory> service_factories_;
-
- // List of currently active ServicePorts.
- struct Port;
- std::map<int, Port> ports_;
- int next_port_id_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_CONTEXT_IMPL_H_
diff --git a/chromium/content/browser/navigator_connect/service_port_service_impl.cc b/chromium/content/browser/navigator_connect/service_port_service_impl.cc
deleted file mode 100644
index 310c304ab3e..00000000000
--- a/chromium/content/browser/navigator_connect/service_port_service_impl.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/navigator_connect/service_port_service_impl.h"
-
-#include <utility>
-
-#include "content/browser/message_port_message_filter.h"
-#include "content/browser/message_port_service.h"
-#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
-#include "content/common/service_port_type_converters.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/message_port_types.h"
-#include "mojo/common/common_type_converters.h"
-#include "url/gurl.h"
-
-namespace content {
-
-// static
-void ServicePortServiceImpl::Create(
- const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&ServicePortServiceImpl::CreateOnIOThread,
- navigator_connect_context, message_port_message_filter,
- base::Passed(&request)));
-}
-
-ServicePortServiceImpl::~ServicePortServiceImpl() {
- // Should always be destroyed on the IO thread, but can't check that with
- // DCHECK_CURRENTLY_ON because this class could be destroyed during thread
- // shutdown, at which point that check doesn't work.
- navigator_connect_context_->ServicePortServiceDestroyed(this);
-}
-
-void ServicePortServiceImpl::PostMessageToClient(
- int port_id,
- const MessagePortMessage& message,
- const std::vector<TransferredMessagePort>& sent_message_ports) {
- DCHECK(client_.get());
- // Hold messages on transferred message ports. Normally this wouldn't be
- // needed, but since MessagePort uses regular IPC while this class uses mojo,
- // without holding messages mojo IPC might overtake regular IPC resulting in a
- // non-functional port. When WebMessagePortChannelImpl instances are
- // constructed in the renderer, they will send
- // MessagePortHostMsg_ReleaseMessages to release messages.
- for (const auto& port : sent_message_ports)
- MessagePortService::GetInstance()->HoldMessages(port.id);
-
- std::vector<int> new_routing_ids;
- message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
- sent_message_ports, &new_routing_ids);
- client_->PostMessageToPort(
- port_id, mojo::String::From(message.message_as_string),
- mojo::Array<MojoTransferredMessagePortPtr>::From(sent_message_ports),
- mojo::Array<int32_t>::From(new_routing_ids));
-}
-
-// static
-void ServicePortServiceImpl::CreateOnIOThread(
- const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- new ServicePortServiceImpl(navigator_connect_context,
- message_port_message_filter, std::move(request));
-}
-
-ServicePortServiceImpl::ServicePortServiceImpl(
- const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request)
- : binding_(this, std::move(request)),
- navigator_connect_context_(navigator_connect_context),
- message_port_message_filter_(message_port_message_filter),
- weak_ptr_factory_(this) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-void ServicePortServiceImpl::SetClient(ServicePortServiceClientPtr client) {
- DCHECK(!client_.get());
- // TODO(mek): Set ErrorHandler to listen for errors.
- client_ = std::move(client);
-}
-
-void ServicePortServiceImpl::Connect(const mojo::String& target_url,
- const mojo::String& origin,
- const ConnectCallback& callback) {
- navigator_connect_context_->Connect(
- GURL(target_url), GURL(origin), this,
- base::Bind(&ServicePortServiceImpl::OnConnectResult,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void ServicePortServiceImpl::PostMessageToPort(
- int32_t port_id,
- const mojo::String& message,
- mojo::Array<MojoTransferredMessagePortPtr> ports) {
- // TODO(mek): Similar to http://crbug.com/490222 this code should make sure
- // port_id belongs to the process this IPC was received from.
- std::vector<TransferredMessagePort> transferred_ports =
- ports.To<std::vector<TransferredMessagePort>>();
-
- MessagePortService* mps = MessagePortService::GetInstance();
- // First, call QueueMessages for all transferred ports, since the ports
- // haven't sent their own IPC for that.
- for (const TransferredMessagePort& port : transferred_ports) {
- mps->QueueMessages(port.id);
- }
-
- navigator_connect_context_->PostMessage(
- port_id, MessagePortMessage(message.To<base::string16>()),
- transferred_ports);
-}
-
-void ServicePortServiceImpl::ClosePort(int32_t port_id) {
- MessagePortService::GetInstance()->Destroy(port_id);
-}
-
-void ServicePortServiceImpl::OnConnectResult(const ConnectCallback& callback,
- int message_port_id,
- bool success) {
- callback.Run(success ? SERVICE_PORT_CONNECT_RESULT_ACCEPT
- : SERVICE_PORT_CONNECT_RESULT_REJECT,
- message_port_id);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/navigator_connect/service_port_service_impl.h b/chromium/content/browser/navigator_connect/service_port_service_impl.h
deleted file mode 100644
index be1815ed3ed..00000000000
--- a/chromium/content/browser/navigator_connect/service_port_service_impl.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_NAVIGATOR_CONNECT_SERVICE_PORT_SERVICE_IMPL_H_
-#define CONTENT_BROWSER_NAVIGATOR_CONNECT_SERVICE_PORT_SERVICE_IMPL_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/service_port_service.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace content {
-struct MessagePortMessage;
-class MessagePortMessageFilter;
-class NavigatorConnectContextImpl;
-struct TransferredMessagePort;
-
-// Browser side class representing a ServicePortCollection in the renderer. One
-// instance of this class is created for each ServicePortCollection, and is
-// automatically destroyed when the ServicePortCollection in the renderer goes
-// away.
-class ServicePortServiceImpl : public ServicePortService {
- public:
- // Factory method called by mojo to create a new instance of this class to
- // handle requests from a new ServicePortCollection.
- static void Create(const scoped_refptr<NavigatorConnectContextImpl>&
- navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>&
- message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request);
- ~ServicePortServiceImpl() override;
-
- // Called by NavigatorConnectContextImpl to post a message to a port that is
- // owned by this ServicePortCollection.
- void PostMessageToClient(
- int port_id,
- const MessagePortMessage& message,
- const std::vector<TransferredMessagePort>& sent_message_ports);
-
- private:
- static void CreateOnIOThread(
- const scoped_refptr<NavigatorConnectContextImpl>&
- navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>&
- message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request);
- ServicePortServiceImpl(const scoped_refptr<NavigatorConnectContextImpl>&
- navigator_connect_context,
- const scoped_refptr<MessagePortMessageFilter>&
- message_port_message_filter,
- mojo::InterfaceRequest<ServicePortService> request);
-
- // ServicePortService methods:
- void SetClient(ServicePortServiceClientPtr client) override;
- void Connect(const mojo::String& target_url,
- const mojo::String& origin,
- const ConnectCallback& callback) override;
- void PostMessageToPort(
- int32_t port_id,
- const mojo::String& message,
- mojo::Array<MojoTransferredMessagePortPtr> ports) override;
- void ClosePort(int32_t port_id) override;
-
- // Callback called when a connection to a service has been establised or
- // rejected.
- void OnConnectResult(const ConnectCallback& callback,
- int message_port_id,
- bool success);
-
- mojo::StrongBinding<ServicePortService> binding_;
- scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context_;
- scoped_refptr<MessagePortMessageFilter> message_port_message_filter_;
- ServicePortServiceClientPtr client_;
- base::WeakPtrFactory<ServicePortServiceImpl> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ServicePortServiceImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_NAVIGATOR_CONNECT_SERVICE_PORT_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/net/quota_policy_cookie_store.cc b/chromium/content/browser/net/quota_policy_cookie_store.cc
index 9404981fb60..6767eb8d4b5 100644
--- a/chromium/content/browser/net/quota_policy_cookie_store.cc
+++ b/chromium/content/browser/net/quota_policy_cookie_store.cc
@@ -129,17 +129,18 @@ CookieStoreConfig::CookieStoreConfig(
CookieStoreConfig::~CookieStoreConfig() {
}
-net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
+scoped_ptr<net::CookieStore> CreateCookieStore(
+ const CookieStoreConfig& config) {
// TODO(bcwhite): Remove ScopedTracker below once crbug.com/483686 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION("483686 content::CreateCookieStore"));
- net::CookieMonster* cookie_monster = nullptr;
+ scoped_ptr<net::CookieMonster> cookie_monster;
if (config.path.empty()) {
// Empty path means in-memory store.
- cookie_monster = new net::CookieMonster(nullptr,
- config.cookie_delegate.get());
+ cookie_monster.reset(
+ new net::CookieMonster(nullptr, config.cookie_delegate.get()));
} else {
scoped_refptr<base::SequencedTaskRunner> client_task_runner =
config.client_task_runner;
@@ -171,8 +172,8 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
sqlite_store.get(),
config.storage_policy.get());
- cookie_monster =
- new net::CookieMonster(persistent_store, config.cookie_delegate.get());
+ cookie_monster.reset(
+ new net::CookieMonster(persistent_store, config.cookie_delegate.get()));
if ((config.session_cookie_mode ==
CookieStoreConfig::PERSISTANT_SESSION_COOKIES) ||
(config.session_cookie_mode ==
@@ -181,7 +182,10 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
}
}
- return cookie_monster;
+ if (!config.cookieable_schemes.empty())
+ cookie_monster->SetCookieableSchemes(config.cookieable_schemes);
+
+ return std::move(cookie_monster);
}
} // namespace content
diff --git a/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc b/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
index ca33d6ecbd3..01db50f9b3d 100644
--- a/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
+++ b/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -96,10 +96,10 @@ class QuotaPolicyCookieStoreTest : public testing::Test {
const std::string& domain,
const std::string& path,
const base::Time& creation) {
- store_->AddCookie(
- net::CanonicalCookie(
- GURL(), name, value, domain, path, creation, creation, creation,
- false, false, false, net::COOKIE_PRIORITY_DEFAULT));
+ store_->AddCookie(net::CanonicalCookie(
+ GURL(), name, value, domain, path, creation, creation, creation, false,
+ false, net::CookieSameSite::DEFAULT_MODE,
+ net::COOKIE_PRIORITY_DEFAULT));
}
void DestroyStore() {
diff --git a/chromium/content/browser/notifications/notification_database.h b/chromium/content/browser/notifications/notification_database.h
index 4f230a11c86..e5914e1abf1 100644
--- a/chromium/content/browser/notifications/notification_database.h
+++ b/chromium/content/browser/notifications/notification_database.h
@@ -6,11 +6,13 @@
#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_DATABASE_H_
#include <stdint.h>
+
#include <set>
#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/sequence_checker.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/notifications/notification_database_data.proto b/chromium/content/browser/notifications/notification_database_data.proto
index 3047d2b4356..aad02a8cf2a 100644
--- a/chromium/content/browser/notifications/notification_database_data.proto
+++ b/chromium/content/browser/notifications/notification_database_data.proto
@@ -20,16 +20,25 @@ message NotificationDatabaseDataProto {
// A notification action, corresponds to content::PlatformNotificationAction.
//
- // Next tag: 3
+ // Next tag: 6
message NotificationAction {
+ // Corresponds to PlatformNotificationActionType.
+ enum Type {
+ BUTTON = 0;
+ TEXT = 1;
+ }
+
optional string action = 1;
optional string title = 2;
+ optional string icon = 3;
+ optional Type type = 4;
+ optional string placeholder = 5;
}
// Actual data payload of the notification. This message is the protocol
// buffer meant to serialize the content::PlatformNotificationData structure.
//
- // Next tag: 12
+ // Next tag: 15
message NotificationData {
enum Direction {
LEFT_TO_RIGHT = 0;
@@ -43,7 +52,10 @@ message NotificationDatabaseDataProto {
optional string body = 4;
optional string tag = 5;
optional string icon = 6;
+ optional string badge = 14;
repeated int32 vibration_pattern = 9 [packed=true];
+ optional int64 timestamp = 12;
+ optional bool renotify = 13;
optional bool silent = 7;
optional bool require_interaction = 11;
optional bytes data = 8;
diff --git a/chromium/content/browser/notifications/notification_database_data_conversions.cc b/chromium/content/browser/notifications/notification_database_data_conversions.cc
index cf19704f9dc..381f0d3ef9c 100644
--- a/chromium/content/browser/notifications/notification_database_data_conversions.cc
+++ b/chromium/content/browser/notifications/notification_database_data_conversions.cc
@@ -6,8 +6,11 @@
#include <stddef.h>
+#include <memory>
+
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "content/browser/notifications/notification_database_data.pb.h"
#include "content/public/browser/notification_database_data.h"
@@ -50,12 +53,16 @@ bool DeserializeNotificationDatabaseData(const std::string& input,
notification_data->body = base::UTF8ToUTF16(payload.body());
notification_data->tag = payload.tag();
notification_data->icon = GURL(payload.icon());
+ notification_data->badge = GURL(payload.badge());
if (payload.vibration_pattern().size() > 0) {
notification_data->vibration_pattern.assign(
payload.vibration_pattern().begin(), payload.vibration_pattern().end());
}
+ notification_data->timestamp =
+ base::Time::FromInternalValue(payload.timestamp());
+ notification_data->renotify = payload.renotify();
notification_data->silent = payload.silent();
notification_data->require_interaction = payload.require_interaction();
@@ -66,8 +73,25 @@ bool DeserializeNotificationDatabaseData(const std::string& input,
for (const auto& payload_action : payload.actions()) {
PlatformNotificationAction action;
+
+ switch (payload_action.type()) {
+ case NotificationDatabaseDataProto::NotificationAction::BUTTON:
+ action.type = PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
+ break;
+ case NotificationDatabaseDataProto::NotificationAction::TEXT:
+ action.type = PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+ break;
+ default:
+ NOTREACHED();
+ }
+
action.action = payload_action.action();
action.title = base::UTF8ToUTF16(payload_action.title());
+ action.icon = GURL(payload_action.icon());
+ if (payload_action.has_placeholder()) {
+ action.placeholder = base::NullableString16(
+ base::UTF8ToUTF16(payload_action.placeholder()), false);
+ }
notification_data->actions.push_back(action);
}
@@ -78,7 +102,7 @@ bool SerializeNotificationDatabaseData(const NotificationDatabaseData& input,
std::string* output) {
DCHECK(output);
- scoped_ptr<NotificationDatabaseDataProto::NotificationData> payload(
+ std::unique_ptr<NotificationDatabaseDataProto::NotificationData> payload(
new NotificationDatabaseDataProto::NotificationData());
const PlatformNotificationData& notification_data = input.notification_data;
@@ -104,10 +128,13 @@ bool SerializeNotificationDatabaseData(const NotificationDatabaseData& input,
payload->set_body(base::UTF16ToUTF8(notification_data.body));
payload->set_tag(notification_data.tag);
payload->set_icon(notification_data.icon.spec());
+ payload->set_badge(notification_data.badge.spec());
for (size_t i = 0; i < notification_data.vibration_pattern.size(); ++i)
payload->add_vibration_pattern(notification_data.vibration_pattern[i]);
+ payload->set_timestamp(notification_data.timestamp.ToInternalValue());
+ payload->set_renotify(notification_data.renotify);
payload->set_silent(notification_data.silent);
payload->set_require_interaction(notification_data.require_interaction);
@@ -119,8 +146,28 @@ bool SerializeNotificationDatabaseData(const NotificationDatabaseData& input,
for (const PlatformNotificationAction& action : notification_data.actions) {
NotificationDatabaseDataProto::NotificationAction* payload_action =
payload->add_actions();
+
+ switch (action.type) {
+ case PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
+ payload_action->set_type(
+ NotificationDatabaseDataProto::NotificationAction::BUTTON);
+ break;
+ case PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
+ payload_action->set_type(
+ NotificationDatabaseDataProto::NotificationAction::TEXT);
+ break;
+ default:
+ NOTREACHED() << "Unknown action type: " << action.type;
+ }
+
payload_action->set_action(action.action);
payload_action->set_title(base::UTF16ToUTF8(action.title));
+ payload_action->set_icon(action.icon.spec());
+
+ if (!action.placeholder.is_null()) {
+ payload_action->set_placeholder(
+ base::UTF16ToUTF8(action.placeholder.string()));
+ }
}
NotificationDatabaseDataProto message;
diff --git a/chromium/content/browser/notifications/notification_database_data_unittest.cc b/chromium/content/browser/notifications/notification_database_data_unittest.cc
index a080ae4d558..bf93b3547ee 100644
--- a/chromium/content/browser/notifications/notification_database_data_unittest.cc
+++ b/chromium/content/browser/notifications/notification_database_data_unittest.cc
@@ -6,8 +6,10 @@
#include <stdint.h>
#include "base/macros.h"
+#include "base/strings/nullable_string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "content/browser/notifications/notification_database_data.pb.h"
#include "content/browser/notifications/notification_database_data_conversions.h"
#include "content/common/notification_constants.h"
@@ -20,13 +22,18 @@ namespace content {
const int64_t kNotificationId = 42;
const int64_t kServiceWorkerRegistrationId = 9001;
+const PlatformNotificationActionType kNotificationActionType =
+ PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
const char kOrigin[] = "https://example.com/";
const char kNotificationTitle[] = "My Notification";
const char kNotificationLang[] = "nl";
const char kNotificationBody[] = "Hello, world!";
const char kNotificationTag[] = "my_tag";
const char kNotificationIconUrl[] = "https://example.com/icon.png";
+const char kNotificationBadgeUrl[] = "https://example.com/badge.png";
+const char kNotificationActionIconUrl[] = "https://example.com/action_icon.png";
const int kNotificationVibrationPattern[] = {100, 200, 300};
+const double kNotificationTimestamp = 621046800.;
const unsigned char kNotificationData[] = {0xdf, 0xff, 0x0, 0x0, 0xff, 0xdf};
TEST(NotificationDatabaseDataTest, SerializeAndDeserializeData) {
@@ -45,14 +52,21 @@ TEST(NotificationDatabaseDataTest, SerializeAndDeserializeData) {
notification_data.body = base::ASCIIToUTF16(kNotificationBody);
notification_data.tag = kNotificationTag;
notification_data.icon = GURL(kNotificationIconUrl);
+ notification_data.badge = GURL(kNotificationBadgeUrl);
notification_data.vibration_pattern = vibration_pattern;
+ notification_data.timestamp = base::Time::FromJsTime(kNotificationTimestamp);
+ notification_data.renotify = true;
notification_data.silent = true;
notification_data.require_interaction = true;
notification_data.data = developer_data;
for (size_t i = 0; i < kPlatformNotificationMaxActions; i++) {
PlatformNotificationAction notification_action;
+ notification_action.type = kNotificationActionType;
notification_action.action = base::SizeTToString(i);
notification_action.title = base::SizeTToString16(i);
+ notification_action.icon = GURL(kNotificationActionIconUrl);
+ notification_action.placeholder =
+ base::NullableString16(base::SizeTToString16(i), false);
notification_data.actions.push_back(notification_action);
}
@@ -88,10 +102,13 @@ TEST(NotificationDatabaseDataTest, SerializeAndDeserializeData) {
EXPECT_EQ(notification_data.body, copied_notification_data.body);
EXPECT_EQ(notification_data.tag, copied_notification_data.tag);
EXPECT_EQ(notification_data.icon, copied_notification_data.icon);
+ EXPECT_EQ(notification_data.badge, copied_notification_data.badge);
EXPECT_THAT(copied_notification_data.vibration_pattern,
testing::ElementsAreArray(kNotificationVibrationPattern));
+ EXPECT_EQ(notification_data.timestamp, copied_notification_data.timestamp);
+ EXPECT_EQ(notification_data.renotify, copied_notification_data.renotify);
EXPECT_EQ(notification_data.silent, copied_notification_data.silent);
EXPECT_EQ(notification_data.require_interaction,
copied_notification_data.require_interaction);
@@ -103,10 +120,44 @@ TEST(NotificationDatabaseDataTest, SerializeAndDeserializeData) {
ASSERT_EQ(notification_data.actions.size(),
copied_notification_data.actions.size());
for (size_t i = 0; i < notification_data.actions.size(); ++i) {
+ EXPECT_EQ(notification_data.actions[i].type,
+ copied_notification_data.actions[i].type);
EXPECT_EQ(notification_data.actions[i].action,
copied_notification_data.actions[i].action);
EXPECT_EQ(notification_data.actions[i].title,
copied_notification_data.actions[i].title);
+ EXPECT_EQ(notification_data.actions[i].icon,
+ copied_notification_data.actions[i].icon);
+ EXPECT_EQ(notification_data.actions[i].placeholder,
+ copied_notification_data.actions[i].placeholder);
+ EXPECT_FALSE(copied_notification_data.actions[i].placeholder.is_null());
+ }
+}
+
+TEST(NotificationDatabaseDataTest, SerializeAndDeserializeActionTypes) {
+ PlatformNotificationActionType action_types[] = {
+ PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON,
+ PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT};
+
+ for (PlatformNotificationActionType action_type : action_types) {
+ PlatformNotificationData notification_data;
+
+ PlatformNotificationAction action;
+ action.type = action_type;
+ notification_data.actions.push_back(action);
+
+ NotificationDatabaseData database_data;
+ database_data.notification_data = notification_data;
+
+ std::string serialized_data;
+ ASSERT_TRUE(
+ SerializeNotificationDatabaseData(database_data, &serialized_data));
+
+ NotificationDatabaseData copied_data;
+ ASSERT_TRUE(
+ DeserializeNotificationDatabaseData(serialized_data, &copied_data));
+
+ EXPECT_EQ(action_type, copied_data.notification_data.actions[0].type);
}
}
@@ -135,4 +186,26 @@ TEST(NotificationDatabaseDataTest, SerializeAndDeserializeDirections) {
}
}
+TEST(NotificationDatabaseDataTest, SerializeAndDeserializeNullPlaceholder) {
+ PlatformNotificationAction action;
+ action.type = kNotificationActionType;
+ action.placeholder = base::NullableString16(); // null string.
+
+ PlatformNotificationData notification_data;
+ notification_data.actions.push_back(action);
+
+ NotificationDatabaseData database_data;
+ database_data.notification_data = notification_data;
+
+ std::string serialized_data;
+ ASSERT_TRUE(
+ SerializeNotificationDatabaseData(database_data, &serialized_data));
+
+ NotificationDatabaseData copied_data;
+ ASSERT_TRUE(
+ DeserializeNotificationDatabaseData(serialized_data, &copied_data));
+
+ EXPECT_TRUE(copied_data.notification_data.actions[0].placeholder.is_null());
+}
+
} // namespace content
diff --git a/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
index d48491ce2b8..032d50362f5 100644
--- a/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -10,32 +10,47 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_database_data.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/platform_notification_data.h"
namespace content {
namespace {
-using NotificationClickDispatchCompleteCallback =
- NotificationEventDispatcher::NotificationClickDispatchCompleteCallback;
+using NotificationDispatchCompleteCallback =
+ NotificationEventDispatcher::NotificationDispatchCompleteCallback;
+using NotificationOperationCallback =
+ base::Callback<void(const ServiceWorkerRegistration*,
+ const NotificationDatabaseData&)>;
+using NotificationOperationCallbackWithContext =
+ base::Callback<void(const scoped_refptr<PlatformNotificationContext>&,
+ const ServiceWorkerRegistration*,
+ const NotificationDatabaseData&)>;
-// To be called when the notificationclick event has finished executing. Will
-// post a task to call |dispatch_complete_callback| on the UI thread.
-void NotificationClickEventFinished(
- const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
- const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
- ServiceWorkerStatusCode service_worker_status) {
+// To be called when a notification event has finished executing. Will post a
+// task to call |dispatch_complete_callback| on the UI thread.
+void NotificationEventFinished(
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ PersistentNotificationStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(dispatch_complete_callback, status));
+}
+
+// To be called when a notification event has finished with a
+// ServiceWorkerStatusCode result. Will call NotificationEventFinished with a
+// PersistentNotificationStatus derived from the service worker status.
+void ServiceWorkerNotificationEventFinished(
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ ServiceWorkerStatusCode service_worker_status) {
#if defined(OS_ANDROID)
// This LOG(INFO) deliberately exists to help track down the cause of
// https://crbug.com/534537, where notifications sometimes do not react to
// the user clicking on them. It should be removed once that's fixed.
- LOG(INFO) << "The notificationclick event has finished: "
- << service_worker_status;
+ LOG(INFO) << "The notification event has finished: " << service_worker_status;
#endif
PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
@@ -67,17 +82,17 @@ void NotificationClickEventFinished(
status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
break;
}
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(dispatch_complete_callback, status));
+ NotificationEventFinished(dispatch_complete_callback, status);
}
-// Dispatches the notificationclick on |service_worker_registration| if the
-// registration was available. Must be called on the IO thread.
-void DispatchNotificationClickEventOnRegistration(
+// Dispatches the given notification action event on
+// |service_worker_registration| if the registration was available. Must be
+// called on the IO thread.
+void DispatchNotificationEventOnRegistration(
const NotificationDatabaseData& notification_database_data,
- int action_index,
- const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const NotificationOperationCallback& dispatch_event_action,
+ const NotificationDispatchCompleteCallback& dispatch_error_callback,
ServiceWorkerStatusCode service_worker_status,
const scoped_refptr<ServiceWorkerRegistration>&
service_worker_registration) {
@@ -87,18 +102,13 @@ void DispatchNotificationClickEventOnRegistration(
// https://crbug.com/534537, where notifications sometimes do not react to
// the user clicking on them. It should be removed once that's fixed.
LOG(INFO) << "Trying to dispatch notification for SW with status: "
- << service_worker_status << " action_index: " << action_index;
+ << service_worker_status;
#endif
if (service_worker_status == SERVICE_WORKER_OK) {
- base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
- base::Bind(&NotificationClickEventFinished, dispatch_complete_callback,
- service_worker_registration);
-
DCHECK(service_worker_registration->active_version());
- service_worker_registration->active_version()
- ->DispatchNotificationClickEvent(
- dispatch_event_callback, notification_database_data.notification_id,
- notification_database_data.notification_data, action_index);
+
+ dispatch_event_action.Run(service_worker_registration.get(),
+ notification_database_data);
return;
}
@@ -133,16 +143,17 @@ void DispatchNotificationClickEventOnRegistration(
}
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(dispatch_complete_callback, status));
+ base::Bind(dispatch_error_callback, status));
}
// Finds the ServiceWorkerRegistration associated with the |origin| and
// |service_worker_registration_id|. Must be called on the IO thread.
void FindServiceWorkerRegistration(
const GURL& origin,
- int action_index,
- const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const NotificationOperationCallback& notification_action_callback,
+ const NotificationDispatchCompleteCallback& dispatch_error_callback,
bool success,
const NotificationDatabaseData& notification_database_data) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -151,22 +162,21 @@ void FindServiceWorkerRegistration(
// This LOG(INFO) deliberately exists to help track down the cause of
// https://crbug.com/534537, where notifications sometimes do not react to
// the user clicking on them. It should be removed once that's fixed.
- LOG(INFO) << "Lookup for ServiceWoker Registration: success:" << success
- << " action_index: " << action_index;
+ LOG(INFO) << "Lookup for ServiceWoker Registration: success: " << success;
#endif
if (!success) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(dispatch_complete_callback,
+ base::Bind(dispatch_error_callback,
PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR));
return;
}
service_worker_context->FindReadyRegistrationForId(
notification_database_data.service_worker_registration_id, origin,
- base::Bind(&DispatchNotificationClickEventOnRegistration,
- notification_database_data, action_index,
- dispatch_complete_callback));
+ base::Bind(&DispatchNotificationEventOnRegistration,
+ notification_database_data, notification_context,
+ notification_action_callback, dispatch_error_callback));
}
// Reads the data associated with the |persistent_notification_id| belonging to
@@ -174,41 +184,140 @@ void FindServiceWorkerRegistration(
void ReadNotificationDatabaseData(
int64_t persistent_notification_id,
const GURL& origin,
- int action_index,
- const NotificationClickDispatchCompleteCallback& dispatch_complete_callback,
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
- scoped_refptr<PlatformNotificationContextImpl> notification_context) {
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const NotificationOperationCallback& notification_read_callback,
+ const NotificationDispatchCompleteCallback& dispatch_error_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
notification_context->ReadNotificationData(
persistent_notification_id, origin,
- base::Bind(&FindServiceWorkerRegistration, origin, action_index,
- dispatch_complete_callback, service_worker_context));
+ base::Bind(&FindServiceWorkerRegistration, origin, service_worker_context,
+ notification_context, notification_read_callback,
+ dispatch_error_callback));
}
-} // namespace
+// -----------------------------------------------------------------------------
-// static
-NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() {
- return NotificationEventDispatcherImpl::GetInstance();
+// Dispatches the notificationclick event on |service_worker|. Must be called on
+// the IO thread, and with the worker running.
+void DispatchNotificationClickEventOnWorker(
+ const scoped_refptr<ServiceWorkerVersion>& service_worker,
+ const NotificationDatabaseData& notification_database_data,
+ int action_index,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int request_id = service_worker->StartRequest(
+ ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, callback);
+ service_worker->DispatchSimpleEvent<
+ ServiceWorkerHostMsg_NotificationClickEventFinished>(
+ request_id,
+ ServiceWorkerMsg_NotificationClickEvent(
+ request_id, notification_database_data.notification_id,
+ notification_database_data.notification_data, action_index));
}
-NotificationEventDispatcherImpl*
-NotificationEventDispatcherImpl::GetInstance() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return base::Singleton<NotificationEventDispatcherImpl>::get();
+// Dispatches the notification click event on the |service_worker_registration|.
+void DoDispatchNotificationClickEvent(
+ int action_index,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const ServiceWorkerRegistration* service_worker_registration,
+ const NotificationDatabaseData& notification_database_data) {
+ ServiceWorkerVersion::StatusCallback status_callback = base::Bind(
+ &ServiceWorkerNotificationEventFinished, dispatch_complete_callback);
+ service_worker_registration->active_version()->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK,
+ base::Bind(
+ &DispatchNotificationClickEventOnWorker,
+ make_scoped_refptr(service_worker_registration->active_version()),
+ notification_database_data, action_index, status_callback),
+ status_callback);
}
-NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() {}
+// -----------------------------------------------------------------------------
-NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() {}
+// Called when the notification data has been deleted to finish the notification
+// close event.
+void OnPersistentNotificationDataDeleted(
+ ServiceWorkerStatusCode service_worker_status,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ bool success) {
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ ServiceWorkerNotificationEventFinished(dispatch_complete_callback,
+ service_worker_status);
+ return;
+ }
+ NotificationEventFinished(
+ dispatch_complete_callback,
+ success ? PERSISTENT_NOTIFICATION_STATUS_SUCCESS
+ : PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR);
+}
-void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
+// Called when the persistent notification close event has been handled
+// to remove the notification from the database.
+void DeleteNotificationDataFromDatabase(
+ const int64_t notification_id,
+ const GURL& origin,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ ServiceWorkerStatusCode status_code) {
+ notification_context->DeleteNotificationData(
+ notification_id, origin,
+ base::Bind(&OnPersistentNotificationDataDeleted, status_code,
+ dispatch_complete_callback));
+}
+
+// Dispatches the notificationclose event on |service_worker|. Must be called on
+// the IO thread, and with the worker running.
+void DispatchNotificationCloseEventOnWorker(
+ const scoped_refptr<ServiceWorkerVersion>& service_worker,
+ const NotificationDatabaseData& notification_database_data,
+ const ServiceWorkerVersion::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int request_id = service_worker->StartRequest(
+ ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, callback);
+ service_worker->DispatchSimpleEvent<
+ ServiceWorkerHostMsg_NotificationCloseEventFinished>(
+ request_id, ServiceWorkerMsg_NotificationCloseEvent(
+ request_id, notification_database_data.notification_id,
+ notification_database_data.notification_data));
+}
+
+// Actually dispatches the notification close event on the service worker
+// registration.
+void DoDispatchNotificationCloseEvent(
+ bool by_user,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback,
+ const scoped_refptr<PlatformNotificationContext>& notification_context,
+ const ServiceWorkerRegistration* service_worker_registration,
+ const NotificationDatabaseData& notification_database_data) {
+ const ServiceWorkerVersion::StatusCallback dispatch_event_callback =
+ base::Bind(&DeleteNotificationDataFromDatabase,
+ notification_database_data.notification_id,
+ notification_database_data.origin, notification_context,
+ dispatch_complete_callback);
+ if (by_user) {
+ service_worker_registration->active_version()->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE,
+ base::Bind(
+ &DispatchNotificationCloseEventOnWorker,
+ make_scoped_refptr(service_worker_registration->active_version()),
+ notification_database_data, dispatch_event_callback),
+ dispatch_event_callback);
+ } else {
+ dispatch_event_callback.Run(ServiceWorkerStatusCode::SERVICE_WORKER_OK);
+ }
+}
+
+// Dispatches any notification event. The actual, specific event dispatch should
+// be done by the |notification_action_callback|.
+void DispatchNotificationEvent(
BrowserContext* browser_context,
int64_t persistent_notification_id,
const GURL& origin,
- int action_index,
- const NotificationClickDispatchCompleteCallback&
- dispatch_complete_callback) {
+ const NotificationOperationCallbackWithContext&
+ notification_action_callback,
+ const NotificationDispatchCompleteCallback& notification_error_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_GT(persistent_notification_id, 0);
DCHECK(origin.is_valid());
@@ -219,15 +328,57 @@ void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
static_cast<ServiceWorkerContextWrapper*>(
partition->GetServiceWorkerContext());
- scoped_refptr<PlatformNotificationContextImpl> notification_context =
- static_cast<PlatformNotificationContextImpl*>(
- partition->GetPlatformNotificationContext());
+ scoped_refptr<PlatformNotificationContext> notification_context =
+ partition->GetPlatformNotificationContext();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ReadNotificationDatabaseData, persistent_notification_id,
- origin, action_index, dispatch_complete_callback,
- service_worker_context, notification_context));
+ origin, service_worker_context, notification_context,
+ base::Bind(notification_action_callback, notification_context),
+ notification_error_callback));
+}
+
+} // namespace
+
+// static
+NotificationEventDispatcher* NotificationEventDispatcher::GetInstance() {
+ return NotificationEventDispatcherImpl::GetInstance();
+}
+
+NotificationEventDispatcherImpl*
+NotificationEventDispatcherImpl::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return base::Singleton<NotificationEventDispatcherImpl>::get();
+}
+
+NotificationEventDispatcherImpl::NotificationEventDispatcherImpl() {}
+
+NotificationEventDispatcherImpl::~NotificationEventDispatcherImpl() {}
+
+void NotificationEventDispatcherImpl::DispatchNotificationClickEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ int action_index,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback) {
+ DispatchNotificationEvent(
+ browser_context, persistent_notification_id, origin,
+ base::Bind(&DoDispatchNotificationClickEvent, action_index,
+ dispatch_complete_callback),
+ dispatch_complete_callback);
+}
+
+void NotificationEventDispatcherImpl::DispatchNotificationCloseEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ bool by_user,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback) {
+ DispatchNotificationEvent(browser_context, persistent_notification_id, origin,
+ base::Bind(&DoDispatchNotificationCloseEvent,
+ by_user, dispatch_complete_callback),
+ dispatch_complete_callback);
}
} // namespace content
diff --git a/chromium/content/browser/notifications/notification_event_dispatcher_impl.h b/chromium/content/browser/notifications/notification_event_dispatcher_impl.h
index fbc5d429f27..fc19dc9ed77 100644
--- a/chromium/content/browser/notifications/notification_event_dispatcher_impl.h
+++ b/chromium/content/browser/notifications/notification_event_dispatcher_impl.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "content/public/browser/notification_database_data.h"
#include "content/public/browser/notification_event_dispatcher.h"
namespace content {
@@ -25,8 +26,15 @@ class NotificationEventDispatcherImpl : public NotificationEventDispatcher {
int64_t persistent_notification_id,
const GURL& origin,
int action_index,
- const NotificationClickDispatchCompleteCallback&
- dispatch_complete_callback) override;
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback)
+ override;
+ void DispatchNotificationCloseEvent(
+ BrowserContext* browser_context,
+ int64_t persistent_notification_id,
+ const GURL& origin,
+ bool by_user,
+ const NotificationDispatchCompleteCallback& dispatch_complete_callback)
+ override;
private:
NotificationEventDispatcherImpl();
diff --git a/chromium/content/browser/notifications/notification_message_filter.cc b/chromium/content/browser/notifications/notification_message_filter.cc
index f8c3ba89435..08297505482 100644
--- a/chromium/content/browser/notifications/notification_message_filter.cc
+++ b/chromium/content/browser/notifications/notification_message_filter.cc
@@ -45,6 +45,27 @@ PlatformNotificationData SanitizeNotificationData(
return sanitized_data;
}
+// Returns true when |resources| looks ok, false otherwise.
+bool ValidateNotificationResources(const NotificationResources& resources) {
+ if (resources.notification_icon.width() >
+ kPlatformNotificationMaxIconSizePx ||
+ resources.notification_icon.height() >
+ kPlatformNotificationMaxIconSizePx) {
+ return false;
+ }
+ if (resources.badge.width() > kPlatformNotificationMaxBadgeSizePx ||
+ resources.badge.height() > kPlatformNotificationMaxBadgeSizePx) {
+ return false;
+ }
+ for (const auto& action_icon : resources.action_icons) {
+ if (action_icon.width() > kPlatformNotificationMaxActionIconSizePx ||
+ action_icon.height() > kPlatformNotificationMaxActionIconSizePx) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
NotificationMessageFilter::NotificationMessageFilter(
@@ -109,12 +130,17 @@ void NotificationMessageFilter::OnCheckNotificationPermission(
void NotificationMessageFilter::OnShowPlatformNotification(
int notification_id,
const GURL& origin,
- const SkBitmap& icon,
- const PlatformNotificationData& notification_data) {
+ const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!RenderProcessHost::FromID(process_id_))
return;
+ if (!ValidateNotificationResources(notification_resources)) {
+ bad_message::ReceivedBadMessage(this, bad_message::NMF_INVALID_ARGUMENT);
+ return;
+ }
+
scoped_ptr<DesktopNotificationDelegate> delegate(
new PageNotificationDelegate(process_id_, notification_id));
@@ -126,9 +152,9 @@ void NotificationMessageFilter::OnShowPlatformNotification(
return;
base::Closure close_closure;
- service->DisplayNotification(browser_context_, origin, icon,
- SanitizeNotificationData(notification_data),
- std::move(delegate), &close_closure);
+ service->DisplayNotification(
+ browser_context_, origin, SanitizeNotificationData(notification_data),
+ notification_resources, std::move(delegate), &close_closure);
if (!close_closure.is_null())
close_closures_[notification_id] = close_closure;
@@ -138,8 +164,8 @@ void NotificationMessageFilter::OnShowPersistentNotification(
int request_id,
int64_t service_worker_registration_id,
const GURL& origin,
- const SkBitmap& icon,
- const PlatformNotificationData& notification_data) {
+ const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (GetPermissionForOriginOnIO(origin) !=
blink::WebNotificationPermissionAllowed) {
@@ -147,6 +173,11 @@ void NotificationMessageFilter::OnShowPersistentNotification(
return;
}
+ if (!ValidateNotificationResources(notification_resources)) {
+ bad_message::ReceivedBadMessage(this, bad_message::NMF_INVALID_ARGUMENT);
+ return;
+ }
+
NotificationDatabaseData database_data;
database_data.origin = origin;
database_data.service_worker_registration_id = service_worker_registration_id;
@@ -160,15 +191,15 @@ void NotificationMessageFilter::OnShowPersistentNotification(
notification_context_->WriteNotificationData(
origin, database_data,
base::Bind(&NotificationMessageFilter::DidWritePersistentNotificationData,
- weak_factory_io_.GetWeakPtr(), request_id, origin, icon,
- sanitized_notification_data));
+ weak_factory_io_.GetWeakPtr(), request_id, origin,
+ sanitized_notification_data, notification_resources));
}
void NotificationMessageFilter::DidWritePersistentNotificationData(
int request_id,
const GURL& origin,
- const SkBitmap& icon,
const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources,
bool success,
int64_t persistent_notification_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -182,8 +213,8 @@ void NotificationMessageFilter::DidWritePersistentNotificationData(
BrowserThread::UI, FROM_HERE,
base::Bind(&PlatformNotificationService::DisplayPersistentNotification,
base::Unretained(service), // The service is a singleton.
- browser_context_, persistent_notification_id, origin, icon,
- notification_data));
+ browser_context_, persistent_notification_id, origin,
+ notification_data, notification_resources));
}
Send(new PlatformNotificationMsg_DidShowPersistent(request_id, success));
diff --git a/chromium/content/browser/notifications/notification_message_filter.h b/chromium/content/browser/notifications/notification_message_filter.h
index 74ecf2f441d..a9d3e231f4d 100644
--- a/chromium/content/browser/notifications/notification_message_filter.h
+++ b/chromium/content/browser/notifications/notification_message_filter.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <map>
+#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
@@ -17,11 +18,11 @@
#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h"
class GURL;
-class SkBitmap;
namespace content {
class BrowserContext;
+struct NotificationResources;
class PlatformNotificationContextImpl;
struct PlatformNotificationData;
class PlatformNotificationService;
@@ -57,14 +58,14 @@ class NotificationMessageFilter : public BrowserMessageFilter {
void OnShowPlatformNotification(
int notification_id,
const GURL& origin,
- const SkBitmap& icon,
- const PlatformNotificationData& notification_data);
+ const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources);
void OnShowPersistentNotification(
int request_id,
int64_t service_worker_registration_id,
const GURL& origin,
- const SkBitmap& icon,
- const PlatformNotificationData& notification_data);
+ const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources);
void OnGetNotifications(int request_id,
int64_t service_worker_registration_id,
const GURL& origin,
@@ -79,8 +80,8 @@ class NotificationMessageFilter : public BrowserMessageFilter {
void DidWritePersistentNotificationData(
int request_id,
const GURL& origin,
- const SkBitmap& icon,
const PlatformNotificationData& notification_data,
+ const NotificationResources& notification_resources,
bool success,
int64_t persistent_notification_id);
diff --git a/chromium/content/browser/permissions/permission_service_context.cc b/chromium/content/browser/permissions/permission_service_context.cc
index 91bd4d04ac1..a83267a0db7 100644
--- a/chromium/content/browser/permissions/permission_service_context.cc
+++ b/chromium/content/browser/permissions/permission_service_context.cc
@@ -32,7 +32,7 @@ PermissionServiceContext::~PermissionServiceContext() {
}
void PermissionServiceContext::CreateService(
- mojo::InterfaceRequest<PermissionService> request) {
+ mojo::InterfaceRequest<blink::mojom::PermissionService> request) {
services_.push_back(new PermissionServiceImpl(this, std::move(request)));
}
diff --git a/chromium/content/browser/permissions/permission_service_context.h b/chromium/content/browser/permissions/permission_service_context.h
index 0534ae1b61d..3db134edd82 100644
--- a/chromium/content/browser/permissions/permission_service_context.h
+++ b/chromium/content/browser/permissions/permission_service_context.h
@@ -10,26 +10,33 @@
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/interface_request.h"
+namespace blink {
+namespace mojom {
+class PermissionService;
+}
+}
+
namespace content {
-class PermissionService;
class PermissionServiceImpl;
class RenderFrameHost;
class RenderProcessHost;
// Provides information to a PermissionService. It is used by the
-// PermissionService to handle request permission UI.
+// PermissionServiceImpl to handle request permission UI.
// There is one PermissionServiceContext per RenderFrameHost/RenderProcessHost
-// which owns it. It then owns all PermissionService associated to their owner.
+// which owns it. It then owns all PermissionServiceImpl associated to their
+// owner.
class PermissionServiceContext : public WebContentsObserver {
public:
explicit PermissionServiceContext(RenderFrameHost* render_frame_host);
explicit PermissionServiceContext(RenderProcessHost* render_process_host);
~PermissionServiceContext() override;
- void CreateService(mojo::InterfaceRequest<PermissionService> request);
+ void CreateService(
+ mojo::InterfaceRequest<blink::mojom::PermissionService> request);
- // Called by a PermissionService identified as |service| when it has a
+ // Called by a PermissionServiceImpl identified as |service| when it has a
// connection error in order to get unregistered and killed.
void ServiceHadConnectionError(PermissionServiceImpl* service);
diff --git a/chromium/content/browser/permissions/permission_service_impl.cc b/chromium/content/browser/permissions/permission_service_impl.cc
index ce1f25f92ad..c7f92a8d9e9 100644
--- a/chromium/content/browser/permissions/permission_service_impl.cc
+++ b/chromium/content/browser/permissions/permission_service_impl.cc
@@ -12,30 +12,35 @@
#include "content/public/browser/permission_manager.h"
#include "content/public/browser/permission_type.h"
+using blink::mojom::PermissionName;
+using blink::mojom::PermissionStatus;
+
namespace content {
namespace {
PermissionType PermissionNameToPermissionType(PermissionName name) {
switch(name) {
- case PERMISSION_NAME_GEOLOCATION:
+ case PermissionName::GEOLOCATION:
return PermissionType::GEOLOCATION;
- case PERMISSION_NAME_NOTIFICATIONS:
+ case PermissionName::NOTIFICATIONS:
return PermissionType::NOTIFICATIONS;
- case PERMISSION_NAME_PUSH_NOTIFICATIONS:
+ case PermissionName::PUSH_NOTIFICATIONS:
return PermissionType::PUSH_MESSAGING;
- case PERMISSION_NAME_MIDI:
+ case PermissionName::MIDI:
return PermissionType::MIDI;
- case PERMISSION_NAME_MIDI_SYSEX:
+ case PermissionName::MIDI_SYSEX:
return PermissionType::MIDI_SYSEX;
- case PERMISSION_NAME_PROTECTED_MEDIA_IDENTIFIER:
+ case PermissionName::PROTECTED_MEDIA_IDENTIFIER:
return PermissionType::PROTECTED_MEDIA_IDENTIFIER;
- case PERMISSION_NAME_DURABLE_STORAGE:
+ case PermissionName::DURABLE_STORAGE:
return PermissionType::DURABLE_STORAGE;
- case PERMISSION_NAME_AUDIO_CAPTURE:
+ case PermissionName::AUDIO_CAPTURE:
return PermissionType::AUDIO_CAPTURE;
- case PERMISSION_NAME_VIDEO_CAPTURE:
+ case PermissionName::VIDEO_CAPTURE:
return PermissionType::VIDEO_CAPTURE;
+ case PermissionName::BACKGROUND_SYNC:
+ return PermissionType::BACKGROUND_SYNC;
}
NOTREACHED();
@@ -67,7 +72,7 @@ PermissionServiceImpl::PendingRequest::~PendingRequest() {
mojo::Array<PermissionStatus> result =
mojo::Array<PermissionStatus>::New(request_count);
for (int i = 0; i < request_count; ++i)
- result[i] = PERMISSION_STATUS_DENIED;
+ result[i] = PermissionStatus::DENIED;
callback.Run(std::move(result));
}
@@ -83,12 +88,12 @@ PermissionServiceImpl::PendingSubscription::PendingSubscription(
PermissionServiceImpl::PendingSubscription::~PendingSubscription() {
if (!callback.is_null())
- callback.Run(PERMISSION_STATUS_ASK);
+ callback.Run(PermissionStatus::ASK);
}
PermissionServiceImpl::PermissionServiceImpl(
PermissionServiceContext* context,
- mojo::InterfaceRequest<PermissionService> request)
+ mojo::InterfaceRequest<blink::mojom::PermissionService> request)
: context_(context),
binding_(this, std::move(request)),
weak_factory_(this) {
@@ -109,7 +114,6 @@ void PermissionServiceImpl::OnConnectionError() {
void PermissionServiceImpl::RequestPermission(
PermissionName permission,
const mojo::String& origin,
- bool user_gesture,
const PermissionStatusCallback& callback) {
// This condition is valid if the call is coming from a ChildThread instead of
// a RenderFrame. Some consumers of the service run in Workers and some in
@@ -122,7 +126,7 @@ void PermissionServiceImpl::RequestPermission(
DCHECK(browser_context);
if (!context_->render_frame_host() ||
!browser_context->GetPermissionManager()) {
- callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
+ callback.Run(GetPermissionStatusFromName(permission, GURL(origin.get())));
return;
}
@@ -131,8 +135,7 @@ void PermissionServiceImpl::RequestPermission(
int id = browser_context->GetPermissionManager()->RequestPermission(
PermissionNameToPermissionType(permission),
context_->render_frame_host(),
- GURL(origin),
- user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
+ GURL(origin.get()),
base::Bind(&PermissionServiceImpl::OnRequestPermissionResponse,
weak_factory_.GetWeakPtr(),
pending_request_id));
@@ -150,13 +153,12 @@ void PermissionServiceImpl::OnRequestPermissionResponse(
int pending_request_id,
PermissionStatus status) {
OnRequestPermissionsResponse(pending_request_id,
- std::vector<PermissionStatus>(1, status));
+ std::vector<PermissionStatus>(1, status));
}
void PermissionServiceImpl::RequestPermissions(
mojo::Array<PermissionName> permissions,
const mojo::String& origin,
- bool user_gesture,
const PermissionsStatusCallback& callback) {
if (permissions.is_null()) {
callback.Run(mojo::Array<PermissionStatus>());
@@ -175,8 +177,10 @@ void PermissionServiceImpl::RequestPermissions(
if (!context_->render_frame_host() ||
!browser_context->GetPermissionManager()) {
mojo::Array<PermissionStatus> result(permissions.size());
- for (size_t i = 0; i < permissions.size(); ++i)
- result[i] = GetPermissionStatusFromName(permissions[i], GURL(origin));
+ for (size_t i = 0; i < permissions.size(); ++i) {
+ result[i] =
+ GetPermissionStatusFromName(permissions[i], GURL(origin.get()));
+ }
callback.Run(std::move(result));
return;
}
@@ -190,8 +194,7 @@ void PermissionServiceImpl::RequestPermissions(
int id = browser_context->GetPermissionManager()->RequestPermissions(
types,
context_->render_frame_host(),
- GURL(origin),
- user_gesture, // TODO(mlamouri): should be removed (crbug.com/423770)
+ GURL(origin.get()),
base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse,
weak_factory_.GetWeakPtr(),
pending_request_id));
@@ -247,21 +250,21 @@ void PermissionServiceImpl::HasPermission(
PermissionName permission,
const mojo::String& origin,
const PermissionStatusCallback& callback) {
- callback.Run(GetPermissionStatusFromName(permission, GURL(origin)));
+ callback.Run(GetPermissionStatusFromName(permission, GURL(origin.get())));
}
void PermissionServiceImpl::RevokePermission(
PermissionName permission,
const mojo::String& origin,
const PermissionStatusCallback& callback) {
- GURL origin_url(origin);
+ GURL origin_url(origin.get());
PermissionType permission_type = PermissionNameToPermissionType(permission);
- PermissionStatus status = GetPermissionStatusFromType(permission_type,
- origin_url);
+ PermissionStatus status =
+ GetPermissionStatusFromType(permission_type, origin_url);
// Resetting the permission should only be possible if the permission is
// already granted.
- if (status != PERMISSION_STATUS_GRANTED) {
+ if (status != PermissionStatus::GRANTED) {
callback.Run(status);
return;
}
@@ -276,7 +279,7 @@ void PermissionServiceImpl::GetNextPermissionChange(
const mojo::String& mojo_origin,
PermissionStatus last_known_status,
const PermissionStatusCallback& callback) {
- GURL origin(mojo_origin);
+ GURL origin(mojo_origin.get());
PermissionStatus current_status =
GetPermissionStatusFromName(permission, origin);
if (current_status != last_known_status) {
@@ -313,17 +316,19 @@ void PermissionServiceImpl::GetNextPermissionChange(
}
PermissionStatus PermissionServiceImpl::GetPermissionStatusFromName(
- PermissionName permission, const GURL& origin) {
+ PermissionName permission,
+ const GURL& origin) {
return GetPermissionStatusFromType(PermissionNameToPermissionType(permission),
origin);
}
PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType(
- PermissionType type, const GURL& origin) {
+ PermissionType type,
+ const GURL& origin) {
BrowserContext* browser_context = context_->GetBrowserContext();
DCHECK(browser_context);
if (!browser_context->GetPermissionManager())
- return PERMISSION_STATUS_DENIED;
+ return PermissionStatus::DENIED;
// If the embedding_origin is empty we'll use |origin| instead.
GURL embedding_origin = context_->GetEmbeddingOrigin();
diff --git a/chromium/content/browser/permissions/permission_service_impl.h b/chromium/content/browser/permissions/permission_service_impl.h
index 13761daca2f..dfda77549f1 100644
--- a/chromium/content/browser/permissions/permission_service_impl.h
+++ b/chromium/content/browser/permissions/permission_service_impl.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/permissions/permission_service_context.h"
-#include "content/common/permission_service.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h"
namespace content {
@@ -23,7 +23,7 @@ enum class PermissionType;
// to have some information about the current context. That enables the service
// to know whether it can show UI and have knowledge of the associated
// WebContents for example.
-class PermissionServiceImpl : public PermissionService {
+class PermissionServiceImpl : public blink::mojom::PermissionService {
public:
~PermissionServiceImpl() override;
@@ -35,13 +35,15 @@ class PermissionServiceImpl : public PermissionService {
protected:
friend PermissionServiceContext;
- PermissionServiceImpl(PermissionServiceContext* context,
- mojo::InterfaceRequest<PermissionService> request);
+ PermissionServiceImpl(
+ PermissionServiceContext* context,
+ mojo::InterfaceRequest<blink::mojom::PermissionService> request);
private:
- using PermissionStatusCallback = mojo::Callback<void(PermissionStatus)>;
+ using PermissionStatusCallback =
+ mojo::Callback<void(blink::mojom::PermissionStatus)>;
using PermissionsStatusCallback =
- mojo::Callback<void(mojo::Array<PermissionStatus>)>;
+ mojo::Callback<void(mojo::Array<blink::mojom::PermissionStatus>)>;
struct PendingRequest {
PendingRequest(const PermissionsStatusCallback& callback,
@@ -68,50 +70,49 @@ class PermissionServiceImpl : public PermissionService {
};
using SubscriptionsMap = IDMap<PendingSubscription, IDMapOwnPointer>;
- // PermissionService.
- void HasPermission(PermissionName permission,
+ // blink::mojom::PermissionService.
+ void HasPermission(blink::mojom::PermissionName permission,
const mojo::String& origin,
const PermissionStatusCallback& callback) override;
- void RequestPermission(PermissionName permission,
+ void RequestPermission(blink::mojom::PermissionName permission,
const mojo::String& origin,
- bool user_gesture,
const PermissionStatusCallback& callback) override;
- void RequestPermissions(mojo::Array<PermissionName> permissions,
+ void RequestPermissions(mojo::Array<blink::mojom::PermissionName> permissions,
const mojo::String& origin,
- bool user_gesture,
const PermissionsStatusCallback& callback) override;
- void RevokePermission(PermissionName permission,
+ void RevokePermission(blink::mojom::PermissionName permission,
const mojo::String& origin,
const PermissionStatusCallback& callback) override;
void GetNextPermissionChange(
- PermissionName permission,
+ blink::mojom::PermissionName permission,
const mojo::String& origin,
- PermissionStatus last_known_status,
+ blink::mojom::PermissionStatus last_known_status,
const PermissionStatusCallback& callback) override;
void OnConnectionError();
- void OnRequestPermissionResponse(
- int pending_request_id,
- PermissionStatus status);
+ void OnRequestPermissionResponse(int pending_request_id,
+ blink::mojom::PermissionStatus status);
void OnRequestPermissionsResponse(
int pending_request_id,
- const std::vector<PermissionStatus>& result);
-
- PermissionStatus GetPermissionStatusFromName(PermissionName permission,
- const GURL& origin);
- PermissionStatus GetPermissionStatusFromType(PermissionType type,
- const GURL& origin);
+ const std::vector<blink::mojom::PermissionStatus>& result);
+
+ blink::mojom::PermissionStatus GetPermissionStatusFromName(
+ blink::mojom::PermissionName permission,
+ const GURL& origin);
+ blink::mojom::PermissionStatus GetPermissionStatusFromType(
+ PermissionType type,
+ const GURL& origin);
void ResetPermissionStatus(PermissionType type, const GURL& origin);
void OnPermissionStatusChanged(int pending_subscription_id,
- PermissionStatus status);
+ blink::mojom::PermissionStatus status);
RequestsMap pending_requests_;
SubscriptionsMap pending_subscriptions_;
// context_ owns |this|.
PermissionServiceContext* context_;
- mojo::Binding<PermissionService> binding_;
+ mojo::Binding<blink::mojom::PermissionService> binding_;
base::WeakPtrFactory<PermissionServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PermissionServiceImpl);
diff --git a/chromium/content/browser/plugin_data_remover_impl.cc b/chromium/content/browser/plugin_data_remover_impl.cc
index fa0aab250c0..5299f6bfaea 100644
--- a/chromium/content/browser/plugin_data_remover_impl.cc
+++ b/chromium/content/browser/plugin_data_remover_impl.cc
@@ -15,11 +15,9 @@
#include "base/synchronization/waitable_event.h"
#include "base/version.h"
#include "build/build_config.h"
-#include "content/browser/plugin_process_host.h"
#include "content/browser/plugin_service_impl.h"
#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"
#include "content/common/child_process_host_impl.h"
-#include "content/common/plugin_process_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/child_process_host.h"
@@ -61,8 +59,7 @@ void PluginDataRemover::GetSupportedPlugins(
}
class PluginDataRemoverImpl::Context
- : public PluginProcessHost::Client,
- public PpapiPluginProcessHost::BrokerClient,
+ : public PpapiPluginProcessHost::BrokerClient,
public IPC::Listener,
public base::RefCountedThreadSafe<Context,
BrowserThread::DeleteOnIOThread> {
@@ -71,8 +68,7 @@ class PluginDataRemoverImpl::Context
: event_(new base::WaitableEvent(true, false)),
begin_time_(begin_time),
is_removing_(false),
- browser_context_path_(browser_context->GetPath()),
- resource_context_(browser_context->GetResourceContext()) {
+ browser_context_path_(browser_context->GetPath()) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
@@ -104,23 +100,22 @@ class PluginDataRemoverImpl::Context
base::FilePath plugin_path = plugins[0].path;
+ PepperPluginInfo* pepper_info =
+ plugin_service->GetRegisteredPpapiPluginInfo(plugin_path);
+ if (!pepper_info) {
+ event_->Signal();
+ return;
+ }
+
DCHECK_CURRENTLY_ON(BrowserThread::IO);
remove_start_time_ = base::Time::Now();
is_removing_ = true;
- // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
- // eventually be called, so we need to keep this object around until then.
- AddRef();
- PepperPluginInfo* pepper_info =
- plugin_service->GetRegisteredPpapiPluginInfo(plugin_path);
- if (pepper_info) {
- plugin_name_ = pepper_info->name;
- // Use the broker since we run this function outside the sandbox.
- plugin_service->OpenChannelToPpapiBroker(0, plugin_path, this);
- } else {
- plugin_service->OpenChannelToNpapiPlugin(
- 0, 0, GURL(), GURL(), mime_type, this);
- }
+ // Balanced in OnPpapiChannelOpened.
+ AddRef();
+ plugin_name_ = pepper_info->name;
+ // Use the broker since we run this function outside the sandbox.
+ plugin_service->OpenChannelToPpapiBroker(0, plugin_path, this);
}
// Called when a timeout happens in order not to block the client
@@ -130,35 +125,8 @@ class PluginDataRemoverImpl::Context
SignalDone();
}
- // PluginProcessHost::Client methods.
- int ID() override {
- // Generate a unique identifier for this PluginProcessHostClient.
- return ChildProcessHostImpl::GenerateChildProcessUniqueId();
- }
-
bool OffTheRecord() override { return false; }
- ResourceContext* GetResourceContext() override { return resource_context_; }
-
- void SetPluginInfo(const WebPluginInfo& info) override {}
-
- void OnFoundPluginProcessHost(PluginProcessHost* host) override {}
-
- void OnSentPluginChannelRequest() override {}
-
- void OnChannelOpened(const IPC::ChannelHandle& handle) override {
- ConnectToChannel(handle, false);
- // Balancing the AddRef call.
- Release();
- }
-
- void OnError() override {
- LOG(ERROR) << "Couldn't open plugin channel";
- SignalDone();
- // Balancing the AddRef call.
- Release();
- }
-
// PpapiPluginProcessHost::BrokerClient implementation.
void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
int* renderer_id) override {
@@ -170,7 +138,7 @@ class PluginDataRemoverImpl::Context
base::ProcessId /* peer_pid */,
int /* child_id */) override {
if (!channel_handle.name.empty())
- ConnectToChannel(channel_handle, true);
+ ConnectToChannel(channel_handle);
// Balancing the AddRef call.
Release();
@@ -179,8 +147,6 @@ class PluginDataRemoverImpl::Context
// IPC::Listener methods.
bool OnMessageReceived(const IPC::Message& message) override {
IPC_BEGIN_MESSAGE_MAP(Context, message)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ClearSiteDataResult,
- OnClearSiteDataResult)
IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult,
OnPpapiClearSiteDataResult)
IPC_MESSAGE_UNHANDLED_ERROR()
@@ -222,7 +188,7 @@ class PluginDataRemoverImpl::Context
}
// Connects the client side of a newly opened plugin channel.
- void ConnectToChannel(const IPC::ChannelHandle& handle, bool is_ppapi) {
+ void ConnectToChannel(const IPC::ChannelHandle& handle) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If we timed out, don't bother connecting.
@@ -241,13 +207,7 @@ class PluginDataRemoverImpl::Context
? std::numeric_limits<uint64_t>::max()
: (base::Time::Now() - begin_time_).InSeconds();
- IPC::Message* msg;
- if (is_ppapi) {
- msg = CreatePpapiClearSiteDataMsg(max_age);
- } else {
- msg = new PluginProcessMsg_ClearSiteData(
- std::string(), kClearAllData, max_age);
- }
+ IPC::Message* msg = CreatePpapiClearSiteDataMsg(max_age);
if (!channel_->Send(msg)) {
NOTREACHED() << "Couldn't send ClearSiteData message";
SignalDone();
@@ -255,15 +215,9 @@ class PluginDataRemoverImpl::Context
}
}
- // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
- // PluginProcessHostMsg_ClearSiteDataResult handler.
+ // Handles the PpapiHostMsg_ClearSiteDataResult message.
void OnPpapiClearSiteDataResult(uint32_t request_id, bool success) {
DCHECK_EQ(0u, request_id);
- OnClearSiteDataResult(success);
- }
-
- // Handles the PluginProcessHostMsg_ClearSiteDataResult message.
- void OnClearSiteDataResult(bool success) {
LOG_IF(ERROR, !success) << "ClearSiteData returned error";
UMA_HISTOGRAM_TIMES("ClearPluginData.time",
base::Time::Now() - remove_start_time_);
@@ -291,9 +245,6 @@ class PluginDataRemoverImpl::Context
// browser context when we start so we can use it later on the I/O thread.
base::FilePath browser_context_path_;
- // The resource context for the profile. Use only on the I/O thread.
- ResourceContext* resource_context_;
-
// The name of the plugin. Use only on the I/O thread.
std::string plugin_name_;
diff --git a/chromium/content/browser/plugin_loader_posix.cc b/chromium/content/browser/plugin_loader_posix.cc
deleted file mode 100644
index dcfb55812ef..00000000000
--- a/chromium/content/browser/plugin_loader_posix.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/plugin_loader_posix.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/metrics/histogram.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "content/browser/utility_process_host_impl.h"
-#include "content/common/child_process_host_impl.h"
-#include "content/common/plugin_list.h"
-#include "content/common/utility_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/plugin_service.h"
-#include "content/public/browser/user_metrics.h"
-
-namespace content {
-
-PluginLoaderPosix::PluginLoaderPosix()
- : next_load_index_(0), loading_plugins_(false) {
-}
-
-void PluginLoaderPosix::GetPlugins(
- const PluginService::GetPluginsCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- std::vector<WebPluginInfo> cached_plugins;
- if (PluginList::Singleton()->GetPluginsNoRefresh(&cached_plugins)) {
- // Can't assume the caller is reentrant.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, cached_plugins));
- return;
- }
-
- if (!loading_plugins_) {
- loading_plugins_ = true;
- callbacks_.push_back(callback);
-
- // When |loading_plugins_| is set to false, this instance must call
- // SetPlugins().
- PluginList::Singleton()->PrepareForPluginLoading();
-
- BrowserThread::PostTask(BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&PluginLoaderPosix::GetPluginsToLoad,
- make_scoped_refptr(this)));
- } else {
- // If we are currently loading plugins, the plugin list might have been
- // invalidated in the mean time, or might get invalidated before we finish.
- // We'll wait until we have finished the current run, then try to get them
- // again from the plugin list. If it has indeed been invalidated, it will
- // restart plugin loading, otherwise it will immediately run the callback.
- callbacks_.push_back(base::Bind(&PluginLoaderPosix::GetPluginsWrapper,
- make_scoped_refptr(this), callback));
- }
-}
-
-bool PluginLoaderPosix::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PluginLoaderPosix, message)
- IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadedPlugin, OnPluginLoaded)
- IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadPluginFailed, OnPluginLoadFailed)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PluginLoaderPosix::OnProcessCrashed(int exit_code) {
- RecordAction(
- base::UserMetricsAction("PluginLoaderPosix.UtilityProcessCrashed"));
-
- if (next_load_index_ == canonical_list_.size()) {
- // How this case occurs is unknown. See crbug.com/111935.
- canonical_list_.clear();
- } else {
- canonical_list_.erase(canonical_list_.begin(),
- canonical_list_.begin() + next_load_index_ + 1);
- }
-
- next_load_index_ = 0;
-
- LoadPluginsInternal();
-}
-
-void PluginLoaderPosix::OnProcessLaunchFailed() {
- FinishedLoadingPlugins();
-}
-
-bool PluginLoaderPosix::Send(IPC::Message* message) {
- if (process_host_.get())
- return process_host_->Send(message);
- return false;
-}
-
-PluginLoaderPosix::~PluginLoaderPosix() {
-}
-
-void PluginLoaderPosix::GetPluginsToLoad() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
- base::TimeTicks start_time(base::TimeTicks::Now());
-
- loaded_plugins_.clear();
- next_load_index_ = 0;
-
- canonical_list_.clear();
- PluginList::Singleton()->GetPluginPathsToLoad(
- &canonical_list_,
- PluginService::GetInstance()->NPAPIPluginsSupported());
-
- internal_plugins_.clear();
- PluginList::Singleton()->GetInternalPlugins(&internal_plugins_);
-
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&PluginLoaderPosix::LoadPluginsInternal,
- make_scoped_refptr(this)));
-
- LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
- (base::TimeTicks::Now() - start_time) *
- base::Time::kMicrosecondsPerMillisecond);
-}
-
-void PluginLoaderPosix::LoadPluginsInternal() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // Check if the list is empty or all plugins have already been loaded before
- // forking.
- if (IsFinishedLoadingPlugins()) {
- FinishedLoadingPlugins();
- return;
- }
-
- RecordAction(
- base::UserMetricsAction("PluginLoaderPosix.LaunchUtilityProcess"));
-
- UtilityProcessHostImpl* host = new UtilityProcessHostImpl(
- this,
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get());
- process_host_ = host->AsWeakPtr();
- process_host_->DisableSandbox();
-
- bool launched = LaunchUtilityProcess();
- if (!launched) {
- // The utility process either failed to start or failed to receive the IPC.
- // This process will never receive any callbacks for OnPluginLoaded() or
- // OnPluginLoadFailed().
- FinishedLoadingPlugins();
- }
-}
-
-void PluginLoaderPosix::GetPluginsWrapper(
- const PluginService::GetPluginsCallback& callback,
- const std::vector<WebPluginInfo>& plugins_unused) {
- // We are being called after plugin loading has finished, but we don't know
- // whether the plugin list has been invalidated in the mean time
- // (and therefore |plugins| might already be stale). So we simply ignore it
- // and call regular GetPlugins() instead.
- GetPlugins(callback);
-}
-
-void PluginLoaderPosix::OnPluginLoaded(uint32_t index,
- const WebPluginInfo& plugin) {
- if (index != next_load_index_) {
- LOG(ERROR) << "Received unexpected plugin load message for "
- << plugin.path.value() << "; index=" << index;
- return;
- }
-
- auto it = FindInternalPlugin(plugin.path);
- if (it != internal_plugins_.end()) {
- loaded_plugins_.push_back(*it);
- internal_plugins_.erase(it);
- } else {
- loaded_plugins_.push_back(plugin);
- }
-
- ++next_load_index_;
-
- if (IsFinishedLoadingPlugins())
- FinishedLoadingPlugins();
-}
-
-void PluginLoaderPosix::OnPluginLoadFailed(uint32_t index,
- const base::FilePath& plugin_path) {
- if (index != next_load_index_) {
- LOG(ERROR) << "Received unexpected plugin load failure message for "
- << plugin_path.value() << "; index=" << index;
- return;
- }
-
- ++next_load_index_;
-
- auto it = FindInternalPlugin(plugin_path);
- if (it != internal_plugins_.end()) {
- loaded_plugins_.push_back(*it);
- internal_plugins_.erase(it);
- }
-
- if (IsFinishedLoadingPlugins())
- FinishedLoadingPlugins();
-}
-
-std::vector<WebPluginInfo>::iterator PluginLoaderPosix::FindInternalPlugin(
- const base::FilePath& plugin_path) {
- return std::find_if(internal_plugins_.begin(), internal_plugins_.end(),
- [&plugin_path](const WebPluginInfo& plugin) {
- return plugin.path == plugin_path;
- });
-}
-
-bool PluginLoaderPosix::IsFinishedLoadingPlugins() {
- if (canonical_list_.empty())
- return true;
-
- DCHECK(next_load_index_ <= canonical_list_.size());
- return next_load_index_ == canonical_list_.size();
-}
-
-void PluginLoaderPosix::FinishedLoadingPlugins() {
- loading_plugins_ = false;
- PluginList::Singleton()->SetPlugins(loaded_plugins_);
-
- for (auto& callback : callbacks_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, loaded_plugins_));
- }
- callbacks_.clear();
-}
-
-bool PluginLoaderPosix::LaunchUtilityProcess() {
- return process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/plugin_loader_posix.h b/chromium/content/browser/plugin_loader_posix.h
deleted file mode 100644
index 51814131fcf..00000000000
--- a/chromium/content/browser/plugin_loader_posix.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_PLUGIN_LOADER_POSIX_H_
-#define CONTENT_BROWSER_PLUGIN_LOADER_POSIX_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "content/browser/plugin_service_impl.h"
-#include "content/public/browser/utility_process_host_client.h"
-#include "content/public/common/webplugininfo.h"
-#include "ipc/ipc_sender.h"
-
-namespace content {
-class UtilityProcessHost;
-
-// This class is responsible for managing the out-of-process plugin loading on
-// POSIX systems. It primarily lives on the IO thread, but has a brief stay on
-// the FILE thread to iterate over plugin directories when it is first
-// constructed.
-//
-// The following is the algorithm used to load plugins:
-// 1. This asks the PluginList for the list of all potential plugins to attempt
-// to load. This is referred to as the canonical list.
-// 2. The child process this hosts is forked and the canonical list is sent to
-// it.
-// 3. The child process iterates over the canonical list, attempting to load
-// each plugin in the order specified by the list. It sends an IPC message
-// to the browser after each load, indicating success or failure. The two
-// processes synchronize the position in the vector that will be used to
-// attempt to load the next plugin.
-// 4. If the child dies during this process, the host forks another child and
-// resumes loading at the position past the plugin that it just attempted to
-// load, bypassing the problematic plugin.
-// 5. This algorithm continues until the canonical list has been walked to the
-// end, after which the list of loaded plugins is set on the PluginList and
-// the completion callback is run.
-class CONTENT_EXPORT PluginLoaderPosix
- : public NON_EXPORTED_BASE(UtilityProcessHostClient),
- public IPC::Sender {
- public:
- PluginLoaderPosix();
-
- // Must be called from the IO thread. The |callback| will be called on the IO
- // thread too.
- void GetPlugins(const PluginService::GetPluginsCallback& callback);
-
- // UtilityProcessHostClient:
- void OnProcessCrashed(int exit_code) override;
- void OnProcessLaunchFailed() override;
- bool OnMessageReceived(const IPC::Message& message) override;
-
- // IPC::Sender:
- bool Send(IPC::Message* msg) override;
-
- private:
- ~PluginLoaderPosix() override;
-
- // Called on the FILE thread to get the list of plugin paths to probe.
- void GetPluginsToLoad();
-
- // Must be called on the IO thread.
- virtual void LoadPluginsInternal();
-
- // Called after plugin loading has finished, if we don't know whether the
- // plugin list has been invalidated in the mean time.
- void GetPluginsWrapper(
- const PluginService::GetPluginsCallback& callback,
- const std::vector<WebPluginInfo>& plugins_unused);
-
- // Message handlers.
- void OnPluginLoaded(uint32_t index, const WebPluginInfo& plugin);
- void OnPluginLoadFailed(uint32_t index, const base::FilePath& plugin_path);
-
- // Returns an iterator to the plugin in |internal_plugins_| whose path
- // matches |plugin_path|.
- std::vector<WebPluginInfo>::iterator FindInternalPlugin(
- const base::FilePath& plugin_path);
-
- // Runs all the registered callbacks on each's target loop if the condition
- // for ending the load process is done (i.e. the |next_load_index_| is outside
- // the range of the |canonical_list_|).
- bool MaybeRunPendingCallbacks();
-
- // Returns true if there are no plugins left to load.
- bool IsFinishedLoadingPlugins();
-
- // This method should be called when the plugins are finished loading.
- // It updates the PluginList's list of plugins, and runs the queued callbacks.
- void FinishedLoadingPlugins();
-
- // Launches the utility process that loads the plugins.
- // Virtual for testing.
- virtual bool LaunchUtilityProcess();
-
- // The process host for which this is a client.
- base::WeakPtr<UtilityProcessHost> process_host_;
-
- // A list of paths to plugins which will be loaded by the utility process, in
- // the order specified by this vector.
- std::vector<base::FilePath> canonical_list_;
-
- // The index in |canonical_list_| of the plugin that the child process will
- // attempt to load next.
- size_t next_load_index_;
-
- // Internal plugins that have been registered at the time of loading.
- std::vector<WebPluginInfo> internal_plugins_;
-
- // A vector of plugins that have been loaded successfully.
- std::vector<WebPluginInfo> loaded_plugins_;
-
- // The callback and message loop on which the callback will be run when the
- // plugin loading process has been completed.
- std::vector<PluginService::GetPluginsCallback> callbacks_;
-
- // True if there is (or is about to be) a utility process that loads plugins.
- bool loading_plugins_;
-
- friend class MockPluginLoaderPosix;
- DISALLOW_COPY_AND_ASSIGN(PluginLoaderPosix);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_PLUGIN_LOADER_POSIX_H_
diff --git a/chromium/content/browser/plugin_loader_posix_unittest.cc b/chromium/content/browser/plugin_loader_posix_unittest.cc
deleted file mode 100644
index ec1fa0b51f7..00000000000
--- a/chromium/content/browser/plugin_loader_posix_unittest.cc
+++ /dev/null
@@ -1,426 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/plugin_loader_posix.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/browser_thread_impl.h"
-#include "content/common/plugin_list.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
-
-namespace content {
-
-class MockPluginLoaderPosix : public PluginLoaderPosix {
- public:
- MOCK_METHOD0(LoadPluginsInternal, void(void));
-
- size_t number_of_pending_callbacks() {
- return callbacks_.size();
- }
-
- std::vector<base::FilePath>* canonical_list() {
- return &canonical_list_;
- }
-
- size_t next_load_index() {
- return next_load_index_;
- }
-
- const std::vector<WebPluginInfo>& loaded_plugins() {
- return loaded_plugins_;
- }
-
- std::vector<WebPluginInfo>* internal_plugins() {
- return &internal_plugins_;
- }
-
- void RealLoadPluginsInternal() {
- PluginLoaderPosix::LoadPluginsInternal();
- }
-
- bool LaunchUtilityProcess() override {
- // This method always does nothing and returns false. The actual
- // implementation of this method launches another process, which is not
- // very unit_test friendly.
- return false;
- }
-
- void TestOnPluginLoaded(uint32_t index, const WebPluginInfo& plugin) {
- OnPluginLoaded(index, plugin);
- }
-
- void TestOnPluginLoadFailed(uint32_t index, const base::FilePath& path) {
- OnPluginLoadFailed(index, path);
- }
-
- protected:
- virtual ~MockPluginLoaderPosix() {}
-};
-
-void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) {
- ++(*run_count);
-}
-
-class PluginLoaderPosixTest : public testing::Test {
- public:
- PluginLoaderPosixTest()
- : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"),
- ASCIIToUTF16("1.0"), base::string16()),
- plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"),
- ASCIIToUTF16("2.0"), base::string16()),
- plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"),
- ASCIIToUTF16("3.0"), base::string16()),
- file_thread_(BrowserThread::FILE, &message_loop_),
- io_thread_(BrowserThread::IO, &message_loop_),
- plugin_loader_(new MockPluginLoaderPosix) {
- }
-
- void SetUp() override { PluginServiceImpl::GetInstance()->Init(); }
-
- base::MessageLoop* message_loop() { return &message_loop_; }
- MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); }
-
- void AddThreePlugins() {
- plugin_loader_->canonical_list()->clear();
- plugin_loader_->canonical_list()->push_back(plugin1_.path);
- plugin_loader_->canonical_list()->push_back(plugin2_.path);
- plugin_loader_->canonical_list()->push_back(plugin3_.path);
- }
-
- // Data used for testing.
- WebPluginInfo plugin1_;
- WebPluginInfo plugin2_;
- WebPluginInfo plugin3_;
-
- private:
- // Destroys PluginService and PluginList.
- base::ShadowingAtExitManager at_exit_manager_;
-
- base::MessageLoopForIO message_loop_;
- BrowserThreadImpl file_thread_;
- BrowserThreadImpl io_thread_;
-
- scoped_refptr<MockPluginLoaderPosix> plugin_loader_;
-};
-
-TEST_F(PluginLoaderPosixTest, QueueRequests) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->canonical_list()->clear();
- plugin_loader()->canonical_list()->push_back(plugin1_.path);
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- message_loop()->RunUntilIdle();
-
- EXPECT_EQ(2, did_callback);
-}
-
-TEST_F(PluginLoaderPosixTest, QueueRequestsAndInvalidate) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- EXPECT_EQ(0, did_callback);
- ::testing::Mock::VerifyAndClearExpectations(plugin_loader());
-
- // Invalidate the plugin list, then queue up another request.
- PluginList::Singleton()->RefreshPlugins();
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
-
- plugin_loader()->canonical_list()->clear();
- plugin_loader()->canonical_list()->push_back(plugin1_.path);
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- message_loop()->RunUntilIdle();
-
- // Only the first request should have been fulfilled.
- EXPECT_EQ(1, did_callback);
-
- plugin_loader()->canonical_list()->clear();
- plugin_loader()->canonical_list()->push_back(plugin1_.path);
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- message_loop()->RunUntilIdle();
-
- EXPECT_EQ(2, did_callback);
-}
-
-TEST_F(PluginLoaderPosixTest, ThreeSuccessfulLoads) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- AddThreePlugins();
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
-
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- EXPECT_EQ(1u, plugin_loader()->next_load_index());
- EXPECT_EQ(1u, plugins.size());
- EXPECT_EQ(plugin1_.name, plugins[0].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(1, plugin2_);
- EXPECT_EQ(2u, plugin_loader()->next_load_index());
- EXPECT_EQ(2u, plugins.size());
- EXPECT_EQ(plugin2_.name, plugins[1].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(2, plugin3_);
- EXPECT_EQ(3u, plugins.size());
- EXPECT_EQ(plugin3_.name, plugins[2].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
-}
-
-TEST_F(PluginLoaderPosixTest, ThreeSuccessfulLoadsThenCrash) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
- message_loop()->RunUntilIdle();
-
- AddThreePlugins();
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
-
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- EXPECT_EQ(1u, plugin_loader()->next_load_index());
- EXPECT_EQ(1u, plugins.size());
- EXPECT_EQ(plugin1_.name, plugins[0].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(1, plugin2_);
- EXPECT_EQ(2u, plugin_loader()->next_load_index());
- EXPECT_EQ(2u, plugins.size());
- EXPECT_EQ(plugin2_.name, plugins[1].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(2, plugin3_);
- EXPECT_EQ(3u, plugins.size());
- EXPECT_EQ(plugin3_.name, plugins[2].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
-
- plugin_loader()->OnProcessCrashed(42);
-}
-
-TEST_F(PluginLoaderPosixTest, TwoFailures) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- AddThreePlugins();
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
-
- plugin_loader()->TestOnPluginLoadFailed(0, plugin1_.path);
- EXPECT_EQ(1u, plugin_loader()->next_load_index());
- EXPECT_EQ(0u, plugins.size());
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(1, plugin2_);
- EXPECT_EQ(2u, plugin_loader()->next_load_index());
- EXPECT_EQ(1u, plugins.size());
- EXPECT_EQ(plugin2_.name, plugins[0].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoadFailed(2, plugin3_.path);
- EXPECT_EQ(1u, plugins.size());
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
-}
-
-TEST_F(PluginLoaderPosixTest, CrashedProcess) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- AddThreePlugins();
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
-
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- EXPECT_EQ(1u, plugin_loader()->next_load_index());
- EXPECT_EQ(1u, plugins.size());
- EXPECT_EQ(plugin1_.name, plugins[0].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- plugin_loader()->OnProcessCrashed(42);
- EXPECT_EQ(1u, plugin_loader()->canonical_list()->size());
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
- EXPECT_EQ(plugin3_.path.value(),
- plugin_loader()->canonical_list()->at(0).value());
-}
-
-TEST_F(PluginLoaderPosixTest, InternalPlugin) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
-
- plugin2_.path = base::FilePath("/internal/plugin.plugin");
-
- AddThreePlugins();
-
- plugin_loader()->internal_plugins()->clear();
- plugin_loader()->internal_plugins()->push_back(plugin2_);
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
-
- plugin_loader()->TestOnPluginLoaded(0, plugin1_);
- EXPECT_EQ(1u, plugin_loader()->next_load_index());
- EXPECT_EQ(1u, plugins.size());
- EXPECT_EQ(plugin1_.name, plugins[0].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- // Internal plugins can fail to load if they're built-in with manual
- // entrypoint functions.
- plugin_loader()->TestOnPluginLoadFailed(1, plugin2_.path);
- EXPECT_EQ(2u, plugin_loader()->next_load_index());
- EXPECT_EQ(2u, plugins.size());
- EXPECT_EQ(plugin2_.name, plugins[1].name);
- EXPECT_EQ(0u, plugin_loader()->internal_plugins()->size());
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(0, did_callback);
-
- plugin_loader()->TestOnPluginLoaded(2, plugin3_);
- EXPECT_EQ(3u, plugins.size());
- EXPECT_EQ(plugin3_.name, plugins[2].name);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
-}
-
-TEST_F(PluginLoaderPosixTest, AllCrashed) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- plugin_loader()->GetPlugins(callback);
-
- // Spin the loop so that the canonical list of plugins can be set.
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
- message_loop()->RunUntilIdle();
- AddThreePlugins();
-
- EXPECT_EQ(0u, plugin_loader()->next_load_index());
-
- // Mock the first two calls like normal.
- testing::Expectation first =
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
- // On the last call, go through the default impl.
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
- .After(first)
- .WillOnce(
- testing::Invoke(plugin_loader(),
- &MockPluginLoaderPosix::RealLoadPluginsInternal));
- plugin_loader()->OnProcessCrashed(42);
- plugin_loader()->OnProcessCrashed(42);
- plugin_loader()->OnProcessCrashed(42);
-
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
-
- EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
-}
-
-TEST_F(PluginLoaderPosixTest, PluginLaunchFailed) {
- int did_callback = 0;
- PluginService::GetPluginsCallback callback =
- base::Bind(&VerifyCallback, base::Unretained(&did_callback));
-
- EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
- .WillOnce(testing::Invoke(
- plugin_loader(), &MockPluginLoaderPosix::RealLoadPluginsInternal));
-
- plugin_loader()->GetPlugins(callback);
- message_loop()->RunUntilIdle();
- EXPECT_EQ(1, did_callback);
- EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
-
- // TODO(erikchen): This is a genuine leak that should be fixed.
- // https://code.google.com/p/chromium/issues/detail?id=431906
- testing::Mock::AllowLeak(plugin_loader());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/plugin_process_host.cc b/chromium/content/browser/plugin_process_host.cc
deleted file mode 100644
index cb14fa7b669..00000000000
--- a/chromium/content/browser/plugin_process_host.cc
+++ /dev/null
@@ -1,442 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/plugin_process_host.h"
-
-#include <stddef.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-#include "components/tracing/tracing_switches.h"
-#include "content/browser/browser_child_process_host_impl.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/browser/loader/resource_message_filter.h"
-#include "content/browser/plugin_service_impl.h"
-#include "content/common/child_process_host_impl.h"
-#include "content/common/plugin_process_messages.h"
-#include "content/common/resource_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/plugin_service.h"
-#include "content/public/browser/resource_context.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/process_type.h"
-#include "content/public/common/sandboxed_process_launcher_delegate.h"
-#include "ipc/ipc_switches.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/switches.h"
-#include "ui/gl/gl_switches.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#include "ui/gfx/geometry/rect.h"
-#endif
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#include "content/common/plugin_constants_win.h"
-#endif
-
-namespace content {
-
-namespace {
-
-base::LazyInstance<std::map<base::ProcessId, WebPluginInfo> >
- g_process_webplugin_info = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<base::Lock>::Leaky
- g_process_webplugin_info_lock = LAZY_INSTANCE_INITIALIZER;
-}
-
-bool PluginProcessHost::GetWebPluginInfoFromPluginPid(base::ProcessId pid,
- WebPluginInfo* info) {
- base::AutoLock lock(g_process_webplugin_info_lock.Get());
- if (!g_process_webplugin_info.Get().count(pid))
- return false;
-
- *info = g_process_webplugin_info.Get()[pid];
- return true;
-}
-
-#if defined(OS_WIN)
-void PluginProcessHost::OnPluginWindowDestroyed(HWND window, HWND parent) {
- // The window is destroyed at this point, we just care about its parent, which
- // is the intermediate window we created.
- std::set<HWND>::iterator window_index =
- plugin_parent_windows_set_.find(parent);
- if (window_index == plugin_parent_windows_set_.end())
- return;
-
- plugin_parent_windows_set_.erase(window_index);
- PostMessage(parent, WM_CLOSE, 0, 0);
-}
-
-void PluginProcessHost::AddWindow(HWND window) {
- plugin_parent_windows_set_.insert(window);
-}
-#endif // defined(OS_WIN)
-
-// NOTE: changes to this class need to be reviewed by the security team.
-class PluginSandboxedProcessLauncherDelegate
- : public SandboxedProcessLauncherDelegate {
- public:
- explicit PluginSandboxedProcessLauncherDelegate(ChildProcessHost* host)
-#if defined(OS_POSIX)
- : ipc_fd_(host->TakeClientFileDescriptor())
-#endif // OS_POSIX
- {}
-
- ~PluginSandboxedProcessLauncherDelegate() override {}
-
-#if defined(OS_WIN)
- bool ShouldSandbox() override {
- return false;
- }
-
-#elif defined(OS_POSIX)
- base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); }
-#endif // OS_WIN
-
- private:
-#if defined(OS_POSIX)
- base::ScopedFD ipc_fd_;
-#endif // OS_POSIX
-
- DISALLOW_COPY_AND_ASSIGN(PluginSandboxedProcessLauncherDelegate);
-};
-
-PluginProcessHost::PluginProcessHost()
- : pid_(base::kNullProcessId)
-#if defined(OS_MACOSX)
- , plugin_cursor_visible_(true)
-#endif
-{
- process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_PLUGIN, this));
-}
-
-PluginProcessHost::~PluginProcessHost() {
-#if defined(OS_WIN)
- // We erase HWNDs from the plugin_parent_windows_set_ when we receive a
- // notification that the window is being destroyed. If we don't receive this
- // notification and the PluginProcessHost instance is being destroyed, it
- // means that the plugin process crashed. We paint a sad face in this case in
- // the renderer process. To ensure that the sad face shows up, and we don't
- // leak HWNDs, we should destroy existing plugin parent windows.
- std::set<HWND>::iterator window_index;
- for (window_index = plugin_parent_windows_set_.begin();
- window_index != plugin_parent_windows_set_.end();
- ++window_index) {
- PostMessage(*window_index, WM_CLOSE, 0, 0);
- }
-#elif defined(OS_MACOSX)
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // If the plugin process crashed but had fullscreen windows open at the time,
- // make sure that the menu bar is visible.
- for (size_t i = 0; i < plugin_fullscreen_windows_set_.size(); ++i) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::ReleaseFullScreen,
- base::mac::kFullScreenModeHideAll));
- }
- // If the plugin hid the cursor, reset that.
- if (!plugin_cursor_visible_) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::SetCursorVisibility, true));
- }
-#endif
- // Cancel all pending and sent requests.
- CancelRequests();
-
- {
- base::AutoLock lock(g_process_webplugin_info_lock.Get());
- g_process_webplugin_info.Get()[pid_] = info_;
- }
-}
-
-bool PluginProcessHost::Send(IPC::Message* message) {
- return process_->Send(message);
-}
-
-bool PluginProcessHost::Init(const WebPluginInfo& info) {
- info_ = info;
- process_->SetName(info_.name);
-
- std::string channel_id = process_->GetHost()->CreateChannel();
- if (channel_id.empty())
- return false;
-
- // Build command line for plugin. When we have a plugin launcher, we can't
- // allow "self" on linux and we need the real file path.
- const base::CommandLine& browser_command_line =
- *base::CommandLine::ForCurrentProcess();
- base::CommandLine::StringType plugin_launcher =
- browser_command_line.GetSwitchValueNative(switches::kPluginLauncher);
-
-#if defined(OS_LINUX)
- int flags = plugin_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
- ChildProcessHost::CHILD_NORMAL;
-#else
- int flags = ChildProcessHost::CHILD_NORMAL;
-#endif
-
- base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
- if (exe_path.empty())
- return false;
-
- base::CommandLine* cmd_line = new base::CommandLine(exe_path);
- // Put the process type and plugin path first so they're easier to see
- // in process listings using native process management tools.
- cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kPluginProcess);
- cmd_line->AppendSwitchPath(switches::kPluginPath, info.path);
-
-#if defined(OS_WIN)
- if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument())
- cmd_line->AppendArg(switches::kPrefetchArgumentOther);
-#endif // defined(OS_WIN)
-
- // Propagate the following switches to the plugin command line (along with
- // any associated values) if present in the browser command line
- static const char* const kSwitchNames[] = {
- switches::kDisableBreakpad,
- switches::kDisableDirectNPAPIRequests,
- switches::kEnableStatsTable,
- switches::kFullMemoryCrashReport,
- switches::kLoggingLevel,
- switches::kLogPluginMessages,
- switches::kNoSandbox,
- switches::kPluginStartupDialog,
- switches::kTraceConfigFile,
- switches::kTraceStartup,
- switches::kUseGL,
- switches::kForceDeviceScaleFactor,
-#if defined(OS_MACOSX)
- switches::kDisableCoreAnimationPlugins,
- switches::kEnableSandboxLogging,
-#endif
- };
-
- cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
- arraysize(kSwitchNames));
-
- GpuDataManagerImpl::GetInstance()->AppendPluginCommandLine(cmd_line);
-
- // If specified, prepend a launcher program to the command line.
- if (!plugin_launcher.empty())
- cmd_line->PrependWrapper(plugin_launcher);
-
- std::string locale = GetContentClient()->browser()->GetApplicationLocale();
- if (!locale.empty()) {
- // Pass on the locale so the null plugin will use the right language in the
- // prompt to install the desired plugin.
- cmd_line->AppendSwitchASCII(switches::kLang, locale);
- }
-
- cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
-
- // The plugin needs to be shutdown gracefully, i.e. NP_Shutdown needs to be
- // called on the plugin. The plugin process exits when it receives the
- // OnChannelError notification indicating that the browser plugin channel has
- // been destroyed.
- bool terminate_on_shutdown = false;
- process_->Launch(
- new PluginSandboxedProcessLauncherDelegate(process_->GetHost()),
- cmd_line,
- terminate_on_shutdown);
-
- ResourceMessageFilter::GetContextsCallback get_contexts_callback(
- base::Bind(&PluginProcessHost::GetContexts,
- base::Unretained(this)));
-
- // TODO(jam): right now we're passing NULL for appcache, blob storage, file
- // system and host zoom level context. If NPAPI plugins actually use this,
- // we'll have to plumb them.
- ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
- process_->GetData().id, PROCESS_TYPE_PLUGIN, NULL, NULL, NULL, NULL, NULL,
- get_contexts_callback);
- process_->AddFilter(resource_message_filter);
- return true;
-}
-
-void PluginProcessHost::ForceShutdown() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- Send(new PluginProcessMsg_NotifyRenderersOfPendingShutdown());
- process_->ForceShutdown();
-}
-
-bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PluginProcessHost, msg)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ChannelCreated, OnChannelCreated)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ChannelDestroyed,
- OnChannelDestroyed)
-#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginWindowDestroyed,
- OnPluginWindowDestroyed)
-#endif
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginShowWindow,
- OnPluginShowWindow)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginHideWindow,
- OnPluginHideWindow)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginSetCursorVisibility,
- OnPluginSetCursorVisibility)
-#endif
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-void PluginProcessHost::OnChannelConnected(int32_t peer_pid) {
- for (size_t i = 0; i < pending_requests_.size(); ++i) {
- RequestPluginChannel(pending_requests_[i]);
- }
-
- pending_requests_.clear();
-
- pid_ = peer_pid;
- {
- base::AutoLock lock(g_process_webplugin_info_lock.Get());
- g_process_webplugin_info.Get()[pid_] = info_;
- }
-}
-
-void PluginProcessHost::OnChannelError() {
- CancelRequests();
-}
-
-bool PluginProcessHost::CanShutdown() {
- return sent_requests_.empty();
-}
-
-void PluginProcessHost::OnProcessCrashed(int exit_code) {
- PluginServiceImpl::GetInstance()->RegisterPluginCrash(info_.path);
-}
-
-void PluginProcessHost::CancelRequests() {
- for (size_t i = 0; i < pending_requests_.size(); ++i)
- pending_requests_[i]->OnError();
- pending_requests_.clear();
-
- while (!sent_requests_.empty()) {
- Client* client = sent_requests_.front();
- if (client)
- client->OnError();
- sent_requests_.pop_front();
- }
-}
-
-void PluginProcessHost::OpenChannelToPlugin(Client* client) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&BrowserChildProcessHostImpl::NotifyProcessInstanceCreated,
- process_->GetData()));
- client->SetPluginInfo(info_);
- if (process_->GetHost()->IsChannelOpening()) {
- // The channel is already in the process of being opened. Put
- // this "open channel" request into a queue of requests that will
- // be run once the channel is open.
- pending_requests_.push_back(client);
- return;
- }
-
- // We already have an open channel, send a request right away to plugin.
- RequestPluginChannel(client);
-}
-
-void PluginProcessHost::CancelPendingRequest(Client* client) {
- std::vector<Client*>::iterator it = pending_requests_.begin();
- while (it != pending_requests_.end()) {
- if (client == *it) {
- pending_requests_.erase(it);
- return;
- }
- ++it;
- }
- DCHECK(it != pending_requests_.end());
-}
-
-void PluginProcessHost::CancelSentRequest(Client* client) {
- std::list<Client*>::iterator it = sent_requests_.begin();
- while (it != sent_requests_.end()) {
- if (client == *it) {
- *it = NULL;
- return;
- }
- ++it;
- }
- DCHECK(it != sent_requests_.end());
-}
-
-void PluginProcessHost::RequestPluginChannel(Client* client) {
- // We can't send any sync messages from the browser because it might lead to
- // a hang. However this async messages must be answered right away by the
- // plugin process (i.e. unblocks a Send() call like a sync message) otherwise
- // a deadlock can occur if the plugin creation request from the renderer is
- // a result of a sync message by the plugin process.
- PluginProcessMsg_CreateChannel* msg =
- new PluginProcessMsg_CreateChannel(
- client->ID(),
- client->OffTheRecord());
- msg->set_unblock(true);
- if (Send(msg)) {
- sent_requests_.push_back(client);
- client->OnSentPluginChannelRequest();
- } else {
- client->OnError();
- }
-}
-
-void PluginProcessHost::OnChannelCreated(
- const IPC::ChannelHandle& channel_handle) {
- Client* client = sent_requests_.front();
-
- if (client) {
- if (!resource_context_map_.count(client->ID())) {
- ResourceContextEntry entry;
- entry.ref_count = 0;
- entry.resource_context = client->GetResourceContext();
- resource_context_map_[client->ID()] = entry;
- }
- resource_context_map_[client->ID()].ref_count++;
- client->OnChannelOpened(channel_handle);
- }
- sent_requests_.pop_front();
-}
-
-void PluginProcessHost::OnChannelDestroyed(int renderer_id) {
- resource_context_map_[renderer_id].ref_count--;
- if (!resource_context_map_[renderer_id].ref_count)
- resource_context_map_.erase(renderer_id);
-}
-
-void PluginProcessHost::GetContexts(ResourceType resource_type,
- int origin_pid,
- ResourceContext** resource_context,
- net::URLRequestContext** request_context) {
- *resource_context =
- resource_context_map_[origin_pid].resource_context;
- *request_context = (*resource_context)->GetRequestContext();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/plugin_process_host.h b/chromium/content/browser/plugin_process_host.h
deleted file mode 100644
index 66ec73dfd8d..00000000000
--- a/chromium/content/browser/plugin_process_host.h
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_PLUGIN_PROCESS_HOST_H_
-#define CONTENT_BROWSER_PLUGIN_PROCESS_HOST_H_
-
-#include "build/build_config.h"
-
-#include <stdint.h>
-
-#include <list>
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/process/process_handle.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/browser_child_process_host_delegate.h"
-#include "content/public/browser/browser_child_process_host_iterator.h"
-#include "content/public/common/process_type.h"
-#include "content/public/common/resource_type.h"
-#include "content/public/common/webplugininfo.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ui/gfx/native_widget_types.h"
-
-struct ResourceHostMsg_Request;
-
-namespace gfx {
-class Rect;
-}
-
-namespace IPC {
-struct ChannelHandle;
-}
-
-namespace net {
-class URLRequestContext;
-}
-
-namespace content {
-class BrowserChildProcessHostImpl;
-class ResourceContext;
-
-// Represents the browser side of the browser <--> plugin communication
-// channel. Different plugins run in their own process, but multiple instances
-// of the same plugin run in the same process. There will be one
-// PluginProcessHost per plugin process, matched with a corresponding
-// PluginProcess running in the plugin process. The browser is responsible for
-// starting the plugin process when a plugin is created that doesn't already
-// have a process. After that, most of the communication is directly between
-// the renderer and plugin processes.
-class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
- public IPC::Sender {
- public:
- class Client {
- public:
- // Returns an opaque unique identifier for the process requesting
- // the channel.
- virtual int ID() = 0;
- // Returns the resource context for the renderer requesting the channel.
- virtual ResourceContext* GetResourceContext() = 0;
- virtual bool OffTheRecord() = 0;
- virtual void SetPluginInfo(const WebPluginInfo& info) = 0;
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) = 0;
- virtual void OnSentPluginChannelRequest() = 0;
- // The client should delete itself when one of these methods is called.
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) = 0;
- virtual void OnError() = 0;
-
- protected:
- virtual ~Client() {}
- };
-
- PluginProcessHost();
- ~PluginProcessHost() override;
-
- // IPC::Sender implementation:
- bool Send(IPC::Message* message) override;
-
- // Initialize the new plugin process, returning true on success. This must
- // be called before the object can be used.
- bool Init(const WebPluginInfo& info);
-
- // Force the plugin process to shutdown (cleanly).
- void ForceShutdown();
-
- bool OnMessageReceived(const IPC::Message& msg) override;
- void OnChannelConnected(int32_t peer_pid) override;
- void OnChannelError() override;
-
- // Tells the plugin process to create a new channel for communication with a
- // renderer. When the plugin process responds with the channel name,
- // OnChannelOpened in the client is called.
- void OpenChannelToPlugin(Client* client);
-
- // This function is called to cancel pending requests to open new channels.
- void CancelPendingRequest(Client* client);
-
- // This function is called to cancel sent requests to open new channels.
- void CancelSentRequest(Client* client);
-
- // This function is called on the IO thread once we receive a reply from the
- // modal HTML dialog (in the form of a JSON string). This function forwards
- // that reply back to the plugin that requested the dialog.
- void OnModalDialogResponse(const std::string& json_retval,
- IPC::Message* sync_result);
-
-#if defined(OS_MACOSX)
- // This function is called on the IO thread when the browser becomes the
- // active application.
- void OnAppActivation();
-#endif
-
- const WebPluginInfo& info() const { return info_; }
-
-#if defined(OS_WIN)
- // Tracks plugin parent windows created on the browser UI thread.
- void AddWindow(HWND window);
-#endif
-
- // Given a pid of a plugin process, returns the plugin information in |info|
- // if we know about that process. Otherwise returns false.
- // This method can be called on any thread.
- static bool GetWebPluginInfoFromPluginPid(base::ProcessId pid,
- WebPluginInfo* info);
-
- private:
- // Sends a message to the plugin process to request creation of a new channel
- // for the given mime type.
- void RequestPluginChannel(Client* client);
-
- // Message handlers.
- void OnChannelCreated(const IPC::ChannelHandle& channel_handle);
- void OnChannelDestroyed(int renderer_id);
-
-#if defined(OS_WIN)
- void OnPluginWindowDestroyed(HWND window, HWND parent);
-#endif
-
-#if defined(OS_MACOSX)
- void OnPluginShowWindow(uint32_t window_id,
- gfx::Rect window_rect,
- bool modal);
- void OnPluginHideWindow(uint32_t window_id, gfx::Rect window_rect);
- void OnPluginSetCursorVisibility(bool visible);
-#endif
-
- bool CanShutdown() override;
- void OnProcessCrashed(int exit_code) override;
-
- void CancelRequests();
-
- // Callback for ResourceMessageFilter.
- void GetContexts(ResourceType resource_type,
- int origin_pid,
- ResourceContext** resource_context,
- net::URLRequestContext** request_context);
-
- // These are channel requests that we are waiting to send to the
- // plugin process once the channel is opened.
- std::vector<Client*> pending_requests_;
-
- // These are the channel requests that we have already sent to
- // the plugin process, but haven't heard back about yet.
- std::list<Client*> sent_requests_;
-
- // Information about the plugin.
- WebPluginInfo info_;
-
- // The pid of the plugin process.
- int pid_;
-
-#if defined(OS_WIN)
- // Tracks plugin parent windows created on the UI thread.
- std::set<HWND> plugin_parent_windows_set_;
-#endif
-#if defined(OS_MACOSX)
- // Tracks plugin windows currently visible.
- std::set<uint32_t> plugin_visible_windows_set_;
- // Tracks full screen windows currently visible.
- std::set<uint32_t> plugin_fullscreen_windows_set_;
- // Tracks modal windows currently visible.
- std::set<uint32_t> plugin_modal_windows_set_;
- // Tracks the current visibility of the cursor.
- bool plugin_cursor_visible_;
-#endif
-
- // Map from render_process_id to its ResourceContext. Instead of storing the
- // raw pointer, we store the struct below. This is needed because a renderer
- // process can actually have multiple IPC channels to the same plugin process,
- // depending on timing conditions with plugin instance creation and shutdown.
- struct ResourceContextEntry {
- ResourceContext* resource_context;
- int ref_count;
- };
- typedef std::map<int, ResourceContextEntry> ResourceContextMap;
- ResourceContextMap resource_context_map_;
-
- scoped_ptr<BrowserChildProcessHostImpl> process_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginProcessHost);
-};
-
-class PluginProcessHostIterator
- : public BrowserChildProcessHostTypeIterator<PluginProcessHost> {
- public:
- PluginProcessHostIterator()
- : BrowserChildProcessHostTypeIterator<PluginProcessHost>(
- PROCESS_TYPE_PLUGIN) {}
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_PLUGIN_PROCESS_HOST_H_
diff --git a/chromium/content/browser/plugin_process_host_mac.cc b/chromium/content/browser/plugin_process_host_mac.cc
deleted file mode 100644
index 8bd04433bf9..00000000000
--- a/chromium/content/browser/plugin_process_host_mac.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <Carbon/Carbon.h>
-#include <stdint.h>
-
-#include "build/build_config.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "content/browser/browser_child_process_host_impl.h"
-#include "content/browser/plugin_process_host.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_data.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace content {
-
-void PluginProcessHost::OnPluginShowWindow(uint32_t window_id,
- gfx::Rect window_rect,
- bool modal) {
- plugin_visible_windows_set_.insert(window_id);
- if (modal)
- plugin_modal_windows_set_.insert(window_id);
- CGRect window_bounds = {
- { window_rect.x(), window_rect.y() },
- { window_rect.width(), window_rect.height() }
- };
- CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID());
- if (CGRectEqualToRect(window_bounds, main_display_bounds) &&
- (plugin_fullscreen_windows_set_.find(window_id) ==
- plugin_fullscreen_windows_set_.end())) {
- plugin_fullscreen_windows_set_.insert(window_id);
- // If the plugin has just shown a window that's the same dimensions as
- // the main display, hide the menubar so that it has the whole screen.
- // (but only if we haven't already seen this fullscreen window, since
- // otherwise our refcounting can get skewed).
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::RequestFullScreen,
- base::mac::kFullScreenModeHideAll));
- }
-}
-
-// Must be called on the UI thread.
-// If plugin_pid is -1, the browser will be the active process on return,
-// otherwise that process will be given focus back before this function returns.
-static void ReleasePluginFullScreen(pid_t plugin_pid) {
- // Releasing full screen only works if we are the frontmost process; grab
- // focus, but give it back to the plugin process if requested.
- base::mac::ActivateProcess(base::GetCurrentProcId());
- base::mac::ReleaseFullScreen(base::mac::kFullScreenModeHideAll);
- if (plugin_pid != -1) {
- base::mac::ActivateProcess(plugin_pid);
- }
-}
-
-void PluginProcessHost::OnPluginHideWindow(uint32_t window_id,
- gfx::Rect window_rect) {
- bool had_windows = !plugin_visible_windows_set_.empty();
- plugin_visible_windows_set_.erase(window_id);
- bool browser_needs_activation = had_windows &&
- plugin_visible_windows_set_.empty();
-
- plugin_modal_windows_set_.erase(window_id);
- if (plugin_fullscreen_windows_set_.find(window_id) !=
- plugin_fullscreen_windows_set_.end()) {
- plugin_fullscreen_windows_set_.erase(window_id);
- pid_t plugin_pid =
- browser_needs_activation ? -1 : process_->GetData().handle;
- browser_needs_activation = false;
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(ReleasePluginFullScreen, plugin_pid));
- }
-
- if (browser_needs_activation) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::ActivateProcess, base::GetCurrentProcId()));
- }
-}
-
-void PluginProcessHost::OnAppActivation() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // If our plugin process has any modal windows up, we need to bring it forward
- // so that they act more like an in-process modal window would.
- if (!plugin_modal_windows_set_.empty()) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::ActivateProcess, process_->GetData().handle));
- }
-}
-
-void PluginProcessHost::OnPluginSetCursorVisibility(bool visible) {
- if (plugin_cursor_visible_ != visible) {
- plugin_cursor_visible_ = visible;
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(base::mac::SetCursorVisibility,
- visible));
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/plugin_service_impl.cc b/chromium/content/browser/plugin_service_impl.cc
index 700d30428c7..c81e19b6b23 100644
--- a/chromium/content/browser/plugin_service_impl.cc
+++ b/chromium/content/browser/plugin_service_impl.cc
@@ -34,108 +34,27 @@
#include "content/public/common/process_type.h"
#include "content/public/common/webplugininfo.h"
-#if defined(OS_WIN)
-#include "content/common/plugin_constants_win.h"
-#include "ui/gfx/win/hwnd_util.h"
-#endif
-
-#if defined(OS_POSIX)
-#include "content/browser/plugin_loader_posix.h"
-#endif
-
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-using ::base::FilePathWatcher;
-#endif
-
namespace content {
namespace {
// This enum is used to collect Flash usage data.
enum FlashUsage {
- // Number of browser processes that have started at least one NPAPI Flash
- // process during their lifetime.
- START_NPAPI_FLASH_AT_LEAST_ONCE,
// Number of browser processes that have started at least one PPAPI Flash
// process during their lifetime.
- START_PPAPI_FLASH_AT_LEAST_ONCE,
+ START_PPAPI_FLASH_AT_LEAST_ONCE = 1,
// Total number of browser processes.
TOTAL_BROWSER_PROCESSES,
FLASH_USAGE_ENUM_COUNT
};
-enum NPAPIPluginStatus {
- // Platform does not support NPAPI.
- NPAPI_STATUS_UNSUPPORTED,
- // Platform supports NPAPI and NPAPI is disabled.
- NPAPI_STATUS_DISABLED,
- // Platform supports NPAPI and NPAPI is enabled.
- NPAPI_STATUS_ENABLED,
- NPAPI_STATUS_ENUM_COUNT
-};
-
-bool LoadPluginListInProcess() {
-#if defined(OS_WIN)
- return true;
-#else
- // If on POSIX, we don't want to load the list of NPAPI plugins in-process as
- // that causes instability.
-
- // Can't load the plugins on the utility thread when in single process mode
- // since that requires GTK which can only be used on the main thread.
- if (RenderProcessHost::run_renderer_in_process())
- return true;
-
- return !PluginService::GetInstance()->NPAPIPluginsSupported();
-#endif
-}
-
// Callback set on the PluginList to assert that plugin loading happens on the
// correct thread.
void WillLoadPluginsCallback(
base::SequencedWorkerPool::SequenceToken token) {
- if (LoadPluginListInProcess()) {
- CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
- token));
- } else {
- CHECK(false) << "Plugin loading should happen out-of-process.";
- }
+ CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
+ token));
}
-#if defined(OS_MACOSX)
-void NotifyPluginsOfActivation() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
- iter->OnAppActivation();
-}
-#endif
-
-#if defined(OS_POSIX)
-#if !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-void NotifyPluginDirChanged(const base::FilePath& path, bool error) {
- if (error) {
- // TODO(pastarmovj): Add some sensible error handling. Maybe silently
- // stopping the watcher would be enough. Or possibly restart it.
- NOTREACHED();
- return;
- }
- VLOG(1) << "Watched path changed: " << path.value();
- // Make the plugin list update itself
- PluginList::Singleton()->RefreshPlugins();
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&PluginService::PurgePluginListCache,
- static_cast<BrowserContext*>(NULL), false));
-}
-#endif // !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-
-void ForwardCallback(base::SingleThreadTaskRunner* target_task_runner,
- const PluginService::GetPluginsCallback& callback,
- const std::vector<WebPluginInfo>& plugins) {
- target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins));
-}
-#endif // defined(OS_POSIX)
-
} // namespace
// static
@@ -159,7 +78,7 @@ PluginServiceImpl* PluginServiceImpl::GetInstance() {
}
PluginServiceImpl::PluginServiceImpl()
- : npapi_plugins_enabled_(false), filter_(NULL) {
+ : filter_(NULL) {
// Collect the total number of browser processes (which create
// PluginServiceImpl objects, to be precise). The number is used to normalize
// the number of processes which start at least one NPAPI/PPAPI Flash process.
@@ -172,8 +91,6 @@ PluginServiceImpl::PluginServiceImpl()
}
PluginServiceImpl::~PluginServiceImpl() {
- // Make sure no plugin channel requests have been leaked.
- DCHECK(pending_plugin_clients_.empty());
}
void PluginServiceImpl::Init() {
@@ -182,80 +99,6 @@ void PluginServiceImpl::Init() {
base::Bind(&WillLoadPluginsCallback, plugin_list_token_));
RegisterPepperPlugins();
-
- // Load any specified on the command line as well.
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
- base::FilePath path =
- command_line->GetSwitchValuePath(switches::kLoadPlugin);
- if (!path.empty())
- AddExtraPluginPath(path);
- path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
- if (!path.empty())
- PluginList::Singleton()->AddExtraPluginDir(path);
-
- if (command_line->HasSwitch(switches::kDisablePluginsDiscovery))
- PluginList::Singleton()->DisablePluginsDiscovery();
-}
-
-void PluginServiceImpl::StartWatchingPlugins() {
- // Start watching for changes in the plugin list. This means watching
- // for changes in the Windows registry keys and on both Windows and POSIX
- // watch for changes in the paths that are expected to contain plugins.
-#if defined(OS_WIN)
- if (hkcu_key_.Create(HKEY_CURRENT_USER,
- kRegistryMozillaPlugins,
- KEY_NOTIFY) == ERROR_SUCCESS) {
- base::win::RegKey::ChangeCallback callback =
- base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this),
- base::Unretained(&hkcu_key_));
- hkcu_key_.StartWatching(callback);
- }
- if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
- kRegistryMozillaPlugins,
- KEY_NOTIFY) == ERROR_SUCCESS) {
- base::win::RegKey::ChangeCallback callback =
- base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this),
- base::Unretained(&hklm_key_));
- hklm_key_.StartWatching(callback);
- }
-#endif
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-// On ChromeOS the user can't install plugins anyway and on Windows all
-// important plugins register themselves in the registry so no need to do that.
-
- // Get the list of all paths for registering the FilePathWatchers
- // that will track and if needed reload the list of plugins on runtime.
- std::vector<base::FilePath> plugin_dirs;
- PluginList::Singleton()->GetPluginDirectories(&plugin_dirs);
-
- for (size_t i = 0; i < plugin_dirs.size(); ++i) {
- // FilePathWatcher can not handle non-absolute paths under windows.
- // We don't watch for file changes in windows now but if this should ever
- // be extended to Windows these lines might save some time of debugging.
-#if defined(OS_WIN)
- if (!plugin_dirs[i].IsAbsolute())
- continue;
-#endif
- FilePathWatcher* watcher = new FilePathWatcher();
- VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
- plugin_dirs[i]));
- file_watchers_.push_back(watcher);
- }
-#endif
-}
-
-PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
- const base::FilePath& plugin_path) {
- for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter->info().path == plugin_path)
- return *iter;
- }
-
- return NULL;
}
PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
@@ -280,46 +123,6 @@ PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
return NULL;
}
-PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
- int render_process_id,
- const base::FilePath& plugin_path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path))
- return NULL;
-
- PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
- if (plugin_host)
- return plugin_host;
-
- WebPluginInfo info;
- if (!GetPluginInfoByPath(plugin_path, &info)) {
- return NULL;
- }
-
- // Record when NPAPI Flash process is started for the first time.
- static bool counted = false;
- if (!counted && base::UTF16ToUTF8(info.name) == kFlashPluginName) {
- counted = true;
- UMA_HISTOGRAM_ENUMERATION("Plugin.FlashUsage",
- START_NPAPI_FLASH_AT_LEAST_ONCE,
- FLASH_USAGE_ENUM_COUNT);
- }
-#if defined(OS_CHROMEOS)
- // TODO(ihf): Move to an earlier place once crbug.com/314301 is fixed. For now
- // we still want Plugin.FlashUsage recorded if we end up here.
- LOG(WARNING) << "Refusing to start npapi plugin on ChromeOS.";
- return NULL;
-#endif
- // This plugin isn't loaded by any plugin process, so create a new process.
- scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
- if (!new_host->Init(info)) {
- NOTREACHED(); // Init is not expected to fail.
- return NULL;
- }
- return new_host.release();
-}
-
PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
int render_process_id,
const base::FilePath& plugin_path,
@@ -388,29 +191,6 @@ PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
return PpapiPluginProcessHost::CreateBrokerHost(*info);
}
-void PluginServiceImpl::OpenChannelToNpapiPlugin(
- int render_process_id,
- int render_frame_id,
- const GURL& url,
- const GURL& page_url,
- const std::string& mime_type,
- PluginProcessHost::Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(!ContainsKey(pending_plugin_clients_, client));
- pending_plugin_clients_.insert(client);
-
- // Make sure plugins are loaded if necessary.
- PluginServiceFilterParams params = {
- render_process_id,
- render_frame_id,
- page_url,
- client->GetResourceContext()
- };
- GetPlugins(base::Bind(
- &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
- base::Unretained(this), params, url, mime_type, client));
-}
-
void PluginServiceImpl::OpenChannelToPpapiPlugin(
int render_process_id,
const base::FilePath& plugin_path,
@@ -440,78 +220,6 @@ void PluginServiceImpl::OpenChannelToPpapiBroker(
}
}
-void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
- PluginProcessHost::Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(ContainsKey(pending_plugin_clients_, client));
- pending_plugin_clients_.erase(client);
-}
-
-void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
- const PluginServiceFilterParams& params,
- const GURL& url,
- const std::string& mime_type,
- PluginProcessHost::Client* client,
- const std::vector<WebPluginInfo>&) {
- GetAllowedPluginForOpenChannelToPlugin(
- params.render_process_id, params.render_frame_id, url, params.page_url,
- mime_type, client, params.resource_context);
-}
-
-void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
- int render_process_id,
- int render_frame_id,
- const GURL& url,
- const GURL& page_url,
- const std::string& mime_type,
- PluginProcessHost::Client* client,
- ResourceContext* resource_context) {
- WebPluginInfo info;
- bool allow_wildcard = true;
- bool found = GetPluginInfo(
- render_process_id, render_frame_id, resource_context,
- url, page_url, mime_type, allow_wildcard,
- NULL, &info, NULL);
- base::FilePath plugin_path;
- if (found)
- plugin_path = info.path;
-
- // Now we jump back to the IO thread to finish opening the channel.
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
- base::Unretained(this),
- render_process_id,
- plugin_path,
- client));
- if (filter_) {
- DCHECK_EQ(WebPluginInfo::PLUGIN_TYPE_NPAPI, info.type);
- filter_->NPAPIPluginLoaded(render_process_id, render_frame_id, mime_type,
- info);
- }
-}
-
-void PluginServiceImpl::FinishOpenChannelToPlugin(
- int render_process_id,
- const base::FilePath& plugin_path,
- PluginProcessHost::Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // Make sure it hasn't been canceled yet.
- if (!ContainsKey(pending_plugin_clients_, client))
- return;
- pending_plugin_clients_.erase(client);
-
- PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(
- render_process_id, plugin_path);
- if (plugin_host) {
- client->OnFoundPluginProcessHost(plugin_host);
- plugin_host->OpenChannelToPlugin(client);
- } else {
- client->OnError();
- }
-}
-
bool PluginServiceImpl::GetPluginInfoArray(
const GURL& url,
const std::string& mime_type,
@@ -520,8 +228,7 @@ bool PluginServiceImpl::GetPluginInfoArray(
std::vector<std::string>* actual_mime_types) {
bool use_stale = false;
PluginList::Singleton()->GetPluginInfoArray(
- url, mime_type, allow_wildcard, &use_stale, NPAPIPluginsSupported(),
- plugins, actual_mime_types);
+ url, mime_type, allow_wildcard, &use_stale, plugins, actual_mime_types);
return use_stale;
}
@@ -598,23 +305,11 @@ void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner(
base::ThreadTaskRunnerHandle::Get());
- if (LoadPluginListInProcess()) {
- BrowserThread::GetBlockingPool()
- ->PostSequencedWorkerTaskWithShutdownBehavior(
- plugin_list_token_, FROM_HERE,
- base::Bind(&PluginServiceImpl::GetPluginsInternal,
- base::Unretained(this), target_task_runner, callback),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
- return;
- }
-#if defined(OS_POSIX)
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PluginServiceImpl::GetPluginsOnIOThread,
- base::Unretained(this), target_task_runner, callback));
-#else
- NOTREACHED();
-#endif
+ BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
+ plugin_list_token_, FROM_HERE,
+ base::Bind(&PluginServiceImpl::GetPluginsInternal, base::Unretained(this),
+ base::RetainedRef(target_task_runner), callback),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
}
void PluginServiceImpl::GetPluginsInternal(
@@ -624,39 +319,11 @@ void PluginServiceImpl::GetPluginsInternal(
plugin_list_token_));
std::vector<WebPluginInfo> plugins;
- PluginList::Singleton()->GetPlugins(&plugins, NPAPIPluginsSupported());
+ PluginList::Singleton()->GetPlugins(&plugins);
target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins));
}
-#if defined(OS_POSIX)
-void PluginServiceImpl::GetPluginsOnIOThread(
- base::SingleThreadTaskRunner* target_task_runner,
- const GetPluginsCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // If we switch back to loading plugins in process, then we need to make
- // sure g_thread_init() gets called since plugins may call glib at load.
-
- if (!plugin_loader_.get())
- plugin_loader_ = new PluginLoaderPosix;
-
- plugin_loader_->GetPlugins(base::Bind(
- &ForwardCallback, make_scoped_refptr(target_task_runner), callback));
-}
-#endif
-
-#if defined(OS_WIN)
-void PluginServiceImpl::OnKeyChanged(base::win::RegKey* key) {
- key->StartWatching(base::Bind(&PluginServiceImpl::OnKeyChanged,
- base::Unretained(this),
- base::Unretained(key)));
-
- PluginList::Singleton()->RefreshPlugins();
- PurgePluginListCache(NULL, false);
-}
-#endif // defined(OS_WIN)
-
void PluginServiceImpl::RegisterPepperPlugins() {
ComputePepperPluginList(&ppapi_plugins_);
for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
@@ -691,16 +358,6 @@ PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
return &ppapi_plugins_[ppapi_plugins_.size() - 1];
}
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-// static
-void PluginServiceImpl::RegisterFilePathWatcher(FilePathWatcher* watcher,
- const base::FilePath& path) {
- bool result = watcher->Watch(path, false,
- base::Bind(&NotifyPluginDirChanged));
- DCHECK(result);
-}
-#endif
-
void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) {
filter_ = filter;
}
@@ -709,20 +366,6 @@ PluginServiceFilter* PluginServiceImpl::GetFilter() {
return filter_;
}
-void PluginServiceImpl::ForcePluginShutdown(const base::FilePath& plugin_path) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&PluginServiceImpl::ForcePluginShutdown,
- base::Unretained(this), plugin_path));
- return;
- }
-
- PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path);
- if (plugin)
- plugin->ForceShutdown();
-}
-
static const unsigned int kMaxCrashesPerInterval = 3;
static const unsigned int kCrashesInterval = 120;
@@ -759,33 +402,9 @@ void PluginServiceImpl::RefreshPlugins() {
PluginList::Singleton()->RefreshPlugins();
}
-void PluginServiceImpl::AddExtraPluginPath(const base::FilePath& path) {
- if (!NPAPIPluginsSupported()) {
- // TODO(jam): remove and just have CHECK once we're sure this doesn't get
- // triggered.
- DVLOG(0) << "NPAPI plugins not supported";
- return;
- }
- PluginList::Singleton()->AddExtraPluginPath(path);
-}
-
-void PluginServiceImpl::RemoveExtraPluginPath(const base::FilePath& path) {
- PluginList::Singleton()->RemoveExtraPluginPath(path);
-}
-
-void PluginServiceImpl::AddExtraPluginDir(const base::FilePath& path) {
- PluginList::Singleton()->AddExtraPluginDir(path);
-}
-
void PluginServiceImpl::RegisterInternalPlugin(
const WebPluginInfo& info,
bool add_at_beginning) {
- // Internal plugins should never be NPAPI.
- CHECK_NE(info.type, WebPluginInfo::PLUGIN_TYPE_NPAPI);
- if (info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) {
- DVLOG(0) << "Don't register NPAPI plugins when they're not supported";
- return;
- }
PluginList::Singleton()->RegisterInternalPlugin(info, add_at_beginning);
}
@@ -798,76 +417,6 @@ void PluginServiceImpl::GetInternalPlugins(
PluginList::Singleton()->GetInternalPlugins(plugins);
}
-bool PluginServiceImpl::NPAPIPluginsSupported() {
-#if defined(OS_WIN) || defined(OS_MACOSX)
- npapi_plugins_enabled_ = GetContentClient()->browser()->IsNPAPIEnabled();
-#if defined(OS_WIN)
- // NPAPI plugins don't play well with Win32k renderer lockdown.
- if (npapi_plugins_enabled_)
- DisableWin32kRendererLockdown();
-#endif
- NPAPIPluginStatus status =
- npapi_plugins_enabled_ ? NPAPI_STATUS_ENABLED : NPAPI_STATUS_DISABLED;
-#else
- NPAPIPluginStatus status = NPAPI_STATUS_UNSUPPORTED;
-#endif
- UMA_HISTOGRAM_ENUMERATION("Plugin.NPAPIStatus", status,
- NPAPI_STATUS_ENUM_COUNT);
-
- return npapi_plugins_enabled_;
-}
-
-void PluginServiceImpl::DisablePluginsDiscoveryForTesting() {
- PluginList::Singleton()->DisablePluginsDiscovery();
-}
-
-#if defined(OS_MACOSX)
-void PluginServiceImpl::AppActivated() {
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&NotifyPluginsOfActivation));
-}
-#elif defined(OS_WIN)
-
-bool GetPluginPropertyFromWindow(
- HWND window, const wchar_t* plugin_atom_property,
- base::string16* plugin_property) {
- ATOM plugin_atom = static_cast<ATOM>(
- reinterpret_cast<uintptr_t>(GetPropW(window, plugin_atom_property)));
- if (plugin_atom != 0) {
- WCHAR plugin_property_local[MAX_PATH] = {0};
- GlobalGetAtomNameW(plugin_atom,
- plugin_property_local,
- ARRAYSIZE(plugin_property_local));
- *plugin_property = plugin_property_local;
- return true;
- }
- return false;
-}
-
-bool PluginServiceImpl::GetPluginInfoFromWindow(
- HWND window,
- base::string16* plugin_name,
- base::string16* plugin_version) {
- if (!IsPluginWindow(window))
- return false;
-
-
- DWORD process_id = 0;
- GetWindowThreadProcessId(window, &process_id);
- WebPluginInfo info;
- if (!PluginProcessHost::GetWebPluginInfoFromPluginPid(process_id, &info))
- return false;
-
- *plugin_name = info.name;
- *plugin_version = info.version;
- return true;
-}
-
-bool PluginServiceImpl::IsPluginWindow(HWND window) {
- return gfx::GetClassName(window) == base::string16(kNativeWindowClassName);
-}
-#endif
-
bool PluginServiceImpl::PpapiDevChannelSupported(
BrowserContext* browser_context,
const GURL& document_url) {
diff --git a/chromium/content/browser/plugin_service_impl.h b/chromium/content/browser/plugin_service_impl.h
index 644a26230a5..e167cc34175 100644
--- a/chromium/content/browser/plugin_service_impl.h
+++ b/chromium/content/browser/plugin_service_impl.h
@@ -24,7 +24,6 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "content/browser/plugin_process_host.h"
#include "content/browser/ppapi_plugin_process_host.h"
#include "content/common/content_export.h"
#include "content/public/browser/plugin_service.h"
@@ -48,20 +47,10 @@ class SingleThreadTaskRunner;
namespace content {
class BrowserContext;
class PluginDirWatcherDelegate;
-class PluginLoaderPosix;
class PluginServiceFilter;
class ResourceContext;
struct PepperPluginInfo;
-// base::Bind() has limited arity, and the filter-related methods tend to
-// surpass that limit.
-struct PluginServiceFilterParams {
- int render_process_id;
- int render_frame_id;
- GURL page_url;
- ResourceContext* resource_context;
-};
-
class CONTENT_EXPORT PluginServiceImpl
: NON_EXPORTED_BASE(public PluginService) {
public:
@@ -70,7 +59,6 @@ class CONTENT_EXPORT PluginServiceImpl
// PluginService implementation:
void Init() override;
- void StartWatchingPlugins() override;
bool GetPluginInfoArray(const GURL& url,
const std::string& mime_type,
bool allow_wildcard,
@@ -95,28 +83,12 @@ class CONTENT_EXPORT PluginServiceImpl
const base::FilePath& plugin_path) override;
void SetFilter(PluginServiceFilter* filter) override;
PluginServiceFilter* GetFilter() override;
- void ForcePluginShutdown(const base::FilePath& plugin_path) override;
bool IsPluginUnstable(const base::FilePath& plugin_path) override;
void RefreshPlugins() override;
- void AddExtraPluginPath(const base::FilePath& path) override;
- void RemoveExtraPluginPath(const base::FilePath& path) override;
- void AddExtraPluginDir(const base::FilePath& path) override;
void RegisterInternalPlugin(const WebPluginInfo& info,
bool add_at_beginning) override;
void UnregisterInternalPlugin(const base::FilePath& path) override;
void GetInternalPlugins(std::vector<WebPluginInfo>* plugins) override;
- bool NPAPIPluginsSupported() override;
- void DisablePluginsDiscoveryForTesting() override;
-#if defined(OS_MACOSX)
- void AppActivated() override;
-#elif defined(OS_WIN)
- bool GetPluginInfoFromWindow(HWND window,
- base::string16* plugin_name,
- base::string16* plugin_version) override;
-
- // Returns true iff the given HWND is a plugin.
- bool IsPluginWindow(HWND window);
-#endif
bool PpapiDevChannelSupported(BrowserContext* browser_context,
const GURL& document_url) override;
@@ -124,8 +96,6 @@ class CONTENT_EXPORT PluginServiceImpl
// has been started by this service. This will start a process to host the
// 'plugin_path' if needed. If the process fails to start, the return value
// is NULL. Must be called on the IO thread.
- PluginProcessHost* FindOrStartNpapiPluginProcess(
- int render_process_id, const base::FilePath& plugin_path);
PpapiPluginProcessHost* FindOrStartPpapiPluginProcess(
int render_process_id,
const base::FilePath& plugin_path,
@@ -136,12 +106,6 @@ class CONTENT_EXPORT PluginServiceImpl
// Opens a channel to a plugin process for the given mime type, starting
// a new plugin process if necessary. This must be called on the IO thread
// or else a deadlock can occur.
- void OpenChannelToNpapiPlugin(int render_process_id,
- int render_frame_id,
- const GURL& url,
- const GURL& page_url,
- const std::string& mime_type,
- PluginProcessHost::Client* client);
void OpenChannelToPpapiPlugin(int render_process_id,
const base::FilePath& plugin_path,
const base::FilePath& profile_data_directory,
@@ -150,9 +114,6 @@ class CONTENT_EXPORT PluginServiceImpl
const base::FilePath& path,
PpapiPluginProcessHost::BrokerClient* client);
- // Cancels opening a channel to a NPAPI plugin.
- void CancelOpenChannelToNpapiPlugin(PluginProcessHost::Client* client);
-
// Used to monitor plugin stability.
void RegisterPluginCrash(const base::FilePath& plugin_path);
@@ -171,7 +132,6 @@ class CONTENT_EXPORT PluginServiceImpl
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. Returns NULL if no process has been
// started.
- PluginProcessHost* FindNpapiPluginProcess(const base::FilePath& plugin_path);
PpapiPluginProcessHost* FindPpapiPluginProcess(
const base::FilePath& plugin_path,
const base::FilePath& profile_data_directory);
@@ -184,67 +144,14 @@ class CONTENT_EXPORT PluginServiceImpl
void GetPluginsInternal(base::SingleThreadTaskRunner* target_task_runner,
const GetPluginsCallback& callback);
-#if defined(OS_POSIX)
- void GetPluginsOnIOThread(base::SingleThreadTaskRunner* target_task_runner,
- const GetPluginsCallback& callback);
-#endif
-
- // Binding directly to GetAllowedPluginForOpenChannelToPlugin() isn't possible
- // because more arity is needed <http://crbug.com/98542>. This just forwards.
- void ForwardGetAllowedPluginForOpenChannelToPlugin(
- const PluginServiceFilterParams& params,
- const GURL& url,
- const std::string& mime_type,
- PluginProcessHost::Client* client,
- const std::vector<WebPluginInfo>&);
- // Helper so we can do the plugin lookup on the FILE thread.
- void GetAllowedPluginForOpenChannelToPlugin(
- int render_process_id,
- int render_frame_id,
- const GURL& url,
- const GURL& page_url,
- const std::string& mime_type,
- PluginProcessHost::Client* client,
- ResourceContext* resource_context);
-
- // Helper so we can finish opening the channel after looking up the
- // plugin.
- void FinishOpenChannelToPlugin(int render_process_id,
- const base::FilePath& plugin_path,
- PluginProcessHost::Client* client);
-
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
- // Registers a new FilePathWatcher for a given path.
- static void RegisterFilePathWatcher(base::FilePathWatcher* watcher,
- const base::FilePath& path);
-#endif
-
-#if defined(OS_WIN)
- // Registry keys for getting notifications when new plugins are installed.
- base::win::RegKey hkcu_key_;
- base::win::RegKey hklm_key_;
-#endif
-
- bool npapi_plugins_enabled_;
-
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
- ScopedVector<base::FilePathWatcher> file_watchers_;
-#endif
-
std::vector<PepperPluginInfo> ppapi_plugins_;
// Weak pointer; outlives us.
PluginServiceFilter* filter_;
- std::set<PluginProcessHost::Client*> pending_plugin_clients_;
-
// Used to sequentialize loading plugins from disk.
base::SequencedWorkerPool::SequenceToken plugin_list_token_;
-#if defined(OS_POSIX)
- scoped_refptr<PluginLoaderPosix> plugin_loader_;
-#endif
-
// Used to detect if a given plugin is crashing over and over.
std::map<base::FilePath, std::vector<base::Time> > crash_times_;
diff --git a/chromium/content/browser/power_save_blocker_impl.cc b/chromium/content/browser/power_save_blocker_impl.cc
index b3f15fb58c7..069cd3a327f 100644
--- a/chromium/content/browser/power_save_blocker_impl.cc
+++ b/chromium/content/browser/power_save_blocker_impl.cc
@@ -14,12 +14,8 @@ scoped_ptr<PowerSaveBlocker> PowerSaveBlocker::Create(
PowerSaveBlockerType type,
Reason reason,
const std::string& description) {
-#if defined(OS_ANDROID) && defined(USE_AURA)
- return nullptr;
-#else
return scoped_ptr<PowerSaveBlocker>(
new PowerSaveBlockerImpl(type, reason, description));
-#endif
}
} // namespace content
diff --git a/chromium/content/browser/power_save_blocker_x11.cc b/chromium/content/browser/power_save_blocker_x11.cc
index 97eefef9519..babc81488a0 100644
--- a/chromium/content/browser/power_save_blocker_x11.cc
+++ b/chromium/content/browser/power_save_blocker_x11.cc
@@ -7,6 +7,7 @@
#include <X11/Xlib.h>
#include <stdint.h>
#include <X11/extensions/dpms.h>
+#include <X11/extensions/scrnsaver.h>
// Xlib #defines Status, but we can't have that for some of our headers.
#ifdef Status
#undef Status
@@ -108,12 +109,22 @@ class PowerSaveBlockerImpl::Delegate
void ApplyBlockFinished(dbus::Response* response);
void RemoveBlockFinished(dbus::Response* response);
+ // Wrapper for XScreenSaverSuspend. Checks whether the X11 Screen Saver
+ // Extension is available first. If it isn't, this is a no-op.
+ // Must be called on the UI thread.
+ static void XSSSuspendSet(bool suspend);
+
// If DPMS (the power saving system in X11) is not enabled, then we don't want
// to try to disable power saving, since on some desktop environments that may
// enable DPMS with very poor default settings (e.g. turning off the display
// after only 1 second). Must be called on the UI thread.
static bool DPMSEnabled();
+ // If no other method is available (i.e. not running under a Desktop
+ // Environment) check whether the X11 Screen Saver Extension can be used
+ // to disable the screen saver. Must be called on the UI thread.
+ static bool XSSAvailable();
+
// Returns an appropriate D-Bus API to use based on the desktop environment.
// Must be called on the UI thread, as it may call DPMSEnabled() above.
static DBusAPI SelectAPI();
@@ -180,9 +191,14 @@ void PowerSaveBlockerImpl::Delegate::CleanUp() {
// initializing on the UI thread, then just cancel it. We don't need to
// remove the block because we haven't even applied it yet.
enqueue_apply_ = false;
- } else if (ShouldBlock()) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&Delegate::RemoveBlock, this));
+ } else {
+ if (ShouldBlock()) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&Delegate::RemoveBlock, this));
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&Delegate::XSSSuspendSet, false));
}
}
@@ -190,12 +206,17 @@ void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::AutoLock lock(lock_);
api_ = SelectAPI();
- if (enqueue_apply_ && ShouldBlock()) {
- // The thread we use here becomes the origin and D-Bus thread for the D-Bus
- // library, so we need to use the same thread above for RemoveBlock(). It
- // must be a thread that allows I/O operations, so we use the FILE thread.
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&Delegate::ApplyBlock, this));
+
+ if (enqueue_apply_) {
+ if (ShouldBlock()) {
+ // The thread we use here becomes the origin and D-Bus thread for the
+ // D-Bus library, so we need to use the same thread above for
+ // RemoveBlock(). It must be a thread that allows I/O operations, so we
+ // use the FILE thread.
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&Delegate::ApplyBlock, this));
+ }
+ XSSSuspendSet(true);
}
enqueue_apply_ = false;
}
@@ -384,6 +405,17 @@ void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
}
// static
+void PowerSaveBlockerImpl::Delegate::XSSSuspendSet(bool suspend) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!XSSAvailable())
+ return;
+
+ XDisplay* display = gfx::GetXDisplay();
+ XScreenSaverSuspend(display, suspend);
+}
+
+// static
bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
XDisplay* display = gfx::GetXDisplay();
@@ -397,6 +429,23 @@ bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
}
// static
+bool PowerSaveBlockerImpl::Delegate::XSSAvailable() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ XDisplay* display = gfx::GetXDisplay();
+ int dummy;
+ int major;
+ int minor;
+
+ if (!XScreenSaverQueryExtension(display, &dummy, &dummy))
+ return false;
+
+ if (!XScreenSaverQueryVersion(display, &major, &minor))
+ return false;
+
+ return major > 1 || (major == 1 && minor >= 1);
+}
+
+// static
DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_ptr<base::Environment> env(base::Environment::Create());
diff --git a/chromium/content/browser/ppapi_plugin_process_host.cc b/chromium/content/browser/ppapi_plugin_process_host.cc
index 3523fc10a8b..56ae0eea7f4 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.cc
+++ b/chromium/content/browser/ppapi_plugin_process_host.cc
@@ -35,6 +35,10 @@
#include "ppapi/proxy/ppapi_messages.h"
#include "ui/base/ui_base_switches.h"
+#if defined(OS_POSIX)
+#include "content/public/browser/zygote_handle_linux.h"
+#endif // defined(OS_POSIX)
+
#if defined(OS_WIN)
#include "content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h"
#include "content/common/sandbox_win.h"
@@ -45,6 +49,10 @@
namespace content {
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+ZygoteHandle g_ppapi_zygote;
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
// NOTE: changes to this class need to be reviewed by the security team.
class PpapiPluginSandboxedProcessLauncherDelegate
: public content::SandboxedProcessLauncherDelegate {
@@ -105,13 +113,18 @@ class PpapiPluginSandboxedProcessLauncherDelegate
}
#elif defined(OS_POSIX)
- bool ShouldUseZygote() override {
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+ ZygoteHandle* GetZygote() override {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType plugin_launcher = browser_command_line
.GetSwitchValueNative(switches::kPpapiPluginLauncher);
- return !is_broker_ && plugin_launcher.empty();
+ if (is_broker_ || !plugin_launcher.empty())
+ return nullptr;
+ return GetGenericZygote();
}
+#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
+
base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); }
#endif // OS_WIN
@@ -200,6 +213,14 @@ PpapiPluginProcessHost* PpapiPluginProcessHost::CreateBrokerHost(
return NULL;
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+// static
+void PpapiPluginProcessHost::EarlyZygoteLaunch() {
+ DCHECK(!g_ppapi_zygote);
+ g_ppapi_zygote = CreateZygote();
+}
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
// static
void PpapiPluginProcessHost::DidCreateOutOfProcessInstance(
int plugin_process_id,
diff --git a/chromium/content/browser/ppapi_plugin_process_host.h b/chromium/content/browser/ppapi_plugin_process_host.h
index 96593494cd2..85e2b64de50 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.h
+++ b/chromium/content/browser/ppapi_plugin_process_host.h
@@ -116,6 +116,11 @@ class PpapiPluginProcessHost : public BrowserChildProcessHostDelegate,
return profile_data_directory_;
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+ // Launch the zygote early in the browser startup.
+ static void EarlyZygoteLaunch();
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
// The client pointer must remain valid until its callback is issued.
private:
diff --git a/chromium/content/browser/presentation/presentation_service_impl.cc b/chromium/content/browser/presentation/presentation_service_impl.cc
index 07644589a40..c2e30e998c6 100644
--- a/chromium/content/browser/presentation/presentation_service_impl.cc
+++ b/chromium/content/browser/presentation/presentation_service_impl.cc
@@ -39,16 +39,15 @@ int GetNextRequestSessionId() {
// |input|: The message to convert.
// |pass_ownership|: If true, function may reuse strings or buffers from
// |input| without copying. |input| can be freely modified.
-presentation::SessionMessagePtr ToMojoSessionMessage(
+mojom::SessionMessagePtr ToMojoSessionMessage(
content::PresentationSessionMessage* input,
bool pass_ownership) {
DCHECK(input);
- presentation::SessionMessagePtr output(presentation::SessionMessage::New());
+ mojom::SessionMessagePtr output(mojom::SessionMessage::New());
if (input->is_binary()) {
// binary data
DCHECK(input->data);
- output->type = presentation::PresentationMessageType::
- PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ output->type = mojom::PresentationMessageType::ARRAY_BUFFER;
if (pass_ownership) {
output->data.Swap(input->data.get());
} else {
@@ -56,8 +55,7 @@ presentation::SessionMessagePtr ToMojoSessionMessage(
}
} else {
// string message
- output->type =
- presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT;
+ output->type = mojom::PresentationMessageType::TEXT;
if (pass_ownership) {
output->message.Swap(&input->message);
} else {
@@ -68,11 +66,11 @@ presentation::SessionMessagePtr ToMojoSessionMessage(
}
scoped_ptr<PresentationSessionMessage> GetPresentationSessionMessage(
- presentation::SessionMessagePtr input) {
+ mojom::SessionMessagePtr input) {
DCHECK(!input.is_null());
scoped_ptr<content::PresentationSessionMessage> output;
switch (input->type) {
- case presentation::PRESENTATION_MESSAGE_TYPE_TEXT: {
+ case mojom::PresentationMessageType::TEXT: {
DCHECK(!input->message.is_null());
DCHECK(input->data.is_null());
// Return null PresentationSessionMessage if size exceeds.
@@ -84,7 +82,7 @@ scoped_ptr<PresentationSessionMessage> GetPresentationSessionMessage(
input->message.Swap(&output->message);
return output;
}
- case presentation::PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER: {
+ case mojom::PresentationMessageType::ARRAY_BUFFER: {
DCHECK(!input->data.is_null());
DCHECK(input->message.is_null());
if (input->data.size() > content::kMaxPresentationSessionMessageSize)
@@ -96,7 +94,7 @@ scoped_ptr<PresentationSessionMessage> GetPresentationSessionMessage(
input->data.Swap(output->data.get());
return output;
}
- case presentation::PRESENTATION_MESSAGE_TYPE_BLOB: {
+ case mojom::PresentationMessageType::BLOB: {
DCHECK(!input->data.is_null());
DCHECK(input->message.is_null());
if (input->data.size() > content::kMaxPresentationSessionMessageSize)
@@ -116,10 +114,9 @@ scoped_ptr<PresentationSessionMessage> GetPresentationSessionMessage(
void InvokeNewSessionMojoCallbackWithError(
const NewSessionMojoCallback& callback) {
- callback.Run(
- presentation::PresentationSessionInfoPtr(),
- presentation::PresentationError::From(
- PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
+ callback.Run(mojom::PresentationSessionInfoPtr(),
+ mojom::PresentationError::From(PresentationError(
+ PRESENTATION_ERROR_UNKNOWN, "Internal error")));
}
} // namespace
@@ -151,15 +148,14 @@ PresentationServiceImpl::~PresentationServiceImpl() {
// static
void PresentationServiceImpl::CreateMojoService(
RenderFrameHost* render_frame_host,
- mojo::InterfaceRequest<presentation::PresentationService> request) {
+ mojo::InterfaceRequest<mojom::PresentationService> request) {
DVLOG(2) << "CreateMojoService";
WebContents* web_contents =
WebContents::FromRenderFrameHost(render_frame_host);
DCHECK(web_contents);
// This object will be deleted when the RenderFrameHost is about to be
- // deleted (RenderFrameDeleted) or if a connection error occurred
- // (OnConnectionError).
+ // deleted (RenderFrameDeleted).
PresentationServiceImpl* impl = new PresentationServiceImpl(
render_frame_host,
web_contents,
@@ -169,17 +165,13 @@ void PresentationServiceImpl::CreateMojoService(
}
void PresentationServiceImpl::Bind(
- mojo::InterfaceRequest<presentation::PresentationService> request) {
- binding_.reset(new mojo::Binding<presentation::PresentationService>(
- this, std::move(request)));
- binding_->set_connection_error_handler([this]() {
- DVLOG(1) << "Connection error";
- delete this;
- });
+ mojo::InterfaceRequest<mojom::PresentationService> request) {
+ binding_.reset(
+ new mojo::Binding<mojom::PresentationService>(this, std::move(request)));
}
void PresentationServiceImpl::SetClient(
- presentation::PresentationServiceClientPtr client) {
+ mojom::PresentationServiceClientPtr client) {
DCHECK(!client_.get());
// TODO(imcheng): Set ErrorHandler to listen for errors.
client_ = std::move(client);
@@ -231,10 +223,9 @@ void PresentationServiceImpl::StartSession(
DVLOG(2) << "StartSession";
if (!delegate_) {
callback.Run(
- presentation::PresentationSessionInfoPtr(),
- presentation::PresentationError::From(
- PresentationError(PRESENTATION_ERROR_NO_AVAILABLE_SCREENS,
- "No screens found.")));
+ mojom::PresentationSessionInfoPtr(),
+ mojom::PresentationError::From(PresentationError(
+ PRESENTATION_ERROR_NO_AVAILABLE_SCREENS, "No screens found.")));
return;
}
@@ -261,11 +252,10 @@ void PresentationServiceImpl::JoinSession(
const NewSessionMojoCallback& callback) {
DVLOG(2) << "JoinSession";
if (!delegate_) {
- callback.Run(
- presentation::PresentationSessionInfoPtr(),
- presentation::PresentationError::From(
- PresentationError(PRESENTATION_ERROR_NO_PRESENTATION_FOUND,
- "Error joining route: No matching route")));
+ callback.Run(mojom::PresentationSessionInfoPtr(),
+ mojom::PresentationError::From(PresentationError(
+ PRESENTATION_ERROR_NO_PRESENTATION_FOUND,
+ "Error joining route: No matching route")));
return;
}
@@ -314,8 +304,8 @@ void PresentationServiceImpl::OnStartSessionSucceeded(
CHECK(pending_start_session_cb_.get());
pending_start_session_cb_->Run(
- presentation::PresentationSessionInfo::From(session_info),
- presentation::PresentationErrorPtr());
+ mojom::PresentationSessionInfo::From(session_info),
+ mojom::PresentationErrorPtr());
ListenForConnectionStateChange(session_info);
pending_start_session_cb_.reset();
start_session_request_id_ = kInvalidRequestSessionId;
@@ -328,8 +318,8 @@ void PresentationServiceImpl::OnStartSessionError(
return;
CHECK(pending_start_session_cb_.get());
- pending_start_session_cb_->Run(presentation::PresentationSessionInfoPtr(),
- presentation::PresentationError::From(error));
+ pending_start_session_cb_->Run(mojom::PresentationSessionInfoPtr(),
+ mojom::PresentationError::From(error));
pending_start_session_cb_.reset();
start_session_request_id_ = kInvalidRequestSessionId;
}
@@ -339,8 +329,8 @@ void PresentationServiceImpl::OnJoinSessionSucceeded(
const PresentationSessionInfo& session_info) {
if (RunAndEraseJoinSessionMojoCallback(
request_session_id,
- presentation::PresentationSessionInfo::From(session_info),
- presentation::PresentationErrorPtr())) {
+ mojom::PresentationSessionInfo::From(session_info),
+ mojom::PresentationErrorPtr())) {
ListenForConnectionStateChange(session_info);
}
}
@@ -348,16 +338,15 @@ void PresentationServiceImpl::OnJoinSessionSucceeded(
void PresentationServiceImpl::OnJoinSessionError(
int request_session_id,
const PresentationError& error) {
- RunAndEraseJoinSessionMojoCallback(
- request_session_id,
- presentation::PresentationSessionInfoPtr(),
- presentation::PresentationError::From(error));
+ RunAndEraseJoinSessionMojoCallback(request_session_id,
+ mojom::PresentationSessionInfoPtr(),
+ mojom::PresentationError::From(error));
}
bool PresentationServiceImpl::RunAndEraseJoinSessionMojoCallback(
int request_session_id,
- presentation::PresentationSessionInfoPtr session,
- presentation::PresentationErrorPtr error) {
+ mojom::PresentationSessionInfoPtr session,
+ mojom::PresentationErrorPtr error) {
auto it = pending_join_session_cbs_.find(request_session_id);
if (it == pending_join_session_cbs_.end())
return false;
@@ -386,8 +375,8 @@ void PresentationServiceImpl::SetDefaultPresentationURL(
}
void PresentationServiceImpl::SendSessionMessage(
- presentation::PresentationSessionInfoPtr session,
- presentation::SessionMessagePtr session_message,
+ mojom::PresentationSessionInfoPtr session,
+ mojom::SessionMessagePtr session_message,
const SendMessageMojoCallback& callback) {
DVLOG(2) << "SendSessionMessage";
DCHECK(!session_message.is_null());
@@ -434,11 +423,18 @@ void PresentationServiceImpl::Terminate(const mojo::String& presentation_url,
void PresentationServiceImpl::OnConnectionStateChanged(
const PresentationSessionInfo& connection,
- PresentationConnectionState state) {
+ const PresentationConnectionStateChangeInfo& info) {
DCHECK(client_.get());
- client_->OnConnectionStateChanged(
- presentation::PresentationSessionInfo::From(connection),
- PresentationConnectionStateToMojo(state));
+ if (info.state == PRESENTATION_CONNECTION_STATE_CLOSED) {
+ client_->OnConnectionClosed(
+ mojom::PresentationSessionInfo::From(connection),
+ PresentationConnectionCloseReasonToMojo(info.close_reason),
+ info.message);
+ } else {
+ client_->OnConnectionStateChanged(
+ mojom::PresentationSessionInfo::From(connection),
+ PresentationConnectionStateToMojo(info.state));
+ }
}
bool PresentationServiceImpl::FrameMatches(
@@ -451,7 +447,7 @@ bool PresentationServiceImpl::FrameMatches(
}
void PresentationServiceImpl::ListenForSessionMessages(
- presentation::PresentationSessionInfoPtr session) {
+ mojom::PresentationSessionInfoPtr session) {
DVLOG(2) << "ListenForSessionMessages";
if (!delegate_)
return;
@@ -470,13 +466,12 @@ void PresentationServiceImpl::OnSessionMessages(
DCHECK(client_);
DVLOG(2) << "OnSessionMessages";
- mojo::Array<presentation::SessionMessagePtr> mojoMessages(messages.size());
+ mojo::Array<mojom::SessionMessagePtr> mojoMessages(messages.size());
for (size_t i = 0; i < messages.size(); ++i)
mojoMessages[i] = ToMojoSessionMessage(messages[i], pass_ownership);
client_->OnSessionMessagesReceived(
- presentation::PresentationSessionInfo::From(session),
- std::move(mojoMessages));
+ mojom::PresentationSessionInfo::From(session), std::move(mojoMessages));
}
void PresentationServiceImpl::DidNavigateAnyFrame(
@@ -529,8 +524,7 @@ void PresentationServiceImpl::Reset() {
pending_join_session_cbs_.clear();
if (on_session_messages_callback_.get()) {
- on_session_messages_callback_->Run(
- mojo::Array<presentation::SessionMessagePtr>());
+ on_session_messages_callback_->Run(mojo::Array<mojom::SessionMessagePtr>());
on_session_messages_callback_.reset();
}
@@ -552,7 +546,7 @@ void PresentationServiceImpl::OnDefaultPresentationStarted(
const PresentationSessionInfo& connection) {
DCHECK(client_.get());
client_->OnDefaultSessionStarted(
- presentation::PresentationSessionInfo::From(connection));
+ mojom::PresentationSessionInfo::From(connection));
ListenForConnectionStateChange(connection);
}
@@ -597,8 +591,8 @@ PresentationServiceImpl::NewSessionMojoCallbackWrapper
}
void PresentationServiceImpl::NewSessionMojoCallbackWrapper::Run(
- presentation::PresentationSessionInfoPtr session,
- presentation::PresentationErrorPtr error) {
+ mojom::PresentationSessionInfoPtr session,
+ mojom::PresentationErrorPtr error) {
DCHECK(!callback_.is_null());
callback_.Run(std::move(session), std::move(error));
callback_.reset();
diff --git a/chromium/content/browser/presentation/presentation_service_impl.h b/chromium/content/browser/presentation/presentation_service_impl.h
index 88a70546780..b0243353655 100644
--- a/chromium/content/browser/presentation/presentation_service_impl.h
+++ b/chromium/content/browser/presentation/presentation_service_impl.h
@@ -33,9 +33,9 @@ struct LoadCommittedDetails;
struct PresentationSessionMessage;
class RenderFrameHost;
-using NewSessionMojoCallback = mojo::Callback<
- void(presentation::PresentationSessionInfoPtr,
- presentation::PresentationErrorPtr)>;
+using NewSessionMojoCallback =
+ mojo::Callback<void(mojom::PresentationSessionInfoPtr,
+ mojom::PresentationErrorPtr)>;
// Implementation of Mojo PresentationService.
// It handles Presentation API requests coming from Blink / renderer process
@@ -46,7 +46,7 @@ using NewSessionMojoCallback = mojo::Callback<
// This class is instantiated on-demand via Mojo's ConnectToRemoteService
// from the renderer when the first presentation API request is handled.
class CONTENT_EXPORT PresentationServiceImpl
- : public NON_EXPORTED_BASE(presentation::PresentationService),
+ : public NON_EXPORTED_BASE(mojom::PresentationService),
public WebContentsObserver,
public PresentationServiceDelegate::Observer {
public:
@@ -57,7 +57,7 @@ class CONTENT_EXPORT PresentationServiceImpl
// |request|: The instance will be bound to this request. Used for Mojo setup.
static void CreateMojoService(
RenderFrameHost* render_frame_host,
- mojo::InterfaceRequest<presentation::PresentationService> request);
+ mojo::InterfaceRequest<mojom::PresentationService> request);
private:
friend class PresentationServiceImplTest;
@@ -89,14 +89,16 @@ class CONTENT_EXPORT PresentationServiceImpl
MaxPendingJoinSessionRequests);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForConnectionStateChange);
+ FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
+ ListenForConnectionClose);
// Maximum number of pending JoinSession requests at any given time.
static const int kMaxNumQueuedSessionRequests = 10;
using PresentationSessionMojoCallback =
- mojo::Callback<void(presentation::PresentationSessionInfoPtr)>;
+ mojo::Callback<void(mojom::PresentationSessionInfoPtr)>;
using SessionMessagesCallback =
- mojo::Callback<void(mojo::Array<presentation::SessionMessagePtr>)>;
+ mojo::Callback<void(mojo::Array<mojom::SessionMessagePtr>)>;
using SendMessageMojoCallback = mojo::Callback<void(bool)>;
// Listener implementation owned by PresentationServiceImpl. An instance of
@@ -129,8 +131,8 @@ class CONTENT_EXPORT PresentationServiceImpl
const NewSessionMojoCallback& callback);
~NewSessionMojoCallbackWrapper();
- void Run(presentation::PresentationSessionInfoPtr session,
- presentation::PresentationErrorPtr error);
+ void Run(mojom::PresentationSessionInfoPtr session,
+ mojom::PresentationErrorPtr error);
private:
NewSessionMojoCallback callback_;
@@ -149,7 +151,7 @@ class CONTENT_EXPORT PresentationServiceImpl
// PresentationService implementation.
void SetDefaultPresentationURL(const mojo::String& url) override;
- void SetClient(presentation::PresentationServiceClientPtr client) override;
+ void SetClient(mojom::PresentationServiceClientPtr client) override;
void ListenForScreenAvailability(const mojo::String& url) override;
void StopListeningForScreenAvailability(const mojo::String& url) override;
void StartSession(
@@ -159,18 +161,18 @@ class CONTENT_EXPORT PresentationServiceImpl
const mojo::String& presentation_url,
const mojo::String& presentation_id,
const NewSessionMojoCallback& callback) override;
- void SendSessionMessage(presentation::PresentationSessionInfoPtr session_info,
- presentation::SessionMessagePtr session_message,
+ void SendSessionMessage(mojom::PresentationSessionInfoPtr session_info,
+ mojom::SessionMessagePtr session_message,
const SendMessageMojoCallback& callback) override;
void CloseConnection(const mojo::String& presentation_url,
const mojo::String& presentation_id) override;
void Terminate(const mojo::String& presentation_url,
const mojo::String& presentation_id) override;
void ListenForSessionMessages(
- presentation::PresentationSessionInfoPtr session) override;
+ mojom::PresentationSessionInfoPtr session) override;
// Creates a binding between this object and |request|.
- void Bind(mojo::InterfaceRequest<presentation::PresentationService> request);
+ void Bind(mojo::InterfaceRequest<mojom::PresentationService> request);
// WebContentsObserver override.
void DidNavigateAnyFrame(
@@ -194,8 +196,8 @@ class CONTENT_EXPORT PresentationServiceImpl
// Returns true if the callback was found.
bool RunAndEraseJoinSessionMojoCallback(
int request_session_id,
- presentation::PresentationSessionInfoPtr session,
- presentation::PresentationErrorPtr error);
+ mojom::PresentationSessionInfoPtr session,
+ mojom::PresentationErrorPtr error);
// Removes all listeners and resets default presentation URL on this instance
// and informs the PresentationServiceDelegate of such.
@@ -237,8 +239,9 @@ class CONTENT_EXPORT PresentationServiceImpl
// Invoked by the embedder's PresentationServiceDelegate when a
// PresentationConnection's state has changed.
- void OnConnectionStateChanged(const PresentationSessionInfo& connection,
- PresentationConnectionState state);
+ void OnConnectionStateChanged(
+ const PresentationSessionInfo& connection,
+ const PresentationConnectionStateChangeInfo& info);
// Returns true if this object is associated with |render_frame_host|.
bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
@@ -249,7 +252,7 @@ class CONTENT_EXPORT PresentationServiceImpl
// Proxy to the PresentationServiceClient to send results (e.g., screen
// availability) to.
- presentation::PresentationServiceClientPtr client_;
+ mojom::PresentationServiceClientPtr client_;
std::string default_presentation_url_;
@@ -268,7 +271,7 @@ class CONTENT_EXPORT PresentationServiceImpl
// RAII binding of |this| to an Presentation interface request.
// The binding is removed when binding_ is cleared or goes out of scope.
- scoped_ptr<mojo::Binding<presentation::PresentationService>> binding_;
+ scoped_ptr<mojo::Binding<mojom::PresentationService>> binding_;
// There can be only one send message request at a time.
scoped_ptr<SendMessageMojoCallback> send_message_callback_;
diff --git a/chromium/content/browser/presentation/presentation_service_impl_unittest.cc b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
index cc98878e95c..e25190bd803 100644
--- a/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -45,18 +45,15 @@ MATCHER_P(Equals, expected, "") {
const char *const kPresentationId = "presentationId";
const char *const kPresentationUrl = "http://foo.com/index.html";
-bool ArePresentationSessionMessagesEqual(
- const presentation::SessionMessage* expected,
- const presentation::SessionMessage* actual) {
+bool ArePresentationSessionMessagesEqual(const mojom::SessionMessage* expected,
+ const mojom::SessionMessage* actual) {
return expected->type == actual->type &&
expected->message == actual->message &&
expected->data.Equals(actual->data);
}
-void DoNothing(
- presentation::PresentationSessionInfoPtr info,
- presentation::PresentationErrorPtr error) {
-}
+void DoNothing(mojom::PresentationSessionInfoPtr info,
+ mojom::PresentationErrorPtr error) {}
} // namespace
@@ -149,38 +146,47 @@ class MockPresentationServiceDelegate : public PresentationServiceDelegate {
bool screen_availability_listening_supported_ = true;
};
-class MockPresentationServiceClient :
- public presentation::PresentationServiceClient {
+class MockPresentationServiceClient : public mojom::PresentationServiceClient {
public:
MOCK_METHOD2(OnScreenAvailabilityUpdated,
void(const mojo::String& url, bool available));
void OnConnectionStateChanged(
- presentation::PresentationSessionInfoPtr connection,
- presentation::PresentationConnectionState new_state) override {
+ mojom::PresentationSessionInfoPtr connection,
+ mojom::PresentationConnectionState new_state) override {
OnConnectionStateChanged(*connection, new_state);
}
MOCK_METHOD2(OnConnectionStateChanged,
- void(const presentation::PresentationSessionInfo& connection,
- presentation::PresentationConnectionState new_state));
+ void(const mojom::PresentationSessionInfo& connection,
+ mojom::PresentationConnectionState new_state));
+
+ void OnConnectionClosed(mojom::PresentationSessionInfoPtr connection,
+ mojom::PresentationConnectionCloseReason reason,
+ const mojo::String& message) override {
+ OnConnectionClosed(*connection, reason, message);
+ }
+ MOCK_METHOD3(OnConnectionClosed,
+ void(const mojom::PresentationSessionInfo& connection,
+ mojom::PresentationConnectionCloseReason reason,
+ const mojo::String& message));
MOCK_METHOD1(OnScreenAvailabilityNotSupported, void(const mojo::String& url));
void OnSessionMessagesReceived(
- presentation::PresentationSessionInfoPtr session_info,
- mojo::Array<presentation::SessionMessagePtr> messages) override {
+ mojom::PresentationSessionInfoPtr session_info,
+ mojo::Array<mojom::SessionMessagePtr> messages) override {
messages_received_ = std::move(messages);
MessagesReceived();
}
MOCK_METHOD0(MessagesReceived, void());
void OnDefaultSessionStarted(
- presentation::PresentationSessionInfoPtr session_info) override {
+ mojom::PresentationSessionInfoPtr session_info) override {
OnDefaultSessionStarted(*session_info);
}
MOCK_METHOD1(OnDefaultSessionStarted,
- void(const presentation::PresentationSessionInfo& session_info));
+ void(const mojom::PresentationSessionInfo& session_info));
- mojo::Array<presentation::SessionMessagePtr> messages_received_;
+ mojo::Array<mojom::SessionMessagePtr> messages_received_;
};
class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
@@ -196,10 +202,9 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
contents()->GetMainFrame(), contents(), &mock_delegate_));
service_impl_->Bind(std::move(request));
- presentation::PresentationServiceClientPtr client_ptr;
- client_binding_.reset(
- new mojo::Binding<presentation::PresentationServiceClient>(
- &mock_client_, mojo::GetProxy(&client_ptr)));
+ mojom::PresentationServiceClientPtr client_ptr;
+ client_binding_.reset(new mojo::Binding<mojom::PresentationServiceClient>(
+ &mock_client_, mojo::GetProxy(&client_ptr)));
service_impl_->SetClient(std::move(client_ptr));
}
@@ -269,17 +274,16 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
}
void ExpectNewSessionMojoCallbackSuccess(
- presentation::PresentationSessionInfoPtr info,
- presentation::PresentationErrorPtr error) {
+ mojom::PresentationSessionInfoPtr info,
+ mojom::PresentationErrorPtr error) {
EXPECT_FALSE(info.is_null());
EXPECT_TRUE(error.is_null());
if (!run_loop_quit_closure_.is_null())
run_loop_quit_closure_.Run();
}
- void ExpectNewSessionMojoCallbackError(
- presentation::PresentationSessionInfoPtr info,
- presentation::PresentationErrorPtr error) {
+ void ExpectNewSessionMojoCallbackError(mojom::PresentationSessionInfoPtr info,
+ mojom::PresentationErrorPtr error) {
EXPECT_TRUE(info.is_null());
EXPECT_FALSE(error.is_null());
if (!run_loop_quit_closure_.is_null())
@@ -287,8 +291,8 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
}
void ExpectSessionMessages(
- const mojo::Array<presentation::SessionMessagePtr>& expected_msgs,
- const mojo::Array<presentation::SessionMessagePtr>& actual_msgs) {
+ const mojo::Array<mojom::SessionMessagePtr>& expected_msgs,
+ const mojo::Array<mojom::SessionMessagePtr>& actual_msgs) {
EXPECT_EQ(expected_msgs.size(), actual_msgs.size());
for (size_t i = 0; i < actual_msgs.size(); ++i) {
EXPECT_TRUE(ArePresentationSessionMessagesEqual(expected_msgs[i].get(),
@@ -306,18 +310,16 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
void RunListenForSessionMessages(const std::string& text_msg,
const std::vector<uint8_t>& binary_data,
bool pass_ownership) {
- mojo::Array<presentation::SessionMessagePtr> expected_msgs(2);
- expected_msgs[0] = presentation::SessionMessage::New();
- expected_msgs[0]->type =
- presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT;
+ mojo::Array<mojom::SessionMessagePtr> expected_msgs(2);
+ expected_msgs[0] = mojom::SessionMessage::New();
+ expected_msgs[0]->type = mojom::PresentationMessageType::TEXT;
expected_msgs[0]->message = text_msg;
- expected_msgs[1] = presentation::SessionMessage::New();
- expected_msgs[1]->type = presentation::PresentationMessageType::
- PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ expected_msgs[1] = mojom::SessionMessage::New();
+ expected_msgs[1]->type = mojom::PresentationMessageType::ARRAY_BUFFER;
expected_msgs[1]->data = mojo::Array<uint8_t>::From(binary_data);
- presentation::PresentationSessionInfoPtr session(
- presentation::PresentationSessionInfo::New());
+ mojom::PresentationSessionInfoPtr session(
+ mojom::PresentationSessionInfo::New());
session->url = kPresentationUrl;
session->id = kPresentationId;
@@ -342,7 +344,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
message->data.reset(new std::vector<uint8_t>(binary_data));
messages.push_back(std::move(message));
- std::vector<presentation::SessionMessagePtr> actual_msgs;
+ std::vector<mojom::SessionMessagePtr> actual_msgs;
{
base::RunLoop run_loop;
EXPECT_CALL(mock_client_, MessagesReceived())
@@ -356,11 +358,10 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
MockPresentationServiceDelegate mock_delegate_;
scoped_ptr<PresentationServiceImpl> service_impl_;
- mojo::InterfacePtr<presentation::PresentationService> service_ptr_;
+ mojo::InterfacePtr<mojom::PresentationService> service_ptr_;
MockPresentationServiceClient mock_client_;
- scoped_ptr<mojo::Binding<presentation::PresentationServiceClient>>
- client_binding_;
+ scoped_ptr<mojo::Binding<mojom::PresentationServiceClient>> client_binding_;
base::Closure run_loop_quit_closure_;
int default_session_started_count_;
@@ -451,7 +452,7 @@ TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrl) {
service_impl_->SetDefaultPresentationURL(url2);
EXPECT_EQ(url2, service_impl_->default_presentation_url_);
- presentation::PresentationSessionInfo session_info;
+ mojom::PresentationSessionInfo session_info;
session_info.url = url2;
session_info.id = kPresentationId;
base::RunLoop run_loop;
@@ -470,17 +471,51 @@ TEST_F(PresentationServiceImplTest, ListenForConnectionStateChange) {
service_impl_->ListenForConnectionStateChange(connection);
// Trigger state change. It should be propagated back up to |mock_client_|.
- presentation::PresentationSessionInfo presentation_connection;
+ mojom::PresentationSessionInfo presentation_connection;
presentation_connection.url = kPresentationUrl;
presentation_connection.id = kPresentationId;
- base::RunLoop run_loop;
- EXPECT_CALL(mock_client_,
- OnConnectionStateChanged(
- Equals(presentation_connection),
- presentation::PRESENTATION_CONNECTION_STATE_CLOSED))
- .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
- state_changed_cb.Run(content::PRESENTATION_CONNECTION_STATE_CLOSED);
- run_loop.Run();
+ {
+ base::RunLoop run_loop;
+ EXPECT_CALL(mock_client_,
+ OnConnectionStateChanged(
+ Equals(presentation_connection),
+ mojom::PresentationConnectionState::TERMINATED))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ state_changed_cb.Run(PresentationConnectionStateChangeInfo(
+ PRESENTATION_CONNECTION_STATE_TERMINATED));
+ run_loop.Run();
+ }
+}
+
+TEST_F(PresentationServiceImplTest, ListenForConnectionClose) {
+ content::PresentationSessionInfo connection(kPresentationUrl,
+ kPresentationId);
+ content::PresentationConnectionStateChangedCallback state_changed_cb;
+ EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
+ .WillOnce(SaveArg<3>(&state_changed_cb));
+ service_impl_->ListenForConnectionStateChange(connection);
+
+ // Trigger connection close. It should be propagated back up to
+ // |mock_client_|.
+ mojom::PresentationSessionInfo presentation_connection;
+ presentation_connection.url = kPresentationUrl;
+ presentation_connection.id = kPresentationId;
+ {
+ base::RunLoop run_loop;
+ PresentationConnectionStateChangeInfo closed_info(
+ PRESENTATION_CONNECTION_STATE_CLOSED);
+ closed_info.close_reason = PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY;
+ closed_info.message = "Foo";
+
+ EXPECT_CALL(
+ mock_client_,
+ OnConnectionClosed(Equals(presentation_connection),
+ mojom::PresentationConnectionCloseReason::WENT_AWAY,
+ mojo::String("Foo")))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ state_changed_cb.Run(closed_info);
+ run_loop.Run();
+ }
}
TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrl) {
@@ -630,14 +665,12 @@ TEST_F(PresentationServiceImplTest, StartSessionInProgress) {
TEST_F(PresentationServiceImplTest, SendStringMessage) {
std::string message("Test presentation session message");
- presentation::PresentationSessionInfoPtr session(
- presentation::PresentationSessionInfo::New());
+ mojom::PresentationSessionInfoPtr session(
+ mojom::PresentationSessionInfo::New());
session->url = kPresentationUrl;
session->id = kPresentationId;
- presentation::SessionMessagePtr message_request(
- presentation::SessionMessage::New());
- message_request->type = presentation::PresentationMessageType::
- PRESENTATION_MESSAGE_TYPE_TEXT;
+ mojom::SessionMessagePtr message_request(mojom::SessionMessage::New());
+ message_request->type = mojom::PresentationMessageType::TEXT;
message_request->message = message;
service_ptr_->SendSessionMessage(
std::move(session), std::move(message_request),
@@ -669,14 +702,12 @@ TEST_F(PresentationServiceImplTest, SendArrayBuffer) {
std::vector<uint8_t> data;
data.assign(buffer, buffer + sizeof(buffer));
- presentation::PresentationSessionInfoPtr session(
- presentation::PresentationSessionInfo::New());
+ mojom::PresentationSessionInfoPtr session(
+ mojom::PresentationSessionInfo::New());
session->url = kPresentationUrl;
session->id = kPresentationId;
- presentation::SessionMessagePtr message_request(
- presentation::SessionMessage::New());
- message_request->type = presentation::PresentationMessageType::
- PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ mojom::SessionMessagePtr message_request(mojom::SessionMessage::New());
+ message_request->type = mojom::PresentationMessageType::ARRAY_BUFFER;
message_request->data = mojo::Array<uint8_t>::From(data);
service_ptr_->SendSessionMessage(
std::move(session), std::move(message_request),
@@ -714,14 +745,12 @@ TEST_F(PresentationServiceImplTest, SendArrayBufferWithExceedingLimit) {
std::vector<uint8_t> data;
data.assign(buffer, buffer + sizeof(buffer));
- presentation::PresentationSessionInfoPtr session(
- presentation::PresentationSessionInfo::New());
+ mojom::PresentationSessionInfoPtr session(
+ mojom::PresentationSessionInfo::New());
session->url = kPresentationUrl;
session->id = kPresentationId;
- presentation::SessionMessagePtr message_request(
- presentation::SessionMessage::New());
- message_request->type = presentation::PresentationMessageType::
- PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
+ mojom::SessionMessagePtr message_request(mojom::SessionMessage::New());
+ message_request->type = mojom::PresentationMessageType::ARRAY_BUFFER;
message_request->data = mojo::Array<uint8_t>::From(data);
service_ptr_->SendSessionMessage(
std::move(session), std::move(message_request),
@@ -746,14 +775,12 @@ TEST_F(PresentationServiceImplTest, SendBlobData) {
std::vector<uint8_t> data;
data.assign(buffer, buffer + sizeof(buffer));
- presentation::PresentationSessionInfoPtr session(
- presentation::PresentationSessionInfo::New());
+ mojom::PresentationSessionInfoPtr session(
+ mojom::PresentationSessionInfo::New());
session->url = kPresentationUrl;
session->id = kPresentationId;
- presentation::SessionMessagePtr message_request(
- presentation::SessionMessage::New());
- message_request->type =
- presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB;
+ mojom::SessionMessagePtr message_request(mojom::SessionMessage::New());
+ message_request->type = mojom::PresentationMessageType::BLOB;
message_request->data = mojo::Array<uint8_t>::From(data);
service_ptr_->SendSessionMessage(
std::move(session), std::move(message_request),
@@ -808,10 +835,12 @@ TEST_F(PresentationServiceImplTest, MaxPendingJoinSessionRequests) {
TEST_F(PresentationServiceImplTest, ScreenAvailabilityNotSupported) {
mock_delegate_.set_screen_availability_listening_supported(false);
+ base::RunLoop run_loop;
EXPECT_CALL(mock_client_,
- OnScreenAvailabilityNotSupported(Eq(kPresentationUrl)));
-
+ OnScreenAvailabilityNotSupported(Eq(kPresentationUrl)))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
ListenForScreenAvailabilityAndWait(kPresentationUrl, false);
+ run_loop.Run();
}
} // namespace content
diff --git a/chromium/content/browser/presentation/presentation_type_converters.cc b/chromium/content/browser/presentation/presentation_type_converters.cc
index cd649976d5f..6343e979fb5 100644
--- a/chromium/content/browser/presentation/presentation_type_converters.cc
+++ b/chromium/content/browser/presentation/presentation_type_converters.cc
@@ -8,36 +8,51 @@
namespace content {
-presentation::PresentationErrorType PresentationErrorTypeToMojo(
+mojom::PresentationErrorType PresentationErrorTypeToMojo(
content::PresentationErrorType input) {
switch (input) {
case content::PRESENTATION_ERROR_NO_AVAILABLE_SCREENS:
- return presentation::PRESENTATION_ERROR_TYPE_NO_AVAILABLE_SCREENS;
+ return mojom::PresentationErrorType::NO_AVAILABLE_SCREENS;
case content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED:
- return presentation::PRESENTATION_ERROR_TYPE_SESSION_REQUEST_CANCELLED;
+ return mojom::PresentationErrorType::SESSION_REQUEST_CANCELLED;
case content::PRESENTATION_ERROR_NO_PRESENTATION_FOUND:
- return presentation::PRESENTATION_ERROR_TYPE_NO_PRESENTATION_FOUND;
+ return mojom::PresentationErrorType::NO_PRESENTATION_FOUND;
case content::PRESENTATION_ERROR_UNKNOWN:
- return presentation::PRESENTATION_ERROR_TYPE_UNKNOWN;
+ return mojom::PresentationErrorType::UNKNOWN;
}
NOTREACHED();
- return presentation::PRESENTATION_ERROR_TYPE_UNKNOWN;
+ return mojom::PresentationErrorType::UNKNOWN;
}
-presentation::PresentationConnectionState PresentationConnectionStateToMojo(
+mojom::PresentationConnectionState PresentationConnectionStateToMojo(
content::PresentationConnectionState state) {
switch (state) {
case content::PRESENTATION_CONNECTION_STATE_CONNECTING:
- return presentation::PRESENTATION_CONNECTION_STATE_CONNECTING;
+ return mojom::PresentationConnectionState::CONNECTING;
case content::PRESENTATION_CONNECTION_STATE_CONNECTED:
- return presentation::PRESENTATION_CONNECTION_STATE_CONNECTED;
+ return mojom::PresentationConnectionState::CONNECTED;
case content::PRESENTATION_CONNECTION_STATE_CLOSED:
- return presentation::PRESENTATION_CONNECTION_STATE_CLOSED;
+ return mojom::PresentationConnectionState::CLOSED;
case content::PRESENTATION_CONNECTION_STATE_TERMINATED:
- return presentation::PRESENTATION_CONNECTION_STATE_TERMINATED;
+ return mojom::PresentationConnectionState::TERMINATED;
}
NOTREACHED();
- return presentation::PRESENTATION_CONNECTION_STATE_TERMINATED;
+ return mojom::PresentationConnectionState::TERMINATED;
+}
+
+mojom::PresentationConnectionCloseReason
+PresentationConnectionCloseReasonToMojo(
+ content::PresentationConnectionCloseReason reason) {
+ switch (reason) {
+ case content::PRESENTATION_CONNECTION_CLOSE_REASON_CONNECTION_ERROR:
+ return mojom::PresentationConnectionCloseReason::CONNECTION_ERROR;
+ case content::PRESENTATION_CONNECTION_CLOSE_REASON_CLOSED:
+ return mojom::PresentationConnectionCloseReason::CLOSED;
+ case content::PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY:
+ return mojom::PresentationConnectionCloseReason::WENT_AWAY;
+ }
+ NOTREACHED();
+ return mojom::PresentationConnectionCloseReason::CONNECTION_ERROR;
}
} // namespace content
diff --git a/chromium/content/browser/presentation/presentation_type_converters.h b/chromium/content/browser/presentation/presentation_type_converters.h
index c707f4fa5e8..e35fbf6abd0 100644
--- a/chromium/content/browser/presentation/presentation_type_converters.h
+++ b/chromium/content/browser/presentation/presentation_type_converters.h
@@ -11,23 +11,26 @@
namespace content {
-CONTENT_EXPORT presentation::PresentationErrorType PresentationErrorTypeToMojo(
+CONTENT_EXPORT mojom::PresentationErrorType PresentationErrorTypeToMojo(
PresentationErrorType input);
-CONTENT_EXPORT presentation::PresentationConnectionState
+CONTENT_EXPORT mojom::PresentationConnectionState
PresentationConnectionStateToMojo(PresentationConnectionState state);
+CONTENT_EXPORT mojom::PresentationConnectionCloseReason
+PresentationConnectionCloseReasonToMojo(
+ PresentationConnectionCloseReason reason);
} // namespace content
namespace mojo {
template <>
-struct TypeConverter<presentation::PresentationSessionInfoPtr,
+struct TypeConverter<content::mojom::PresentationSessionInfoPtr,
content::PresentationSessionInfo> {
- static presentation::PresentationSessionInfoPtr Convert(
+ static content::mojom::PresentationSessionInfoPtr Convert(
const content::PresentationSessionInfo& input) {
- presentation::PresentationSessionInfoPtr output(
- presentation::PresentationSessionInfo::New());
+ content::mojom::PresentationSessionInfoPtr output(
+ content::mojom::PresentationSessionInfo::New());
output->url = input.presentation_url;
output->id = input.presentation_id;
return output;
@@ -36,20 +39,20 @@ struct TypeConverter<presentation::PresentationSessionInfoPtr,
template <>
struct TypeConverter<content::PresentationSessionInfo,
- presentation::PresentationSessionInfoPtr> {
+ content::mojom::PresentationSessionInfoPtr> {
static content::PresentationSessionInfo Convert(
- const presentation::PresentationSessionInfoPtr& input) {
+ const content::mojom::PresentationSessionInfoPtr& input) {
return content::PresentationSessionInfo(input->url, input->id);
}
};
template <>
-struct TypeConverter<presentation::PresentationErrorPtr,
+struct TypeConverter<content::mojom::PresentationErrorPtr,
content::PresentationError> {
- static presentation::PresentationErrorPtr Convert(
+ static content::mojom::PresentationErrorPtr Convert(
const content::PresentationError& input) {
- presentation::PresentationErrorPtr output(
- presentation::PresentationError::New());
+ content::mojom::PresentationErrorPtr output(
+ content::mojom::PresentationError::New());
output->error_type = PresentationErrorTypeToMojo(input.error_type);
output->message = input.message;
return output;
diff --git a/chromium/content/browser/presentation/presentation_type_converters_unittest.cc b/chromium/content/browser/presentation/presentation_type_converters_unittest.cc
index 3107aff3d03..f62c320eb19 100644
--- a/chromium/content/browser/presentation/presentation_type_converters_unittest.cc
+++ b/chromium/content/browser/presentation/presentation_type_converters_unittest.cc
@@ -13,8 +13,8 @@ TEST(PresentationTypeConvertersTest, PresentationSessionInfo) {
std::string presentation_url("http://fooUrl");
std::string presentation_id("presentationId");
PresentationSessionInfo session(presentation_url, presentation_id);
- presentation::PresentationSessionInfoPtr session_mojo(
- presentation::PresentationSessionInfo::From(session));
+ mojom::PresentationSessionInfoPtr session_mojo(
+ mojom::PresentationSessionInfo::From(session));
EXPECT_FALSE(session_mojo.is_null());
EXPECT_EQ(presentation_url, session_mojo->url);
EXPECT_EQ(presentation_id, session_mojo->id);
@@ -23,10 +23,9 @@ TEST(PresentationTypeConvertersTest, PresentationSessionInfo) {
TEST(PresentationTypeConvertersTest, PresentationError) {
std::string message("Error message");
PresentationError error(PRESENTATION_ERROR_NO_AVAILABLE_SCREENS, message);
- presentation::PresentationErrorPtr error_mojo(
- presentation::PresentationError::From(error));
+ mojom::PresentationErrorPtr error_mojo(mojom::PresentationError::From(error));
EXPECT_FALSE(error_mojo.is_null());
- EXPECT_EQ(presentation::PRESENTATION_ERROR_TYPE_NO_AVAILABLE_SCREENS,
+ EXPECT_EQ(mojom::PresentationErrorType::NO_AVAILABLE_SCREENS,
error_mojo->error_type);
EXPECT_EQ(message, error_mojo->message);
}
diff --git a/chromium/content/browser/push_messaging/push_messaging_message_filter.cc b/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
index 41668e37382..26184cf0867 100644
--- a/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -5,9 +5,11 @@
#include "content/browser/push_messaging/push_messaging_message_filter.h"
#include <string>
+#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram.h"
@@ -26,6 +28,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/console_message_level.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/push_messaging_status.h"
#include "third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h"
@@ -147,7 +150,7 @@ class PushMessagingMessageFilter::Core {
// Private Register methods on UI thread -------------------------------------
void DidRequestPermissionInIncognito(const RegisterData& data,
- PermissionStatus status);
+ blink::mojom::PermissionStatus status);
void DidRegister(const RegisterData& data,
const std::string& push_registration_id,
@@ -249,8 +252,7 @@ bool PushMessagingMessageFilter::OnMessageReceived(
void PushMessagingMessageFilter::OnSubscribeFromDocument(
int render_frame_id,
int request_id,
- const std::string& sender_id,
- bool user_visible,
+ const PushSubscriptionOptions& options,
int64_t service_worker_registration_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(mvanouwerkerk): Validate arguments?
@@ -258,7 +260,7 @@ void PushMessagingMessageFilter::OnSubscribeFromDocument(
data.request_id = request_id;
data.service_worker_registration_id = service_worker_registration_id;
data.render_frame_id = render_frame_id;
- data.user_visible = user_visible;
+ data.user_visible = options.user_visible_only;
ServiceWorkerRegistration* service_worker_registration =
service_worker_context_->GetLiveRegistration(
@@ -272,20 +274,20 @@ void PushMessagingMessageFilter::OnSubscribeFromDocument(
service_worker_context_->StoreRegistrationUserData(
service_worker_registration_id, data.requesting_origin,
- kPushSenderIdServiceWorkerKey, sender_id,
- base::Bind(&PushMessagingMessageFilter::DidPersistSenderId,
- weak_factory_io_to_io_.GetWeakPtr(), data, sender_id));
+ kPushSenderIdServiceWorkerKey, options.sender_info,
+ base::Bind(&PushMessagingMessageFilter::DidPersistSenderInfo,
+ weak_factory_io_to_io_.GetWeakPtr(), data, options));
}
void PushMessagingMessageFilter::OnSubscribeFromWorker(
int request_id,
int64_t service_worker_registration_id,
- bool user_visible) {
+ const PushSubscriptionOptions& options) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
RegisterData data;
data.request_id = request_id;
data.service_worker_registration_id = service_worker_registration_id;
- data.user_visible = user_visible;
+ data.user_visible = options.user_visible_only;
ServiceWorkerRegistration* service_worker_registration =
service_worker_context_->GetLiveRegistration(
@@ -296,34 +298,43 @@ void PushMessagingMessageFilter::OnSubscribeFromWorker(
}
data.requesting_origin = service_worker_registration->pattern().GetOrigin();
- // This sender_id will be ignored; instead it will be fetched from storage.
- CheckForExistingRegistration(data, std::string() /* sender_id */);
+ if (!options.sender_info.empty()) {
+ service_worker_context_->StoreRegistrationUserData(
+ service_worker_registration_id, data.requesting_origin,
+ kPushSenderIdServiceWorkerKey, options.sender_info,
+ base::Bind(&PushMessagingMessageFilter::DidPersistSenderInfo,
+ weak_factory_io_to_io_.GetWeakPtr(), data, options));
+ } else {
+ // If there is a sender_info in the subscription options, it will be used,
+ // otherwise the registration sender_info will be used.
+ CheckForExistingRegistration(data, options);
+ }
}
-void PushMessagingMessageFilter::DidPersistSenderId(
+void PushMessagingMessageFilter::DidPersistSenderInfo(
const RegisterData& data,
- const std::string& sender_id,
+ const PushSubscriptionOptions& options,
ServiceWorkerStatusCode service_worker_status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (service_worker_status != SERVICE_WORKER_OK)
SendSubscriptionError(data, PUSH_REGISTRATION_STATUS_STORAGE_ERROR);
else
- CheckForExistingRegistration(data, sender_id);
+ CheckForExistingRegistration(data, options);
}
void PushMessagingMessageFilter::CheckForExistingRegistration(
const RegisterData& data,
- const std::string& sender_id) {
+ const PushSubscriptionOptions& options) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
service_worker_context_->GetRegistrationUserData(
data.service_worker_registration_id, kPushRegistrationIdServiceWorkerKey,
base::Bind(&PushMessagingMessageFilter::DidCheckForExistingRegistration,
- weak_factory_io_to_io_.GetWeakPtr(), data, sender_id));
+ weak_factory_io_to_io_.GetWeakPtr(), data, options));
}
void PushMessagingMessageFilter::DidCheckForExistingRegistration(
const RegisterData& data,
- const std::string& sender_id,
+ const PushSubscriptionOptions& options,
const std::string& push_registration_id,
ServiceWorkerStatusCode service_worker_status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -344,11 +355,11 @@ void PushMessagingMessageFilter::DidCheckForExistingRegistration(
// service_worker_status != SERVICE_WORKER_ERROR_NOT_FOUND instead of
// attempting to do a fresh registration?
// https://w3c.github.io/push-api/#widl-PushRegistrationManager-register-Promise-PushRegistration
- if (data.FromDocument()) {
+ if (!options.sender_info.empty()) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&Core::RegisterOnUI, base::Unretained(ui_core_.get()), data,
- sender_id));
+ options.sender_info));
} else {
service_worker_context_->GetRegistrationUserData(
data.service_worker_registration_id, kPushSenderIdServiceWorkerKey,
@@ -391,7 +402,7 @@ void PushMessagingMessageFilter::DidGetSenderIdFromStorage(
void PushMessagingMessageFilter::Core::RegisterOnUI(
const PushMessagingMessageFilter::RegisterData& data,
- const std::string& sender_id) {
+ const std::string& sender_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PushMessagingService* push_service = service();
if (!push_service) {
@@ -427,7 +438,7 @@ void PushMessagingMessageFilter::Core::RegisterOnUI(
->GetPermissionManager()
->RequestPermission(
PermissionType::PUSH_MESSAGING, render_frame_host,
- data.requesting_origin, false /* user_gesture */,
+ data.requesting_origin,
base::Bind(&PushMessagingMessageFilter::Core::
DidRequestPermissionInIncognito,
weak_factory_ui_to_ui_.GetWeakPtr(), data));
@@ -437,16 +448,18 @@ void PushMessagingMessageFilter::Core::RegisterOnUI(
return;
}
+ PushSubscriptionOptions options;
+ options.user_visible_only = data.user_visible;
+ options.sender_info = sender_info;
if (data.FromDocument()) {
push_service->SubscribeFromDocument(
- data.requesting_origin, data.service_worker_registration_id, sender_id,
- render_process_id_, data.render_frame_id, data.user_visible,
+ data.requesting_origin, data.service_worker_registration_id,
+ render_process_id_, data.render_frame_id, options,
base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
data));
} else {
push_service->SubscribeFromWorker(
- data.requesting_origin, data.service_worker_registration_id, sender_id,
- data.user_visible,
+ data.requesting_origin, data.service_worker_registration_id, options,
base::Bind(&Core::DidRegister, weak_factory_ui_to_ui_.GetWeakPtr(),
data));
}
@@ -454,10 +467,10 @@ void PushMessagingMessageFilter::Core::RegisterOnUI(
void PushMessagingMessageFilter::Core::DidRequestPermissionInIncognito(
const RegisterData& data,
- PermissionStatus status) {
+ blink::mojom::PermissionStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Notification permission should always be denied in incognito.
- DCHECK_EQ(PERMISSION_STATUS_DENIED, status);
+ DCHECK_EQ(blink::mojom::PermissionStatus::DENIED, status);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PushMessagingMessageFilter::SendSubscriptionError, io_parent_,
@@ -914,9 +927,8 @@ void PushMessagingMessageFilter::Core::GetPermissionStatusOnUI(
request_id, blink::WebPushError::ErrorTypeNotSupported));
return;
}
- GURL embedding_origin = requesting_origin;
- permission_status = push_service->GetPermissionStatus(
- requesting_origin, embedding_origin, user_visible);
+ permission_status =
+ push_service->GetPermissionStatus(requesting_origin, user_visible);
} else if (is_incognito()) {
// Return prompt, so the website can't detect incognito mode.
permission_status = blink::WebPushPermissionStatusPrompt;
diff --git a/chromium/content/browser/push_messaging/push_messaging_message_filter.h b/chromium/content/browser/push_messaging/push_messaging_message_filter.h
index aba0b348abc..d2db18a39c8 100644
--- a/chromium/content/browser/push_messaging/push_messaging_message_filter.h
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.h
@@ -23,6 +23,7 @@ namespace content {
class PushMessagingService;
class ServiceWorkerContextWrapper;
+struct PushSubscriptionOptions;
extern const char kPushSenderIdServiceWorkerKey[];
extern const char kPushRegistrationIdServiceWorkerKey[];
@@ -50,26 +51,25 @@ class PushMessagingMessageFilter : public BrowserMessageFilter {
void OnSubscribeFromDocument(int render_frame_id,
int request_id,
- const std::string& sender_id,
- bool user_visible,
+ const PushSubscriptionOptions& options,
int64_t service_worker_registration_id);
void OnSubscribeFromWorker(int request_id,
int64_t service_worker_registration_id,
- bool user_visible);
+ const PushSubscriptionOptions& options);
- void DidPersistSenderId(const RegisterData& data,
- const std::string& sender_id,
- ServiceWorkerStatusCode service_worker_status);
+ void DidPersistSenderInfo(const RegisterData& data,
+ const PushSubscriptionOptions& options,
+ ServiceWorkerStatusCode service_worker_status);
// sender_id is ignored if data.FromDocument() is false.
void CheckForExistingRegistration(const RegisterData& data,
- const std::string& sender_id);
+ const PushSubscriptionOptions& options);
// sender_id is ignored if data.FromDocument() is false.
void DidCheckForExistingRegistration(
const RegisterData& data,
- const std::string& sender_id,
+ const PushSubscriptionOptions& options,
const std::string& push_registration_id,
ServiceWorkerStatusCode service_worker_status);
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.cc b/chromium/content/browser/push_messaging/push_messaging_router.cc
index bc95216ad07..8e93fe71ece 100644
--- a/chromium/content/browser/push_messaging/push_messaging_router.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_router.cc
@@ -10,10 +10,12 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/common/push_event_payload.h"
namespace content {
@@ -22,6 +24,7 @@ namespace {
void RunDeliverCallback(
const PushMessagingRouter::DeliverMessageCallback& deliver_message_callback,
PushDeliveryStatus delivery_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(deliver_message_callback, delivery_status));
@@ -34,7 +37,7 @@ void PushMessagingRouter::DeliverMessage(
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
StoragePartition* partition =
@@ -45,15 +48,15 @@ void PushMessagingRouter::DeliverMessage(
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PushMessagingRouter::FindServiceWorkerRegistration, origin,
- service_worker_registration_id, data, deliver_message_callback,
- service_worker_context));
+ service_worker_registration_id, payload,
+ deliver_message_callback, service_worker_context));
}
// static
void PushMessagingRouter::FindServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -62,12 +65,12 @@ void PushMessagingRouter::FindServiceWorkerRegistration(
service_worker_context->FindReadyRegistrationForId(
service_worker_registration_id, origin,
base::Bind(&PushMessagingRouter::FindServiceWorkerRegistrationCallback,
- data, deliver_message_callback));
+ payload, deliver_message_callback));
}
// static
void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback,
ServiceWorkerStatusCode service_worker_status,
const scoped_refptr<ServiceWorkerRegistration>&
@@ -87,11 +90,28 @@ void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
// alive until the callback dies. Otherwise the registration could be
// released when this method returns - before the event is delivered to the
// service worker.
- base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
+ version->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::PUSH,
+ base::Bind(&PushMessagingRouter::DeliverMessageToWorker,
+ make_scoped_refptr(version), service_worker_registration,
+ payload, deliver_message_callback),
base::Bind(&PushMessagingRouter::DeliverMessageEnd,
- deliver_message_callback, service_worker_registration);
+ deliver_message_callback, service_worker_registration));
+}
- version->DispatchPushEvent(dispatch_event_callback, data);
+// static
+void PushMessagingRouter::DeliverMessageToWorker(
+ const scoped_refptr<ServiceWorkerVersion>& service_worker,
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ const PushEventPayload& payload,
+ const DeliverMessageCallback& deliver_message_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int request_id = service_worker->StartRequest(
+ ServiceWorkerMetrics::EventType::PUSH,
+ base::Bind(&PushMessagingRouter::DeliverMessageEnd,
+ deliver_message_callback, service_worker_registration));
+ service_worker->DispatchSimpleEvent<ServiceWorkerHostMsg_PushEventFinished>(
+ request_id, ServiceWorkerMsg_PushEvent(request_id, payload));
}
// static
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.h b/chromium/content/browser/push_messaging/push_messaging_router.h
index dae9973de26..64adb8a4330 100644
--- a/chromium/content/browser/push_messaging/push_messaging_router.h
+++ b/chromium/content/browser/push_messaging/push_messaging_router.h
@@ -12,13 +12,16 @@
#include "base/memory/weak_ptr.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/common/push_messaging_status.h"
+#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerEventResult.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
+struct PushEventPayload;
class ServiceWorkerContextWrapper;
class ServiceWorkerRegistration;
+class ServiceWorkerVersion;
class PushMessagingRouter {
public:
@@ -31,7 +34,7 @@ class PushMessagingRouter {
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback);
private:
@@ -40,7 +43,7 @@ class PushMessagingRouter {
static void FindServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
@@ -48,12 +51,21 @@ class PushMessagingRouter {
// |data| on the Service Worker identified by |service_worker_registration|.
// Must be called on the IO thread.
static void FindServiceWorkerRegistrationCallback(
- const std::string& data,
+ const PushEventPayload& payload,
const DeliverMessageCallback& deliver_message_callback,
ServiceWorkerStatusCode service_worker_status,
const scoped_refptr<ServiceWorkerRegistration>&
service_worker_registration);
+ // Delivers a push message with |data| to a specific |service_worker|. Must be
+ // called on the IO thread, with the the worker running.
+ static void DeliverMessageToWorker(
+ const scoped_refptr<ServiceWorkerVersion>& service_worker,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ const PushEventPayload& payload,
+ const DeliverMessageCallback& deliver_message_callback);
+
// Gets called asynchronously after the Service Worker has dispatched the push
// event. Must be called on the IO thread.
static void DeliverMessageEnd(
diff --git a/chromium/content/browser/quota/mock_quota_manager_proxy.cc b/chromium/content/browser/quota/mock_quota_manager_proxy.cc
index a8b955d894c..697577b68b6 100644
--- a/chromium/content/browser/quota/mock_quota_manager_proxy.cc
+++ b/chromium/content/browser/quota/mock_quota_manager_proxy.cc
@@ -36,6 +36,16 @@ void MockQuotaManagerProxy::SimulateQuotaManagerDestroyed() {
}
}
+void MockQuotaManagerProxy::GetUsageAndQuota(
+ base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ StorageType type,
+ const QuotaManager::GetUsageAndQuotaCallback& callback) {
+ if (mock_manager()) {
+ mock_manager()->GetUsageAndQuota(origin, type, callback);
+ }
+}
+
void MockQuotaManagerProxy::NotifyStorageAccessed(
QuotaClient::ID client_id, const GURL& origin, StorageType type) {
++storage_accessed_count_;
diff --git a/chromium/content/browser/quota/mock_quota_manager_proxy.h b/chromium/content/browser/quota/mock_quota_manager_proxy.h
index 118761de5c9..e550a9d9de3 100644
--- a/chromium/content/browser/quota/mock_quota_manager_proxy.h
+++ b/chromium/content/browser/quota/mock_quota_manager_proxy.h
@@ -41,7 +41,7 @@ class MockQuotaManagerProxy : public QuotaManagerProxy {
base::SequencedTaskRunner* original_task_runner,
const GURL& origin,
StorageType type,
- const QuotaManager::GetUsageAndQuotaCallback& callback) override {}
+ const QuotaManager::GetUsageAndQuotaCallback& callback) override;
// Validates the |client_id| and updates the internal access count
// which can be accessed via notify_storage_accessed_count().
diff --git a/chromium/content/browser/quota/quota_backend_impl_unittest.cc b/chromium/content/browser/quota/quota_backend_impl_unittest.cc
index 516cab3e1bd..5dfa037185f 100644
--- a/chromium/content/browser/quota/quota_backend_impl_unittest.cc
+++ b/chromium/content/browser/quota/quota_backend_impl_unittest.cc
@@ -10,6 +10,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/thread_task_runner_handle.h"
#include "storage/browser/fileapi/file_system_usage_cache.h"
#include "storage/browser/fileapi/obfuscated_file_util.h"
diff --git a/chromium/content/browser/quota/quota_manager_unittest.cc b/chromium/content/browser/quota/quota_manager_unittest.cc
index 80889ba8b30..665acd953b7 100644
--- a/chromium/content/browser/quota/quota_manager_unittest.cc
+++ b/chromium/content/browser/quota/quota_manager_unittest.cc
@@ -67,10 +67,17 @@ const int kPerHostTemporaryPortion = QuotaManager::kPerHostTemporaryPortion;
const GURL kTestEvictionOrigin = GURL("http://test.eviction.policy/result");
// Returns a deterministic value for the amount of available disk space.
-int64_t GetAvailableDiskSpaceForTest(const base::FilePath&) {
+int64_t GetAvailableDiskSpaceForTest() {
return kAvailableSpaceForApp + kMinimumPreserveForSystem;
}
+bool GetVolumeInfoForTests(const base::FilePath&,
+ uint64_t* available, uint64_t* total) {
+ *available = static_cast<uint64_t>(GetAvailableDiskSpaceForTest());
+ *total = *available * 2;
+ return true;
+}
+
class TestEvictionPolicy : public storage::QuotaEvictionPolicy {
public:
TestEvictionPolicy() {}
@@ -122,7 +129,7 @@ class QuotaManagerTest : public testing::Test {
// Don't (automatically) start the eviction for testing.
quota_manager_->eviction_disabled_ = true;
// Don't query the hard disk for remaining capacity.
- quota_manager_->get_disk_space_fn_ = &GetAvailableDiskSpaceForTest;
+ quota_manager_->get_volume_info_fn_= &GetVolumeInfoForTests;
additional_callback_count_ = 0;
}
@@ -670,7 +677,7 @@ TEST_F(QuotaManagerTest, GetUsage_MultipleClients) {
QuotaClient::kDatabase));
const int64_t kTempQuotaBase =
- GetAvailableDiskSpaceForTest(base::FilePath()) / kPerHostTemporaryPortion;
+ GetAvailableDiskSpaceForTest() / kPerHostTemporaryPortion;
GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp);
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/quota/quota_reservation_manager_unittest.cc b/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
index d2588e168e7..2a9d2e44582 100644
--- a/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
+++ b/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
diff --git a/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc b/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
index 21478c3c635..351c8a1b60b 100644
--- a/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -50,6 +50,12 @@ class MockQuotaEvictionHandler : public storage::QuotaEvictionHandler {
callback.Run(storage::kQuotaStatusOk);
}
+ void AsyncGetVolumeInfo(const VolumeInfoCallback& callback) override {
+ uint64_t available = static_cast<uint64_t>(available_space_);
+ uint64_t total = (1024 * 1024 * 1024) + (2 * available); // 1G plus some.
+ callback.Run(true, available, total);
+ }
+
void GetUsageAndQuotaForEviction(
const UsageAndQuotaCallback& callback) override {
if (error_on_get_usage_and_quota_) {
diff --git a/chromium/content/browser/quota/storage_monitor_unittest.cc b/chromium/content/browser/quota/storage_monitor_unittest.cc
index 002e860b9df..e0f9cce6f8e 100644
--- a/chromium/content/browser/quota/storage_monitor_unittest.cc
+++ b/chromium/content/browser/quota/storage_monitor_unittest.cc
@@ -11,7 +11,7 @@
#include "base/thread_task_runner_handle.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/mock_storage_client.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/storage_monitor.h"
diff --git a/chromium/content/browser/quota/usage_tracker_unittest.cc b/chromium/content/browser/quota/usage_tracker_unittest.cc
index 78d19b2de3d..887772d943a 100644
--- a/chromium/content/browser/quota/usage_tracker_unittest.cc
+++ b/chromium/content/browser/quota/usage_tracker_unittest.cc
@@ -11,7 +11,7 @@
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "content/public/test/mock_special_storage_policy.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/usage_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/content/browser/quota_dispatcher_host.cc b/chromium/content/browser/quota_dispatcher_host.cc
index 8f2043bb4e4..512beaf6aad 100644
--- a/chromium/content/browser/quota_dispatcher_host.cc
+++ b/chromium/content/browser/quota_dispatcher_host.cc
@@ -12,7 +12,7 @@
#include "base/trace_event/trace_event.h"
#include "content/common/quota_messages.h"
#include "content/public/browser/quota_permission_context.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/quota_manager.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/renderer_host/DEPS b/chromium/content/browser/renderer_host/DEPS
index e20b55810dc..8c4fbe05818 100644
--- a/chromium/content/browser/renderer_host/DEPS
+++ b/chromium/content/browser/renderer_host/DEPS
@@ -23,13 +23,6 @@ specific_include_rules = {
"+content/public/browser/web_contents_view.h",
"+media/renderers",
],
- "sandbox_ipc_linux\.cc": [
- "+third_party/WebKit/public/platform/linux/WebFontInfo.h",
- "+third_party/WebKit/public/web/WebKit.h",
- ],
- "sandbox_ipc_linux\.h": [
- "+content/child/blink_platform_impl.h",
- ],
"render_process_host_impl\.cc": [
"+content/browser/frame_host/render_frame_message_filter.h",
],
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.h b/chromium/content/browser/renderer_host/browser_compositor_view_mac.h
index c6ee6ffe345..9ad7e483b4e 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.h
+++ b/chromium/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
-#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_BROWSER_COMPOSITOR_VIEW_MAC_H_
+#define CONTENT_BROWSER_RENDERER_HOST_BROWSER_COMPOSITOR_VIEW_MAC_H_
#include "base/macros.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
@@ -75,4 +75,4 @@ class BrowserCompositorMacPlaceholder {
} // namespace content
-#endif // CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_BROWSER_COMPOSITOR_VIEW_MAC_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.mm b/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm
index 4670ed02ced..92ac2e7f131 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.mm
+++ b/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/compositor/browser_compositor_view_mac.h"
+#include "content/browser/renderer_host/browser_compositor_view_mac.h"
#include <stdint.h>
@@ -11,9 +11,7 @@
#include "base/lazy_instance.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/compositor/image_transport_factory.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/public/browser/context_factory.h"
-#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
@@ -34,18 +32,12 @@ uint32_t g_placeholder_count = 0;
// A spare BrowserCompositorMac kept around for recycling.
base::LazyInstance<scoped_ptr<BrowserCompositorMac>>
- g_recyclable_browser_compositor;
-
-bool WidgetNeedsGLFinishWorkaround() {
- return GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
- gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
-}
+ g_recyclable_browser_compositor;
} // namespace
BrowserCompositorMac::BrowserCompositorMac()
- : accelerated_widget_mac_(
- new ui::AcceleratedWidgetMac(WidgetNeedsGLFinishWorkaround())),
+ : accelerated_widget_mac_(new ui::AcceleratedWidgetMac()),
compositor_(content::GetContextFactory(),
ui::WindowResizeHelperMac::Get()->task_runner()) {
compositor_.SetAcceleratedWidget(
diff --git a/chromium/content/browser/renderer_host/clipboard_message_filter.cc b/chromium/content/browser/renderer_host/clipboard_message_filter.cc
index dea3d127604..e50fedb5cb9 100644
--- a/chromium/content/browser/renderer_host/clipboard_message_filter.cc
+++ b/chromium/content/browser/renderer_host/clipboard_message_filter.cc
@@ -250,11 +250,7 @@ void ClipboardMessageFilter::OnWriteImage(ui::ClipboardType clipboard_type,
}
scoped_ptr<base::SharedMemory> bitmap_buffer(
-#if defined(OS_WIN)
- new base::SharedMemory(handle, true, PeerHandle()));
-#else
new base::SharedMemory(handle, true));
-#endif
SkBitmap bitmap;
// Let Skia do some sanity checking for (no negative widths/heights, no
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.cc b/chromium/content/browser/renderer_host/compositor_impl_android.cc
index 74f1e70e44e..43a22a0504b 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.cc
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.cc
@@ -21,6 +21,7 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/sys_info.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
@@ -42,17 +43,15 @@
#include "cc/trees/layer_tree_settings.h"
#include "content/browser/android/child_process_launcher_android.h"
#include "content/browser/compositor/browser_compositor_overlay_candidate_validator_android.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/common/gpu/client/command_buffer_proxy_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/android/compositor_client.h"
@@ -60,6 +59,8 @@
#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/ipc/client/command_buffer_proxy_impl.h"
+#include "gpu/ipc/client/gpu_channel_host.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkMallocPixelRef.h"
@@ -127,11 +128,11 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface,
}
private:
- CommandBufferProxyImpl* GetCommandBufferProxy() {
+ gpu::CommandBufferProxyImpl* GetCommandBufferProxy() {
ContextProviderCommandBuffer* provider_command_buffer =
static_cast<content::ContextProviderCommandBuffer*>(
context_provider_.get());
- CommandBufferProxyImpl* command_buffer_proxy =
+ gpu::CommandBufferProxyImpl* command_buffer_proxy =
provider_command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
return command_buffer_proxy;
@@ -168,8 +169,7 @@ class ExternalBeginFrameSource : public cc::BeginFrameSourceBase,
}
// cc::BeginFrameSourceBase implementation:
- void OnNeedsBeginFramesChange(
- bool needs_begin_frames) override {
+ void OnNeedsBeginFramesChanged(bool needs_begin_frames) override {
compositor_->OnNeedsBeginFramesChange(needs_begin_frames);
}
@@ -187,7 +187,6 @@ class ExternalBeginFrameSource : public cc::BeginFrameSourceBase,
static bool g_initialized = false;
-bool g_use_surface_manager = false;
base::LazyInstance<cc::SurfaceManager> g_surface_manager =
LAZY_INSTANCE_INITIALIZER;
@@ -196,8 +195,7 @@ int g_surface_id_namespace = 0;
class SingleThreadTaskGraphRunner : public cc::SingleThreadTaskGraphRunner {
public:
SingleThreadTaskGraphRunner() {
- Start("CompositorTileWorker1",
- base::SimpleThread::Options(base::ThreadPriority::BACKGROUND));
+ Start("CompositorTileWorker1", base::SimpleThread::Options());
}
~SingleThreadTaskGraphRunner() override {
@@ -220,17 +218,6 @@ Compositor* Compositor::Create(CompositorClient* client,
void Compositor::Initialize() {
DCHECK(!CompositorImpl::IsInitialized());
g_initialized = true;
- g_use_surface_manager = UseSurfacesEnabled();
-}
-
-// static
-const cc::LayerSettings& Compositor::LayerSettings() {
- return ui::WindowAndroidCompositor::LayerSettings();
-}
-
-// static
-void Compositor::SetLayerSettings(const cc::LayerSettings& settings) {
- ui::WindowAndroidCompositor::SetLayerSettings(settings);
}
// static
@@ -240,8 +227,6 @@ bool CompositorImpl::IsInitialized() {
// static
cc::SurfaceManager* CompositorImpl::GetSurfaceManager() {
- if (!g_use_surface_manager)
- return nullptr;
return g_surface_manager.Pointer();
}
@@ -257,10 +242,9 @@ scoped_ptr<cc::SurfaceIdAllocator> CompositorImpl::CreateSurfaceIdAllocator() {
CompositorImpl::CompositorImpl(CompositorClient* client,
gfx::NativeWindow root_window)
- : root_layer_(cc::Layer::Create(Compositor::LayerSettings())),
+ : root_layer_(cc::Layer::Create()),
+ surface_id_allocator_(CreateSurfaceIdAllocator()),
resource_manager_(root_window),
- surface_id_allocator_(GetSurfaceManager() ? CreateSurfaceIdAllocator()
- : nullptr),
has_transparent_background_(false),
device_scale_factor_(1),
window_(NULL),
@@ -334,9 +318,6 @@ void CompositorImpl::SetSurface(jobject surface) {
window_ = window;
ANativeWindow_acquire(window);
surface_id_ = tracker->AddSurfaceForNativeWidget(window);
- tracker->SetSurfaceHandle(
- surface_id_,
- gfx::GLSurfaceHandle(surface_id_, gfx::NATIVE_DIRECT));
// Register first, SetVisible() might create an OutputSurface.
RegisterViewSurface(surface_id_, j_surface.obj());
SetVisible(true);
@@ -357,13 +338,10 @@ void CompositorImpl::CreateLayerTreeHost() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
settings.initial_debug_state.SetRecordRenderingStats(
command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
- if (command_line->HasSwitch(cc::switches::kDisableCompositorPropertyTrees))
- settings.use_property_trees = false;
+ settings.initial_debug_state.show_fps_counter =
+ command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
settings.single_thread_proxy_scheduler = true;
- settings.use_compositor_animation_timelines = !command_line->HasSwitch(
- switches::kDisableAndroidCompositorAnimationTimelines);
-
cc::LayerTreeHost::InitParams params;
params.client = this;
params.shared_bitmap_manager = HostSharedBitmapManager::current();
@@ -375,8 +353,7 @@ void CompositorImpl::CreateLayerTreeHost() {
host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
DCHECK(!host_->visible());
host_->SetRootLayer(root_layer_);
- if (surface_id_allocator_)
- host_->set_surface_id_namespace(surface_id_allocator_->id_namespace());
+ host_->set_surface_id_namespace(surface_id_allocator_->id_namespace());
host_->SetViewportSize(size_);
host_->set_has_transparent_background(has_transparent_background_);
host_->SetDeviceScaleFactor(device_scale_factor_);
@@ -434,8 +411,8 @@ void CompositorImpl::SetNeedsComposite() {
static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
CreateGpuProcessViewContext(
- const scoped_refptr<GpuChannelHost>& gpu_channel_host,
- const blink::WebGraphicsContext3D::Attributes attributes,
+ const scoped_refptr<gpu::GpuChannelHost>& gpu_channel_host,
+ const gpu::gles2::ContextCreationAttribHelper& attributes,
int surface_id) {
GURL url("chrome://gpu/Compositor::createContext3D");
static const size_t kBytesPerPixel = 4;
@@ -451,15 +428,14 @@ CreateGpuProcessViewContext(
limits.max_transfer_buffer_size = std::min(
3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
- bool lose_context_when_out_of_memory = true;
- return make_scoped_ptr(
- new WebGraphicsContext3DCommandBufferImpl(surface_id,
- url,
- gpu_channel_host.get(),
- attributes,
- lose_context_when_out_of_memory,
- limits,
- NULL));
+ GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
+ gpu::SurfaceHandle surface_handle = tracker->GetSurfaceHandle(surface_id);
+ bool share_resources = true;
+ bool automatic_flushes = false;
+ return make_scoped_ptr(new WebGraphicsContext3DCommandBufferImpl(
+ surface_handle, url, gpu_channel_host.get(), attributes,
+ gfx::PreferIntegratedGpu, share_resources, automatic_flushes, limits,
+ nullptr));
}
void CompositorImpl::UpdateLayerTreeHost() {
@@ -524,9 +500,34 @@ void CompositorImpl::CreateOutputSurface() {
if (!output_surface_request_pending_ || !host_->visible())
return;
- blink::WebGraphicsContext3D::Attributes attrs;
- attrs.shareResources = true;
- attrs.noAutomaticFlushes = true;
+ // This is used for the browser compositor (offscreen) and for the display
+ // compositor (onscreen), so ask for capabilities needed by either one.
+ // The default framebuffer for an offscreen context is not used, so it does
+ // not need alpha, stencil, depth, antialiasing. The display compositor does
+ // not use these things either, except for alpha when it has a transparent
+ // background.
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = -1;
+ attributes.stencil_size = 0;
+ attributes.depth_size = 0;
+ attributes.samples = 0;
+ attributes.sample_buffers = 0;
+ attributes.bind_generates_resource = false;
+
+ if (has_transparent_background_) {
+ attributes.alpha_size = 8;
+ } else if (base::SysInfo::IsLowEndDevice()) {
+ // In this case we prefer to use RGB565 format instead of RGBA8888 if
+ // possible.
+ // TODO(danakj): GpuCommandBufferStub constructor checks for alpha == 0 in
+ // order to enable 565, but it should avoid using 565 when -1s are specified
+ // (IOW check that a <= 0 && rgb > 0 && rgb <= 565) then alpha should be -1.
+ attributes.alpha_size = 0;
+ attributes.red_size = 5;
+ attributes.green_size = 6;
+ attributes.blue_size = 5;
+ }
+
pending_swapbuffers_ = 0;
DCHECK(window_);
@@ -538,11 +539,12 @@ void CompositorImpl::CreateOutputSurface() {
// still get marked as lost from the IO thread, at any point in time really).
// But from here on just try and always lead to either
// DidInitializeOutputSurface() or DidFailToInitializeOutputSurface().
- scoped_refptr<GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
scoped_refptr<ContextProviderCommandBuffer> context_provider(
ContextProviderCommandBuffer::Create(
- CreateGpuProcessViewContext(gpu_channel_host, attrs, surface_id_),
- BROWSER_COMPOSITOR_ONSCREEN_CONTEXT));
+ CreateGpuProcessViewContext(gpu_channel_host, attributes,
+ surface_id_),
+ DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT));
DCHECK(context_provider.get());
scoped_ptr<cc::OutputSurface> real_output_surface(
@@ -552,24 +554,20 @@ void CompositorImpl::CreateOutputSurface() {
base::Unretained(this))));
cc::SurfaceManager* manager = GetSurfaceManager();
- if (manager) {
- display_client_.reset(
- new cc::OnscreenDisplayClient(std::move(real_output_surface), manager,
- HostSharedBitmapManager::current(),
- BrowserGpuMemoryBufferManager::current(),
- host_->settings().renderer_settings,
- base::ThreadTaskRunnerHandle::Get()));
- scoped_ptr<cc::SurfaceDisplayOutputSurface> surface_output_surface(
- new cc::SurfaceDisplayOutputSurface(
- manager, surface_id_allocator_.get(), context_provider, nullptr));
-
- display_client_->set_surface_output_surface(surface_output_surface.get());
- surface_output_surface->set_display_client(display_client_.get());
- display_client_->display()->Resize(size_);
- host_->SetOutputSurface(std::move(surface_output_surface));
- } else {
- host_->SetOutputSurface(std::move(real_output_surface));
- }
+ display_client_.reset(
+ new cc::OnscreenDisplayClient(std::move(real_output_surface), manager,
+ HostSharedBitmapManager::current(),
+ BrowserGpuMemoryBufferManager::current(),
+ host_->settings().renderer_settings,
+ base::ThreadTaskRunnerHandle::Get()));
+ scoped_ptr<cc::SurfaceDisplayOutputSurface> surface_output_surface(
+ new cc::SurfaceDisplayOutputSurface(
+ manager, surface_id_allocator_.get(), context_provider, nullptr));
+
+ display_client_->set_surface_output_surface(surface_output_surface.get());
+ surface_output_surface->set_display_client(display_client_.get());
+ display_client_->display()->Resize(size_);
+ host_->SetOutputSurface(std::move(surface_output_surface));
}
void CompositorImpl::PopulateGpuCapabilities(
@@ -624,10 +622,6 @@ void CompositorImpl::DidCommit() {
root_window_->OnCompositingDidCommit();
}
-void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) {
- root_layer_->AddChild(layer);
-}
-
void CompositorImpl::RequestCopyOfOutputOnRootLayer(
scoped_ptr<cc::CopyOutputRequest> request) {
root_layer_->RequestCopyOfOutput(std::move(request));
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.h b/chromium/content/browser/renderer_host/compositor_impl_android.h
index 9b1a60eb0e9..4bc304ff84c 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.h
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.h
@@ -113,7 +113,6 @@ class CONTENT_EXPORT CompositorImpl
void DidAbortSwapBuffers() override;
// WindowAndroidCompositor implementation.
- void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
void RequestCopyOfOutputOnRootLayer(
scoped_ptr<cc::CopyOutputRequest> request) override;
void OnVSync(base::TimeTicks frame_time,
@@ -132,12 +131,12 @@ class CONTENT_EXPORT CompositorImpl
scoped_refptr<cc::Layer> subroot_layer_;
// Destruction order matters here:
+ scoped_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
base::ObserverList<VSyncObserver, true> observer_list_;
scoped_ptr<cc::LayerTreeHost> host_;
ui::ResourceManagerImpl resource_manager_;
scoped_ptr<cc::OnscreenDisplayClient> display_client_;
- scoped_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
gfx::Size size_;
bool has_transparent_background_;
diff --git a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h
index 981694f329c..f12e43842b5 100644
--- a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h
+++ b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h
@@ -9,7 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
-#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/renderer_host/resize_lock.h"
namespace aura {
class WindowTreeHost;
diff --git a/chromium/content/browser/renderer_host/database_message_filter.cc b/chromium/content/browser/renderer_host/database_message_filter.cc
index 9c9f16ea45e..5f9a8ae5d72 100644
--- a/chromium/content/browser/renderer_host/database_message_filter.cc
+++ b/chromium/content/browser/renderer_host/database_message_filter.cc
@@ -163,12 +163,11 @@ void DatabaseMessageFilter::OnDatabaseOpenFile(
// database tracker.
*handle = IPC::InvalidPlatformFileForTransit();
if (file.IsValid()) {
- *handle = IPC::TakeFileHandleForProcess(std::move(file), PeerHandle());
+ *handle = IPC::TakePlatformFileForTransit(std::move(file));
} else if (tracked_file) {
DCHECK(tracked_file->IsValid());
*handle =
- IPC::GetFileHandleForProcess(tracked_file->GetPlatformFile(),
- PeerHandle(), false);
+ IPC::GetPlatformFileForTransit(tracked_file->GetPlatformFile(), false);
}
}
@@ -305,7 +304,7 @@ void DatabaseMessageFilter::OnDatabaseOpened(
int64_t estimated_size) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- if (!DatabaseUtil::IsValidOriginIdentifier(origin_identifier)) {
+ if (!storage::IsValidOriginIdentifier(origin_identifier)) {
bad_message::ReceivedBadMessage(this,
bad_message::DBMF_INVALID_ORIGIN_ON_OPEN);
return;
@@ -357,7 +356,7 @@ void DatabaseMessageFilter::OnHandleSqliteError(
const base::string16& database_name,
int error) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- if (!DatabaseUtil::IsValidOriginIdentifier(origin_identifier)) {
+ if (!storage::IsValidOriginIdentifier(origin_identifier)) {
bad_message::ReceivedBadMessage(
this, bad_message::DBMF_INVALID_ORIGIN_ON_SQLITE_ERROR);
return;
diff --git a/chromium/content/browser/compositor/delegated_frame_host.cc b/chromium/content/browser/renderer_host/delegated_frame_host.cc
index f381da0eadd..e103e320e66 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.cc
+++ b/chromium/content/browser/renderer_host/delegated_frame_host.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 "content/browser/compositor/delegated_frame_host.h"
+#include "content/browser/renderer_host/delegated_frame_host.h"
#include <algorithm>
#include <string>
@@ -21,10 +21,10 @@
#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_hittest.h"
#include "cc/surfaces/surface_manager.h"
-#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/gpu/compositor_util.h"
-#include "content/common/gpu/client/gl_helper.h"
+#include "content/browser/renderer_host/resize_lock.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/common/content_switches.h"
#include "media/base/video_frame.h"
@@ -65,24 +65,26 @@ void RequireCallback(cc::SurfaceManager* manager,
DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
: client_(client),
compositor_(nullptr),
- use_surfaces_(UseSurfacesEnabled()),
tick_clock_(new base::DefaultTickClock()),
last_output_surface_id_(0),
pending_delegated_ack_count_(0),
skipped_frames_(false),
+ background_color_(SK_ColorRED),
current_scale_factor_(1.f),
can_lock_compositor_(YES_CAN_LOCK),
- delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
+ delegated_frame_evictor_(new DelegatedFrameEvictor(this)),
+ begin_frame_source_(nullptr) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->AddObserver(this);
id_allocator_ = factory->GetContextFactory()->CreateSurfaceIdAllocator();
+ factory->GetSurfaceManager()->RegisterSurfaceFactoryClient(
+ id_allocator_->id_namespace(), this);
}
void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
delegated_frame_evictor_->SetVisible(true);
- if (surface_id_.is_null() && !frame_provider_.get() &&
- !released_front_lock_.get()) {
+ if (surface_id_.is_null() && !released_front_lock_.get()) {
if (compositor_)
released_front_lock_ = compositor_->GetCompositorLock();
}
@@ -151,8 +153,8 @@ void DelegatedFrameHost::CopyFromCompositingSurface(
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(
- base::Bind(&DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
- output_size, preferred_color_type, callback));
+ base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
+ preferred_color_type, callback));
if (!src_subrect.IsEmpty())
request->set_area(src_subrect);
RequestCopyOfOutput(std::move(request));
@@ -169,12 +171,9 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(base::Bind(
- &DelegatedFrameHost::
- CopyFromCompositingSurfaceHasResultForVideo,
+ &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
- nullptr,
- target,
- callback));
+ nullptr, target, callback));
request->set_area(src_subrect);
RequestCopyOfOutput(std::move(request));
}
@@ -200,18 +199,16 @@ void DelegatedFrameHost::EndFrameSubscription() {
}
uint32_t DelegatedFrameHost::GetSurfaceIdNamespace() {
- if (!use_surfaces_)
- return 0;
-
return id_allocator_->id_namespace();
}
cc::SurfaceId DelegatedFrameHost::SurfaceIdAtPoint(
+ cc::SurfaceHittestDelegate* delegate,
const gfx::Point& point,
gfx::Point* transformed_point) {
if (surface_id_.is_null())
return surface_id_;
- cc::SurfaceHittest hittest(nullptr, GetSurfaceManager());
+ cc::SurfaceHittest hittest(delegate, GetSurfaceManager());
gfx::Transform target_transform;
cc::SurfaceId target_surface_id =
hittest.GetTargetSurfaceAtPoint(surface_id_, point, &target_transform);
@@ -243,8 +240,7 @@ bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
// to replace it. Otherwise may cause hangs when the renderer is waiting for
// the completion of latency infos (such as when taking a Snapshot.)
if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
- can_lock_compositor_ == NO_PENDING_COMMIT ||
- !resize_lock_.get())
+ can_lock_compositor_ == NO_PENDING_COMMIT || !resize_lock_.get())
return false;
return size_in_dip != resize_lock_->expected_size();
@@ -256,6 +252,45 @@ void DelegatedFrameHost::WasResized() {
!client_->DelegatedFrameHostIsVisible())
EvictDelegatedFrame();
MaybeCreateResizeLock();
+ UpdateGutters();
+}
+
+void DelegatedFrameHost::UpdateGutters() {
+ if (surface_id_.is_null()) {
+ right_gutter_.reset();
+ bottom_gutter_.reset();
+ return;
+ }
+ if (current_frame_size_in_dip_.width() <
+ client_->DelegatedFrameHostDesiredSizeInDIP().width()) {
+ right_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+ right_gutter_->SetColor(background_color_);
+ int width = client_->DelegatedFrameHostDesiredSizeInDIP().width() -
+ current_frame_size_in_dip_.width();
+ // The right gutter also includes the bottom-right corner, if necessary.
+ int height = client_->DelegatedFrameHostDesiredSizeInDIP().height();
+ right_gutter_->SetBounds(
+ gfx::Rect(current_frame_size_in_dip_.width(), 0, width, height));
+
+ client_->DelegatedFrameHostGetLayer()->Add(right_gutter_.get());
+ } else {
+ right_gutter_.reset();
+ }
+
+ if (current_frame_size_in_dip_.height() <
+ client_->DelegatedFrameHostDesiredSizeInDIP().height()) {
+ bottom_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+ bottom_gutter_->SetColor(background_color_);
+ int width = current_frame_size_in_dip_.width();
+ int height = client_->DelegatedFrameHostDesiredSizeInDIP().height() -
+ current_frame_size_in_dip_.height();
+ bottom_gutter_->SetBounds(
+ gfx::Rect(0, current_frame_size_in_dip_.height(), width, height));
+ client_->DelegatedFrameHostGetLayer()->Add(bottom_gutter_.get());
+
+ } else {
+ bottom_gutter_.reset();
+ }
}
gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
@@ -292,8 +327,8 @@ void DelegatedFrameHost::AttemptFrameSubscriberCapture(
scoped_refptr<media::VideoFrame> frame;
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
- if (!frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
- &frame, &callback))
+ if (!frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time, &frame,
+ &callback))
return;
// Get a texture to re-use; else, create a new one.
@@ -309,9 +344,7 @@ void DelegatedFrameHost::AttemptFrameSubscriberCapture(
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(base::Bind(
&DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
- AsWeakPtr(),
- subscriber_texture,
- frame,
+ AsWeakPtr(), subscriber_texture, frame,
base::Bind(callback, present_time)));
// Setting the source in this copy request asks that the layer abort any prior
// uncommitted copy requests made on behalf of the same frame subscriber.
@@ -398,125 +431,79 @@ void DelegatedFrameHost::SwapDelegatedFrame(
if (!surface_returned_resources_.empty())
SendReturnedDelegatedResources(last_output_surface_id_);
- // Drop the cc::DelegatedFrameResourceCollection so that we will not return
- // any resources from the old output surface with the new output surface id.
- if (resource_collection_.get()) {
- resource_collection_->SetClient(NULL);
-
- if (resource_collection_->LoseAllResources())
- SendReturnedDelegatedResources(last_output_surface_id_);
-
- resource_collection_ = NULL;
- }
last_output_surface_id_ = output_surface_id;
}
- bool immediate_ack = !compositor_;
+ bool skip_frame = false;
pending_delegated_ack_count_++;
+ background_color_ = frame->metadata.root_background_color;
+
if (frame_size.IsEmpty()) {
DCHECK(frame_data->resource_list.empty());
EvictDelegatedFrame();
} else {
- if (use_surfaces_) {
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- cc::SurfaceManager* manager = factory->GetSurfaceManager();
- if (!surface_factory_) {
- surface_factory_ =
- make_scoped_ptr(new cc::SurfaceFactory(manager, this));
- }
- if (surface_id_.is_null() || frame_size != current_surface_size_ ||
- frame_size_in_dip != current_frame_size_in_dip_) {
- if (!surface_id_.is_null())
- surface_factory_->Destroy(surface_id_);
- surface_id_ = id_allocator_->GenerateId();
- surface_factory_->Create(surface_id_);
- // manager must outlive compositors using it.
- client_->DelegatedFrameHostGetLayer()->SetShowSurface(
- surface_id_,
- base::Bind(&SatisfyCallback, base::Unretained(manager)),
- base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
- frame_device_scale_factor, frame_size_in_dip);
- current_surface_size_ = frame_size;
- current_scale_factor_ = frame_device_scale_factor;
- }
-
- frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
- skipped_latency_info_list_.begin(),
- skipped_latency_info_list_.end());
- skipped_latency_info_list_.clear();
-
- gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
- if (desired_size != frame_size_in_dip && !desired_size.IsEmpty())
- immediate_ack = true;
-
- cc::SurfaceFactory::DrawCallback ack_callback;
- if (compositor_ && !immediate_ack) {
- ack_callback = base::Bind(&DelegatedFrameHost::SurfaceDrawn,
- AsWeakPtr(), output_surface_id);
- }
- surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
- ack_callback);
- } else {
- if (!resource_collection_.get()) {
- resource_collection_ = new cc::DelegatedFrameResourceCollection;
- resource_collection_->SetClient(this);
- }
- // If the physical frame size changes, we need a new |frame_provider_|. If
- // the physical frame size is the same, but the size in DIP changed, we
- // need to adjust the scale at which the frames will be drawn, and we do
- // this by making a new |frame_provider_| also to ensure the scale change
- // is presented in sync with the new frame content.
- if (!frame_provider_.get() ||
- frame_size != frame_provider_->frame_size() ||
- frame_size_in_dip != current_frame_size_in_dip_) {
- frame_provider_ = new cc::DelegatedFrameProvider(
- resource_collection_.get(), std::move(frame->delegated_frame_data));
- client_->DelegatedFrameHostGetLayer()->SetShowDelegatedContent(
- frame_provider_.get(), frame_size_in_dip);
- } else {
- frame_provider_->SetFrameData(std::move(frame->delegated_frame_data));
- }
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ if (!surface_factory_) {
+ surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
+ }
+ if (surface_id_.is_null() || frame_size != current_surface_size_ ||
+ frame_size_in_dip != current_frame_size_in_dip_) {
+ if (!surface_id_.is_null())
+ surface_factory_->Destroy(surface_id_);
+ surface_id_ = id_allocator_->GenerateId();
+ surface_factory_->Create(surface_id_);
+ // manager must outlive compositors using it.
+ client_->DelegatedFrameHostGetLayer()->SetShowSurface(
+ surface_id_, base::Bind(&SatisfyCallback, base::Unretained(manager)),
+ base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
+ frame_device_scale_factor, frame_size_in_dip);
+ current_surface_size_ = frame_size;
+ current_scale_factor_ = frame_device_scale_factor;
}
+
+ frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
+ skipped_latency_info_list_.begin(),
+ skipped_latency_info_list_.end());
+ skipped_latency_info_list_.clear();
+
+ gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
+ if (desired_size != frame_size_in_dip && !desired_size.IsEmpty())
+ skip_frame = true;
+
+ cc::SurfaceFactory::DrawCallback ack_callback;
+ if (compositor_ && !skip_frame) {
+ ack_callback = base::Bind(&DelegatedFrameHost::SurfaceDrawn, AsWeakPtr(),
+ output_surface_id);
+ }
+ surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
+ ack_callback);
}
released_front_lock_ = NULL;
current_frame_size_in_dip_ = frame_size_in_dip;
CheckResizeLock();
+ UpdateGutters();
+
if (!damage_rect_in_dip.IsEmpty())
client_->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage(
damage_rect_in_dip);
- if (immediate_ack) {
+ // Note that |compositor_| may be reset by SetShowSurface or
+ // SetShowDelegatedContent above.
+ if (!compositor_ || skip_frame) {
SendDelegatedFrameAck(output_surface_id);
- } else if (!use_surfaces_) {
- std::vector<ui::LatencyInfo>::const_iterator it;
- for (it = frame->metadata.latency_info.begin();
- it != frame->metadata.latency_info.end(); ++it)
- compositor_->SetLatencyInfo(*it);
- // If we've previously skipped any latency infos add them.
- for (it = skipped_latency_info_list_.begin();
- it != skipped_latency_info_list_.end();
- ++it)
- compositor_->SetLatencyInfo(*it);
- skipped_latency_info_list_.clear();
- AddOnCommitCallbackAndDisableLocks(
- base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
- AsWeakPtr(), output_surface_id));
} else {
- AddOnCommitCallbackAndDisableLocks(base::Closure());
+ can_lock_compositor_ = NO_PENDING_COMMIT;
}
- // With Surfaces, WillDrawSurface() will be called as the trigger to attempt
- // a frame subscriber capture instead.
- if (!use_surfaces_)
- AttemptFrameSubscriberCapture(damage_rect);
- if (frame_provider_.get() || !surface_id_.is_null())
+ if (!surface_id_.is_null())
delegated_frame_evictor_->SwappedFrame(
client_->DelegatedFrameHostIsVisible());
// Note: the frame may have been evicted immediately.
}
void DelegatedFrameHost::ClearDelegatedFrame() {
- if (frame_provider_.get() || !surface_id_.is_null())
+ if (!surface_id_.is_null())
EvictDelegatedFrame();
}
@@ -524,8 +511,6 @@ void DelegatedFrameHost::SendDelegatedFrameAck(uint32_t output_surface_id) {
cc::CompositorFrameAck ack;
if (!surface_returned_resources_.empty())
ack.resources.swap(surface_returned_resources_);
- if (resource_collection_.get())
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
DCHECK_GT(pending_delegated_ack_count_, 0);
pending_delegated_ack_count_--;
@@ -536,23 +521,11 @@ void DelegatedFrameHost::SurfaceDrawn(uint32_t output_surface_id,
SendDelegatedFrameAck(output_surface_id);
}
-void DelegatedFrameHost::UnusedResourcesAreAvailable() {
- if (pending_delegated_ack_count_)
- return;
-
- SendReturnedDelegatedResources(last_output_surface_id_);
-}
-
void DelegatedFrameHost::SendReturnedDelegatedResources(
uint32_t output_surface_id) {
cc::CompositorFrameAck ack;
- if (!surface_returned_resources_.empty()) {
- ack.resources.swap(surface_returned_resources_);
- } else {
- DCHECK(resource_collection_.get());
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
- }
- DCHECK(!ack.resources.empty());
+ DCHECK(!surface_returned_resources_.empty());
+ ack.resources.swap(surface_returned_resources_);
client_->DelegatedFrameHostSendReclaimCompositorResources(output_surface_id,
ack);
@@ -562,8 +535,7 @@ void DelegatedFrameHost::ReturnResources(
const cc::ReturnedResourceArray& resources) {
if (resources.empty())
return;
- std::copy(resources.begin(),
- resources.end(),
+ std::copy(resources.begin(), resources.end(),
std::back_inserter(surface_returned_resources_));
if (!pending_delegated_ack_count_)
SendReturnedDelegatedResources(last_output_surface_id_);
@@ -577,168 +549,19 @@ void DelegatedFrameHost::WillDrawSurface(cc::SurfaceId id,
}
void DelegatedFrameHost::SetBeginFrameSource(
- cc::SurfaceId surface_id,
cc::BeginFrameSource* begin_frame_source) {
- // TODO(tansell): Hook this up.
+ // TODO(enne): forward this to DelegatedFrameHostClient to observe and then to
+ // the renderer as an external begin frame source.
}
void DelegatedFrameHost::EvictDelegatedFrame() {
client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
- frame_provider_ = NULL;
if (!surface_id_.is_null()) {
surface_factory_->Destroy(surface_id_);
surface_id_ = cc::SurfaceId();
}
delegated_frame_evictor_->DiscardedFrame();
-}
-
-// static
-void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result) {
- if (result->IsEmpty() || result->size().IsEmpty()) {
- callback.Run(SkBitmap(), content::READBACK_FAILED);
- return;
- }
-
- gfx::Size output_size_in_pixel;
- if (dst_size_in_pixel.IsEmpty())
- output_size_in_pixel = result->size();
- else
- output_size_in_pixel = dst_size_in_pixel;
-
- if (result->HasTexture()) {
- // GPU-accelerated path
- PrepareTextureCopyOutputResult(output_size_in_pixel, color_type, callback,
- std::move(result));
- return;
- }
-
- DCHECK(result->HasBitmap());
- // Software path
- PrepareBitmapCopyOutputResult(output_size_in_pixel, color_type, callback,
- std::move(result));
-}
-
-static void CopyFromCompositingSurfaceFinished(
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::SingleReleaseCallback> release_callback,
- scoped_ptr<SkBitmap> bitmap,
- scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
- bool result) {
- bitmap_pixels_lock.reset();
-
- gpu::SyncToken sync_token;
- if (result) {
- GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
- if (gl_helper)
- gl_helper->GenerateSyncToken(&sync_token);
- }
- const bool lost_resource = !sync_token.HasData();
- release_callback->Run(sync_token, lost_resource);
-
- callback.Run(*bitmap,
- result ? content::READBACK_SUCCESS : content::READBACK_FAILED);
-}
-
-// static
-void DelegatedFrameHost::PrepareTextureCopyOutputResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result) {
- DCHECK(result->HasTexture());
- base::ScopedClosureRunner scoped_callback_runner(
- base::Bind(callback, SkBitmap(), content::READBACK_FAILED));
-
- // TODO(siva.gunturi): We should be able to validate the format here using
- // GLHelper::IsReadbackConfigSupported before we processs the result.
- // See crbug.com/415682 and crbug.com/415131.
- scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->tryAllocPixels(SkImageInfo::Make(
- dst_size_in_pixel.width(), dst_size_in_pixel.height(), color_type,
- kOpaque_SkAlphaType))) {
- scoped_callback_runner.Reset(base::Bind(
- callback, SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE));
- return;
- }
-
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- GLHelper* gl_helper = factory->GetGLHelper();
- if (!gl_helper)
- return;
-
- scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
- new SkAutoLockPixels(*bitmap));
- uint8_t* pixels = static_cast<uint8_t*>(bitmap->getPixels());
-
- cc::TextureMailbox texture_mailbox;
- scoped_ptr<cc::SingleReleaseCallback> release_callback;
- result->TakeTexture(&texture_mailbox, &release_callback);
- DCHECK(texture_mailbox.IsTexture());
-
- ignore_result(scoped_callback_runner.Release());
-
- gl_helper->CropScaleReadbackAndCleanMailbox(
- texture_mailbox.mailbox(), texture_mailbox.sync_token(), result->size(),
- gfx::Rect(result->size()), dst_size_in_pixel, pixels, color_type,
- base::Bind(&CopyFromCompositingSurfaceFinished, callback,
- base::Passed(&release_callback), base::Passed(&bitmap),
- base::Passed(&bitmap_pixels_lock)),
- GLHelper::SCALER_QUALITY_GOOD);
-}
-
-// static
-void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType preferred_color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result) {
- SkColorType color_type = preferred_color_type;
- if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
- // Switch back to default colortype if format not supported.
- color_type = kN32_SkColorType;
- }
- DCHECK(result->HasBitmap());
- scoped_ptr<SkBitmap> source = result->TakeBitmap();
- DCHECK(source);
- SkBitmap scaled_bitmap;
- if (source->width() != dst_size_in_pixel.width() ||
- source->height() != dst_size_in_pixel.height()) {
- scaled_bitmap =
- skia::ImageOperations::Resize(*source,
- skia::ImageOperations::RESIZE_BEST,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height());
- } else {
- scaled_bitmap = *source;
- }
- if (color_type == kN32_SkColorType) {
- DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
- callback.Run(scaled_bitmap, READBACK_SUCCESS);
- return;
- }
- DCHECK_EQ(color_type, kAlpha_8_SkColorType);
- // The software path currently always returns N32 bitmap regardless of the
- // |color_type| we ask for.
- DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
- // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
- SkBitmap grayscale_bitmap;
- bool success = grayscale_bitmap.tryAllocPixels(
- SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
- if (!success) {
- callback.Run(SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE);
- return;
- }
- SkCanvas canvas(grayscale_bitmap);
- SkPaint paint;
- skia::RefPtr<SkColorFilter> filter =
- skia::AdoptRef(SkLumaColorFilter::Create());
- paint.setColorFilter(filter.get());
- canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
- callback.Run(grayscale_bitmap, READBACK_SUCCESS);
+ UpdateGutters();
}
// static
@@ -790,9 +613,8 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
scoped_ptr<cc::CopyOutputResult> result) {
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(callback, gfx::Rect(), false));
- base::ScopedClosureRunner scoped_return_subscriber_texture(
- base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture,
- gpu::SyncToken()));
+ base::ScopedClosureRunner scoped_return_subscriber_texture(base::Bind(
+ &ReturnSubscriberTexture, dfh, subscriber_texture, gpu::SyncToken()));
if (!dfh)
return;
@@ -809,10 +631,9 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
// pixels.
gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
video_frame->visible_rect(), result->size());
- region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
- region_in_frame.y() & ~1,
- region_in_frame.width() & ~1,
- region_in_frame.height() & ~1);
+ region_in_frame =
+ gfx::Rect(region_in_frame.x() & ~1, region_in_frame.y() & ~1,
+ region_in_frame.width() & ~1, region_in_frame.height() & ~1);
if (region_in_frame.IsEmpty())
return;
@@ -863,30 +684,23 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
- GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
- std::string quality_switch = switches::kTabCaptureDownscaleQuality;
- // If we're scaling up, we can use the "best" quality.
- if (result_rect.size().width() < region_in_frame.size().width() &&
- result_rect.size().height() < region_in_frame.size().height())
- quality_switch = switches::kTabCaptureUpscaleQuality;
-
- std::string switch_value =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- quality_switch);
- if (switch_value == "fast")
- quality = GLHelper::SCALER_QUALITY_FAST;
- else if (switch_value == "good")
- quality = GLHelper::SCALER_QUALITY_GOOD;
- else if (switch_value == "best")
- quality = GLHelper::SCALER_QUALITY_BEST;
-
- dfh->yuv_readback_pipeline_.reset(
- gl_helper->CreateReadbackPipelineYUV(quality,
- result_rect.size(),
- result_rect,
- region_in_frame.size(),
- true,
- true));
+ // The scaler chosen here is based on performance measurements of full
+ // end-to-end systems. When down-scaling, always use the "fast" scaler
+ // because it performs well on both low- and high- end machines, provides
+ // decent image quality, and doesn't overwhelm downstream video encoders
+ // with too much entropy (which can drastically increase CPU utilization).
+ // When up-scaling, always use "best" because the quality improvement is
+ // huge with insignificant performance penalty. Note that this strategy
+ // differs from single-frame snapshot capture.
+ GLHelper::ScalerQuality quality =
+ ((result_rect.size().width() < region_in_frame.size().width()) &&
+ (result_rect.size().height() < region_in_frame.size().height()))
+ ? GLHelper::SCALER_QUALITY_BEST
+ : GLHelper::SCALER_QUALITY_FAST;
+
+ dfh->yuv_readback_pipeline_.reset(gl_helper->CreateReadbackPipelineYUV(
+ quality, result_rect.size(), result_rect, region_in_frame.size(), true,
+ true));
yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
}
@@ -897,24 +711,20 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
&DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
dfh->AsWeakPtr(), base::Bind(callback, region_in_frame),
subscriber_texture, base::Passed(&release_callback));
- yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
- texture_mailbox.sync_token(),
- video_frame.get(),
- region_in_frame.origin(),
- finished_callback);
+ yuv_readback_pipeline->ReadbackYUV(
+ texture_mailbox.mailbox(), texture_mailbox.sync_token(),
+ video_frame.get(), region_in_frame.origin(), finished_callback);
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, ui::CompositorObserver implementation:
-void DelegatedFrameHost::OnCompositingDidCommit(
- ui::Compositor* compositor) {
+void DelegatedFrameHost::OnCompositingDidCommit(ui::Compositor* compositor) {
if (can_lock_compositor_ == NO_PENDING_COMMIT) {
can_lock_compositor_ = YES_CAN_LOCK;
if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
can_lock_compositor_ = YES_DID_LOCK;
}
- RunOnCommitCallbacks();
if (resize_lock_ &&
resize_lock_->expected_size() == current_frame_size_in_dip_) {
resize_lock_.reset();
@@ -926,17 +736,14 @@ void DelegatedFrameHost::OnCompositingDidCommit(
}
}
-void DelegatedFrameHost::OnCompositingStarted(
- ui::Compositor* compositor, base::TimeTicks start_time) {
+void DelegatedFrameHost::OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) {
last_draw_ended_ = start_time;
}
-void DelegatedFrameHost::OnCompositingEnded(
- ui::Compositor* compositor) {
-}
+void DelegatedFrameHost::OnCompositingEnded(ui::Compositor* compositor) {}
-void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
-}
+void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {}
void DelegatedFrameHost::OnCompositingLockStateChanged(
ui::Compositor* compositor) {
@@ -953,9 +760,8 @@ void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
DCHECK(!compositor_);
}
-void DelegatedFrameHost::OnUpdateVSyncParameters(
- base::TimeTicks timebase,
- base::TimeDelta interval) {
+void DelegatedFrameHost::OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
SetVSyncParameters(timebase, interval);
if (client_->DelegatedFrameHostIsVisible())
client_->DelegatedFrameHostUpdateVSyncParameters(timebase, interval);
@@ -965,7 +771,7 @@ void DelegatedFrameHost::OnUpdateVSyncParameters(
// DelegatedFrameHost, ImageTransportFactoryObserver implementation:
void DelegatedFrameHost::OnLostResources() {
- if (frame_provider_.get() || !surface_id_.is_null())
+ if (!surface_id_.is_null())
EvictDelegatedFrame();
idle_frame_subscriber_textures_.clear();
yuv_readback_pipeline_.reset();
@@ -978,34 +784,17 @@ void DelegatedFrameHost::OnLostResources() {
DelegatedFrameHost::~DelegatedFrameHost() {
DCHECK(!compositor_);
- ImageTransportFactory::GetInstance()->RemoveObserver(this);
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ factory->RemoveObserver(this);
if (!surface_id_.is_null())
surface_factory_->Destroy(surface_id_);
- if (resource_collection_.get())
- resource_collection_->SetClient(NULL);
+ factory->GetSurfaceManager()->UnregisterSurfaceFactoryClient(
+ id_allocator_->id_namespace());
DCHECK(!vsync_manager_.get());
}
-void DelegatedFrameHost::RunOnCommitCallbacks() {
- for (std::vector<base::Closure>::const_iterator
- it = on_compositing_did_commit_callbacks_.begin();
- it != on_compositing_did_commit_callbacks_.end(); ++it) {
- it->Run();
- }
- on_compositing_did_commit_callbacks_.clear();
-}
-
-void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
- const base::Closure& callback) {
- DCHECK(compositor_);
-
- can_lock_compositor_ = NO_PENDING_COMMIT;
- if (!callback.is_null())
- on_compositing_did_commit_callbacks_.push_back(callback);
-}
-
void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
DCHECK(!compositor_);
if (!compositor)
@@ -1015,12 +804,16 @@ void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
DCHECK(!vsync_manager_.get());
vsync_manager_ = compositor_->vsync_manager();
vsync_manager_->AddObserver(this);
+
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ uint32_t parent = compositor->surface_id_allocator()->id_namespace();
+ factory->GetSurfaceManager()->RegisterSurfaceNamespaceHierarchy(
+ parent, id_allocator_->id_namespace());
}
void DelegatedFrameHost::ResetCompositor() {
if (!compositor_)
return;
- RunOnCommitCallbacks();
if (resize_lock_) {
resize_lock_.reset();
client_->DelegatedFrameHostResizeLockWasReleased();
@@ -1031,6 +824,12 @@ void DelegatedFrameHost::ResetCompositor() {
vsync_manager_->RemoveObserver(this);
vsync_manager_ = NULL;
}
+
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ uint32_t parent = compositor_->surface_id_allocator()->id_namespace();
+ factory->GetSurfaceManager()->UnregisterSurfaceNamespaceHierarchy(
+ parent, id_allocator_->id_namespace());
+
compositor_ = nullptr;
}
@@ -1041,21 +840,22 @@ void DelegatedFrameHost::SetVSyncParameters(const base::TimeTicks& timebase,
}
void DelegatedFrameHost::LockResources() {
- DCHECK(frame_provider_.get() || !surface_id_.is_null());
+ DCHECK(!surface_id_.is_null());
delegated_frame_evictor_->LockFrame();
}
void DelegatedFrameHost::RequestCopyOfOutput(
scoped_ptr<cc::CopyOutputRequest> request) {
- if (!request_copy_of_output_callback_for_testing_.is_null())
+ if (!request_copy_of_output_callback_for_testing_.is_null()) {
request_copy_of_output_callback_for_testing_.Run(std::move(request));
- else
+ } else {
client_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(
std::move(request));
+ }
}
void DelegatedFrameHost::UnlockResources() {
- DCHECK(frame_provider_.get() || !surface_id_.is_null());
+ DCHECK(!surface_id_.is_null());
delegated_frame_evictor_->UnlockFrame();
}
@@ -1063,14 +863,10 @@ void DelegatedFrameHost::UnlockResources() {
// DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
- ui::Layer* new_layer) {
+ ui::Layer* new_layer) {
// The new_layer is the one that will be used by our Window, so that's the one
// that should keep our frame. old_layer will be returned to the
// RecreateLayer caller, and should have a copy.
- if (frame_provider_.get()) {
- new_layer->SetShowDelegatedContent(frame_provider_.get(),
- current_frame_size_in_dip_);
- }
if (!surface_id_.is_null()) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
cc::SurfaceManager* manager = factory->GetSurfaceManager();
diff --git a/chromium/content/browser/compositor/delegated_frame_host.h b/chromium/content/browser/renderer_host/delegated_frame_host.h
index 21dc4e0c8f9..9f2b1813acc 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.h
+++ b/chromium/content/browser/renderer_host/delegated_frame_host.h
@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_COMPOSITOR_DELEGATED_FRAME_HOST_H_
-#define CONTENT_BROWSER_COMPOSITOR_DELEGATED_FRAME_HOST_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_
+#define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_
#include <stdint.h>
#include <vector>
#include "base/gtest_prod_util.h"
-#include "cc/layers/delegated_frame_provider.h"
-#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/output/copy_output_result.h"
#include "cc/surfaces/surface_factory_client.h"
#include "content/browser/compositor/image_transport_factory.h"
@@ -87,7 +85,6 @@ class CONTENT_EXPORT DelegatedFrameHost
public ui::LayerOwnerDelegate,
public ImageTransportFactoryObserver,
public DelegatedFrameEvictorClient,
- public cc::DelegatedFrameResourceCollectionClient,
public cc::SurfaceFactoryClient,
public base::SupportsWeakPtr<DelegatedFrameHost> {
public:
@@ -116,14 +113,10 @@ class CONTENT_EXPORT DelegatedFrameHost
// DelegatedFrameEvictorClient implementation.
void EvictDelegatedFrame() override;
- // cc::DelegatedFrameProviderClient implementation.
- void UnusedResourcesAreAvailable() override;
-
// cc::SurfaceFactoryClient implementation.
void ReturnResources(const cc::ReturnedResourceArray& resources) override;
void WillDrawSurface(cc::SurfaceId id, const gfx::Rect& damage_rect) override;
- void SetBeginFrameSource(cc::SurfaceId surface_id,
- cc::BeginFrameSource* begin_frame_source) override;
+ void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
bool CanCopyToBitmap() const;
@@ -155,11 +148,12 @@ class CONTENT_EXPORT DelegatedFrameHost
void BeginFrameSubscription(
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber);
void EndFrameSubscription();
- bool HasFrameSubscriber() const { return frame_subscriber_; }
+ bool HasFrameSubscriber() const { return !!frame_subscriber_; }
uint32_t GetSurfaceIdNamespace();
// Returns a null SurfaceId if this DelegatedFrameHost has not yet created
// a compositor Surface.
- cc::SurfaceId SurfaceIdAtPoint(const gfx::Point& point,
+ cc::SurfaceId SurfaceIdAtPoint(cc::SurfaceHittestDelegate* delegate,
+ const gfx::Point& point,
gfx::Point* transformed_point);
// Given the SurfaceID of a Surface that is contained within this class'
@@ -171,9 +165,6 @@ class CONTENT_EXPORT DelegatedFrameHost
gfx::Point* transformed_point);
// Exposed for tests.
- cc::DelegatedFrameProvider* FrameProviderForTesting() const {
- return frame_provider_.get();
- }
cc::SurfaceId SurfaceIdForTesting() const { return surface_id_; }
void OnCompositingDidCommitForTesting(ui::Compositor* compositor) {
OnCompositingDidCommit(compositor);
@@ -211,29 +202,12 @@ class CONTENT_EXPORT DelegatedFrameHost
// Checks if the resize lock can be released because we received an new frame.
void CheckResizeLock();
- // Run all on compositing commit callbacks.
- void RunOnCommitCallbacks();
-
- // Add on compositing commit callback.
- void AddOnCommitCallbackAndDisableLocks(const base::Closure& callback);
+ // Update the layers for the resize gutters to the right and bottom of the
+ // surface layer.
+ void UpdateGutters();
// Called after async thumbnailer task completes. Scales and crops the result
// of the copy.
- static void CopyFromCompositingSurfaceHasResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result);
- static void PrepareTextureCopyOutputResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result);
- static void PrepareBitmapCopyOutputResult(
- const gfx::Size& dst_size_in_pixel,
- const SkColorType color_type,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result);
static void CopyFromCompositingSurfaceHasResultForVideo(
base::WeakPtr<DelegatedFrameHost> rwhva,
scoped_refptr<OwnedMailbox> subscriber_texture,
@@ -262,12 +236,6 @@ class CONTENT_EXPORT DelegatedFrameHost
DelegatedFrameHostClient* const client_;
ui::Compositor* compositor_;
- // True if this renders into a Surface, false if it renders into a delegated
- // layer.
- bool use_surfaces_;
-
- std::vector<base::Closure> on_compositing_did_commit_callbacks_;
-
// The vsync manager we are observing for changes, if any.
scoped_refptr<ui::CompositorVSyncManager> vsync_manager_;
@@ -293,13 +261,11 @@ class CONTENT_EXPORT DelegatedFrameHost
bool skipped_frames_;
std::vector<ui::LatencyInfo> skipped_latency_info_list_;
- // Holds delegated resources that have been given to a DelegatedFrameProvider,
- // and gives back resources when they are no longer in use for return to the
- // renderer.
- scoped_refptr<cc::DelegatedFrameResourceCollection> resource_collection_;
+ scoped_ptr<ui::Layer> right_gutter_;
+ scoped_ptr<ui::Layer> bottom_gutter_;
- // Provides delegated frame updates to the cc::DelegatedRendererLayer.
- scoped_refptr<cc::DelegatedFrameProvider> frame_provider_;
+ // This is the last root background color from a swapped frame.
+ SkColor background_color_;
// State for rendering into a Surface.
scoped_ptr<cc::SurfaceIdAllocator> id_allocator_;
@@ -338,7 +304,7 @@ class CONTENT_EXPORT DelegatedFrameHost
// Subscriber that listens to frame presentation events.
scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
- std::vector<scoped_refptr<OwnedMailbox> > idle_frame_subscriber_textures_;
+ std::vector<scoped_refptr<OwnedMailbox>> idle_frame_subscriber_textures_;
// Callback used to pass the output request to the layer or to a function
// specified by a test.
@@ -346,12 +312,13 @@ class CONTENT_EXPORT DelegatedFrameHost
request_copy_of_output_callback_for_testing_;
// YUV readback pipeline.
- scoped_ptr<content::ReadbackYUVInterface>
- yuv_readback_pipeline_;
+ scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_;
scoped_ptr<DelegatedFrameEvictor> delegated_frame_evictor_;
+
+ cc::BeginFrameSource* begin_frame_source_;
};
} // namespace content
-#endif // CONTENT_BROWSER_COMPOSITOR_DELEGATED_FRAME_HOST_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_
diff --git a/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc b/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
index 5d186424b66..6d16572b4fe 100644
--- a/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
+++ b/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
@@ -142,13 +142,15 @@ void DWriteFontProxyMessageFilter::OnGetFamilyNames(
mswr::ComPtr<IDWriteFontFamily> family;
HRESULT hr = collection_->GetFontFamily(family_index, &family);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
mswr::ComPtr<IDWriteLocalizedStrings> localized_names;
hr = family->GetFamilyNames(&localized_names);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
size_t string_count = localized_names->GetCount();
@@ -157,25 +159,29 @@ void DWriteFontProxyMessageFilter::OnGetFamilyNames(
for (size_t index = 0; index < string_count; ++index) {
UINT32 length = 0;
hr = localized_names->GetLocaleNameLength(index, &length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
++length; // Reserve space for the null terminator.
locale.resize(length);
hr = localized_names->GetLocaleName(index, locale.data(), length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
- DCHECK_EQ(L'\0', locale[length - 1]);
+ }
+ CHECK_EQ(L'\0', locale[length - 1]);
length = 0;
hr = localized_names->GetStringLength(index, &length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
++length; // Reserve space for the null terminator.
name.resize(length);
hr = localized_names->GetString(index, name.data(), length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
- DCHECK_EQ(L'\0', name[length - 1]);
+ }
+ CHECK_EQ(L'\0', name[length - 1]);
// Would be great to use emplace_back instead.
family_names->push_back(std::pair<base::string16, base::string16>(
@@ -194,8 +200,9 @@ void DWriteFontProxyMessageFilter::OnGetFontFiles(
mswr::ComPtr<IDWriteFontFamily> family;
HRESULT hr = collection_->GetFontFamily(family_index, &family);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
UINT32 font_count = family->GetFontCount();
@@ -206,8 +213,9 @@ void DWriteFontProxyMessageFilter::OnGetFontFiles(
for (UINT32 font_index = 0; font_index < font_count; ++font_index) {
mswr::ComPtr<IDWriteFont> font;
hr = family->GetFont(font_index, &font);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return;
+ }
AddFilesForFont(&path_set, font.Get());
}
@@ -239,26 +247,30 @@ bool DWriteFontProxyMessageFilter::AddFilesForFont(
mswr::ComPtr<IDWriteFontFace> font_face;
HRESULT hr;
hr = font->CreateFontFace(&font_face);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
UINT32 file_count;
hr = font_face->GetFiles(&file_count, nullptr);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
std::vector<mswr::ComPtr<IDWriteFontFile>> font_files;
font_files.resize(file_count);
hr = font_face->GetFiles(
&file_count, reinterpret_cast<IDWriteFontFile**>(font_files.data()));
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
for (unsigned int file_index = 0; file_index < file_count; ++file_index) {
mswr::ComPtr<IDWriteFontFileLoader> loader;
hr = font_files[file_index]->GetLoader(&loader);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
mswr::ComPtr<IDWriteLocalFontFileLoader> local_loader;
hr = loader.CopyTo(local_loader.GetAddressOf()); // QueryInterface.
@@ -271,10 +283,11 @@ bool DWriteFontProxyMessageFilter::AddFilesForFont(
// for this font, forcing blink/skia to fall back to whatever font is
// next). If we get telemetry indicating that this case actually
// happens, we can implement this by exposing the loader via ipc. That
- // will likely by loading the font data into shared memory, although we
- // could proxy the stream reads directly instead.
+ // will likely be by loading the font data into shared memory, although
+ // we could proxy the stream reads directly instead.
LogLoaderType(OTHER_LOADER);
DCHECK(false);
+
return false;
} else if (!SUCCEEDED(hr)) {
return false;
@@ -296,20 +309,23 @@ bool DWriteFontProxyMessageFilter::AddLocalFile(
const void* key;
UINT32 key_size;
hr = font_file->GetReferenceKey(&key, &key_size);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
UINT32 path_length = 0;
hr = local_loader->GetFilePathLengthFromKey(key, key_size, &path_length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
++path_length; // Reserve space for the null terminator.
std::vector<base::char16> file_path_chars;
file_path_chars.resize(path_length);
hr = local_loader->GetFilePathFromKey(key, key_size, file_path_chars.data(),
path_length);
- if (!SUCCEEDED(hr))
+ if (!SUCCEEDED(hr)) {
return false;
+ }
base::string16 file_path = base::i18n::FoldCase(file_path_chars.data());
if (!base::StartsWith(file_path, windows_fonts_path_,
@@ -319,6 +335,12 @@ bool DWriteFontProxyMessageFilter::AddLocalFile(
// this turns out to be a common case, we can either grant the renderer
// access to these files (not sure if this is actually possible), or
// load the file data ourselves and hand it to the renderer.
+
+ // Really, really, really want to know what families hit this. Current
+ // data indicates about 0.09% of families fall into this case. Nothing to
+ // worry about if it's random obscure fonts noone has ever heard of, but
+ // could be a problem if it's common fonts.
+
LogLoaderType(FILE_OUTSIDE_SANDBOX);
NOTREACHED(); // Not yet implemented.
return false;
diff --git a/chromium/content/browser/renderer_host/event_with_latency_info.h b/chromium/content/browser/renderer_host/event_with_latency_info.h
index f55bb0c4e89..0ff2b4c4eea 100644
--- a/chromium/content/browser/renderer_host/event_with_latency_info.h
+++ b/chromium/content/browser/renderer_host/event_with_latency_info.h
@@ -5,66 +5,13 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_EVENT_WITH_LATENCY_INFO_H_
#define CONTENT_BROWSER_RENDERER_HOST_EVENT_WITH_LATENCY_INFO_H_
-#include "ui/events/latency_info.h"
-
-#include "content/common/input/web_input_event_traits.h"
+#include "content/common/input/event_with_latency_info.h"
#include "content/public/browser/native_web_keyboard_event.h"
-namespace blink {
-class WebGestureEvent;
-class WebMouseEvent;
-class WebMouseWheelEvent;
-class WebTouchEvent;
-}
-
namespace content {
-template <typename T>
-class EventWithLatencyInfo {
- public:
- T event;
- mutable ui::LatencyInfo latency;
-
- explicit EventWithLatencyInfo(const T& e) : event(e) {}
-
- EventWithLatencyInfo(const T& e, const ui::LatencyInfo& l)
- : event(e), latency(l) {}
-
- EventWithLatencyInfo() {}
-
- bool CanCoalesceWith(const EventWithLatencyInfo& other)
- const WARN_UNUSED_RESULT {
- return WebInputEventTraits::CanCoalesce(other.event, event);
- }
-
- void CoalesceWith(const EventWithLatencyInfo& other) {
- // |other| should be a newer event than |this|.
- if (other.latency.trace_id() >= 0 && latency.trace_id() >= 0)
- DCHECK_GT(other.latency.trace_id(), latency.trace_id());
- double old_timestamp = event.timeStampSeconds;
- WebInputEventTraits::Coalesce(other.event, &event);
- // When coalescing two input events, we keep the oldest LatencyInfo
- // for Telemetry latency test since it will represent the longest
- // latency.
- if (other.latency.trace_id() >= 0 &&
- (latency.trace_id() < 0 ||
- other.latency.trace_id() < latency.trace_id())) {
- latency = other.latency;
- }
- latency.AddCoalescedEventTimestamp(old_timestamp);
- }
-};
-
typedef EventWithLatencyInfo<NativeWebKeyboardEvent>
NativeWebKeyboardEventWithLatencyInfo;
-typedef EventWithLatencyInfo<blink::WebGestureEvent>
- GestureEventWithLatencyInfo;
-typedef EventWithLatencyInfo<blink::WebMouseWheelEvent>
- MouseWheelEventWithLatencyInfo;
-typedef EventWithLatencyInfo<blink::WebMouseEvent>
- MouseEventWithLatencyInfo;
-typedef EventWithLatencyInfo<blink::WebTouchEvent>
- TouchEventWithLatencyInfo;
} // namespace content
diff --git a/chromium/content/browser/renderer_host/event_with_latency_info_unittest.cc b/chromium/content/browser/renderer_host/event_with_latency_info_unittest.cc
deleted file mode 100644
index 42d490f8ad3..00000000000
--- a/chromium/content/browser/renderer_host/event_with_latency_info_unittest.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/event_with_latency_info.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-
-using blink::WebGestureEvent;
-using blink::WebInputEvent;
-using blink::WebMouseEvent;
-using blink::WebMouseWheelEvent;
-using blink::WebTouchEvent;
-
-namespace content {
-namespace {
-
-class EventWithLatencyInfoTest : public testing::Test {
- protected:
- TouchEventWithLatencyInfo CreateTouchEvent(WebInputEvent::Type type,
- double timestamp) {
- TouchEventWithLatencyInfo touch;
- touch.event.touchesLength = 1;
- touch.event.type = type;
- touch.event.timeStampSeconds = timestamp;
- return touch;
- }
-
- MouseEventWithLatencyInfo CreateMouseEvent(WebInputEvent::Type type,
- double timestamp) {
- MouseEventWithLatencyInfo mouse;
- mouse.event.type = type;
- mouse.event.timeStampSeconds = timestamp;
- return mouse;
- }
-
- MouseWheelEventWithLatencyInfo CreateMouseWheelEvent(double timestamp) {
- MouseWheelEventWithLatencyInfo mouse_wheel;
- mouse_wheel.event.type = WebInputEvent::MouseWheel;
- mouse_wheel.event.timeStampSeconds = timestamp;
- return mouse_wheel;
- }
-
- GestureEventWithLatencyInfo CreateGestureEvent(WebInputEvent::Type type,
- double timestamp) {
- GestureEventWithLatencyInfo gesture;
- gesture.event.type = type;
- gesture.event.timeStampSeconds = timestamp;
- return gesture;
- }
-};
-
-TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForMouseEvent) {
- MouseEventWithLatencyInfo mouse_0 = CreateMouseEvent(
- WebInputEvent::MouseMove, 5.0);
- MouseEventWithLatencyInfo mouse_1 = CreateMouseEvent(
- WebInputEvent::MouseMove, 10.0);
-
- ASSERT_TRUE(mouse_0.CanCoalesceWith(mouse_1));
- mouse_0.CoalesceWith(mouse_1);
- // Coalescing WebMouseEvent preserves newer timestamp.
- EXPECT_EQ(10.0, mouse_0.event.timeStampSeconds);
- ASSERT_EQ(1u, mouse_0.latency.coalesced_events_size());
- EXPECT_EQ(5.0, mouse_0.latency.timestamps_of_coalesced_events()[0]);
-}
-
-TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForMouseWheelEvent) {
- MouseWheelEventWithLatencyInfo mouse_wheel_0 = CreateMouseWheelEvent(5.0);
- MouseWheelEventWithLatencyInfo mouse_wheel_1 = CreateMouseWheelEvent(10.0);
-
- ASSERT_TRUE(mouse_wheel_0.CanCoalesceWith(mouse_wheel_1));
- mouse_wheel_0.CoalesceWith(mouse_wheel_1);
- // Coalescing WebMouseWheelEvent preserves newer timestamp.
- EXPECT_EQ(10.0, mouse_wheel_0.event.timeStampSeconds);
- ASSERT_EQ(1u, mouse_wheel_0.latency.coalesced_events_size());
- EXPECT_EQ(5.0, mouse_wheel_0.latency.timestamps_of_coalesced_events()[0]);
-}
-
-TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForTouchEvent) {
- TouchEventWithLatencyInfo touch_0 = CreateTouchEvent(
- WebInputEvent::TouchMove, 5.0);
- TouchEventWithLatencyInfo touch_1 = CreateTouchEvent(
- WebInputEvent::TouchMove, 10.0);
-
- ASSERT_TRUE(touch_0.CanCoalesceWith(touch_1));
- touch_0.CoalesceWith(touch_1);
- // Coalescing WebTouchEvent preserves newer timestamp.
- EXPECT_EQ(10.0, touch_0.event.timeStampSeconds);
- ASSERT_EQ(1u, touch_0.latency.coalesced_events_size());
- EXPECT_EQ(5.0, touch_0.latency.timestamps_of_coalesced_events()[0]);
-}
-
-TEST_F(EventWithLatencyInfoTest, TimestampCoalescingForGestureEvent) {
- GestureEventWithLatencyInfo scroll_0 = CreateGestureEvent(
- WebInputEvent::GestureScrollUpdate, 5.0);
- GestureEventWithLatencyInfo scroll_1 = CreateGestureEvent(
- WebInputEvent::GestureScrollUpdate, 10.0);
-
- ASSERT_TRUE(scroll_0.CanCoalesceWith(scroll_1));
- scroll_0.CoalesceWith(scroll_1);
- // Coalescing WebGestureEvent preserves newer timestamp.
- EXPECT_EQ(10.0, scroll_0.event.timeStampSeconds);
- ASSERT_EQ(1u, scroll_0.latency.coalesced_events_size());
- EXPECT_EQ(5.0, scroll_0.latency.timestamps_of_coalesced_events()[0]);
-}
-
-} // namespace
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/font_utils_linux.cc b/chromium/content/browser/renderer_host/font_utils_linux.cc
index 715923d6b88..245475f6650 100644
--- a/chromium/content/browser/renderer_host/font_utils_linux.cc
+++ b/chromium/content/browser/renderer_host/font_utils_linux.cc
@@ -12,8 +12,8 @@
#include <string>
#include "base/posix/eintr_wrapper.h"
+#include "ppapi/c/private/pp_private_font_charset.h"
#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
namespace {
@@ -41,30 +41,30 @@ bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
bool is_lgc = false;
switch (fdwCharSet) {
- case NPCharsetAnsi:
+ case PP_PRIVATEFONTCHARSET_ANSI:
// These values I don't really know what to do with, so I'm going to map
// them to English also.
- case NPCharsetDefault:
- case NPCharsetMac:
- case NPCharsetOEM:
- case NPCharsetSymbol:
+ case PP_PRIVATEFONTCHARSET_DEFAULT:
+ case PP_PRIVATEFONTCHARSET_MAC:
+ case PP_PRIVATEFONTCHARSET_OEM:
+ case PP_PRIVATEFONTCHARSET_SYMBOL:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en"));
break;
- case NPCharsetBaltic:
+ case PP_PRIVATEFONTCHARSET_BALTIC:
// The three baltic languages.
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("et"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lv"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lt"));
break;
- case NPCharsetChineseBIG5:
+ case PP_PRIVATEFONTCHARSET_CHINESEBIG5:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw"));
break;
- case NPCharsetGB2312:
+ case PP_PRIVATEFONTCHARSET_GB2312:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn"));
break;
- case NPCharsetEastEurope:
+ case PP_PRIVATEFONTCHARSET_EASTEUROPE:
// A scattering of eastern European languages.
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl"));
@@ -73,38 +73,38 @@ bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr"));
break;
- case NPCharsetGreek:
+ case PP_PRIVATEFONTCHARSET_GREEK:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el"));
break;
- case NPCharsetHangul:
- case NPCharsetJohab:
+ case PP_PRIVATEFONTCHARSET_HANGUL:
+ case PP_PRIVATEFONTCHARSET_JOHAB:
// Korean
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko"));
break;
- case NPCharsetRussian:
+ case PP_PRIVATEFONTCHARSET_RUSSIAN:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru"));
break;
- case NPCharsetShiftJIS:
+ case PP_PRIVATEFONTCHARSET_SHIFTJIS:
// Japanese
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja"));
break;
- case NPCharsetTurkish:
+ case PP_PRIVATEFONTCHARSET_TURKISH:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr"));
break;
- case NPCharsetVietnamese:
+ case PP_PRIVATEFONTCHARSET_VIETNAMESE:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi"));
break;
- case NPCharsetArabic:
+ case PP_PRIVATEFONTCHARSET_ARABIC:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar"));
break;
- case NPCharsetHebrew:
+ case PP_PRIVATEFONTCHARSET_HEBREW:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he"));
break;
- case NPCharsetThai:
+ case PP_PRIVATEFONTCHARSET_THAI:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th"));
break;
// default:
diff --git a/chromium/content/browser/renderer_host/gpu_message_filter.cc b/chromium/content/browser/renderer_host/gpu_message_filter.cc
deleted file mode 100644
index 95355b3e3e1..00000000000
--- a/chromium/content/browser/renderer_host/gpu_message_filter.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#include "content/browser/renderer_host/gpu_message_filter.h"
-
-#include "base/bind.h"
-#include "build/build_config.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/child_process_host_impl.h"
-#include "content/common/gpu/gpu_messages.h"
-
-namespace content {
-
-GpuMessageFilter::GpuMessageFilter(int render_process_id)
- : BrowserMessageFilter(GpuMsgStart),
- gpu_process_id_(0),
- render_process_id_(render_process_id),
- weak_ptr_factory_(this) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-GpuMessageFilter::~GpuMessageFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-bool GpuMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(GpuMessageFilter, message)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_EstablishGpuChannel,
- OnEstablishGpuChannel)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void GpuMessageFilter::OnEstablishGpuChannel(
- CauseForGpuLaunch cause_for_gpu_launch,
- IPC::Message* reply_ptr) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- scoped_ptr<IPC::Message> reply(reply_ptr);
-
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
- // TODO(jbauman): Remove this when we know why renderer processes are
- // hanging on x86-64. https://crbug.com/577127
- if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
- reply->set_reply_error();
- Send(reply.release());
- return;
- }
-#endif
-
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
- if (!host) {
- host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- cause_for_gpu_launch);
- if (!host) {
- reply->set_reply_error();
- Send(reply.release());
- return;
- }
-
- gpu_process_id_ = host->host_id();
- }
-
- bool preempts = false;
- bool preempted = true;
- bool allow_future_sync_points = false;
- bool allow_real_time_streams = false;
- host->EstablishGpuChannel(
- render_process_id_,
- ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
- render_process_id_),
- preempts, preempted, allow_future_sync_points, allow_real_time_streams,
- base::Bind(&GpuMessageFilter::EstablishChannelCallback,
- weak_ptr_factory_.GetWeakPtr(), base::Passed(&reply)));
-}
-
-void GpuMessageFilter::EstablishChannelCallback(
- scoped_ptr<IPC::Message> reply,
- const IPC::ChannelHandle& channel,
- const gpu::GPUInfo& gpu_info) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
- reply.get(), render_process_id_, channel, gpu_info);
- Send(reply.release());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/gpu_message_filter.h b/chromium/content/browser/renderer_host/gpu_message_filter.h
deleted file mode 100644
index 393d0babdc6..00000000000
--- a/chromium/content/browser/renderer_host/gpu_message_filter.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_GPU_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_GPU_MESSAGE_FILTER_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace gpu {
-struct GPUInfo;
-}
-
-namespace content {
-
-// A message filter for messages from the renderer to the GpuProcessHost
-// in the browser. Such messages are typically destined for the GPU process,
-// but need to be mediated by the browser.
-class GpuMessageFilter : public BrowserMessageFilter {
- public:
- GpuMessageFilter(int render_process_id);
-
- // BrowserMessageFilter methods:
- bool OnMessageReceived(const IPC::Message& message) override;
-
- private:
- friend class BrowserThread;
- friend class base::DeleteHelper<GpuMessageFilter>;
-
- ~GpuMessageFilter() override;
-
- // Message handlers called on the browser IO thread:
- void OnEstablishGpuChannel(CauseForGpuLaunch,
- IPC::Message* reply);
- // Helper callbacks for the message handlers.
- void EstablishChannelCallback(scoped_ptr<IPC::Message> reply,
- const IPC::ChannelHandle& channel,
- const gpu::GPUInfo& gpu_info);
-
- int gpu_process_id_;
- int render_process_id_;
-
- base::WeakPtrFactory<GpuMessageFilter> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_GPU_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.cc b/chromium/content/browser/renderer_host/ime_adapter_android.cc
index d70d4969d2e..233c0425b11 100644
--- a/chromium/content/browser/renderer_host/ime_adapter_android.cc
+++ b/chromium/content/browser/renderer_host/ime_adapter_android.cc
@@ -9,8 +9,10 @@
#include <vector>
#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
+#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/frame_host/frame_tree.h"
@@ -26,6 +28,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
#include "jni/ImeAdapter_jni.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -45,7 +48,7 @@ namespace {
// as a key press of character \r.
NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
JNIEnv* env,
- jobject java_key_event,
+ const base::android::JavaRef<jobject>& java_key_event,
int action,
int modifiers,
long time_ms,
@@ -60,8 +63,9 @@ NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
type = blink::WebInputEvent::KeyUp;
else
NOTREACHED() << "Invalid Android key event action: " << action;
- return NativeWebKeyboardEvent(java_key_event, type, modifiers,
- time_ms / 1000.0, key_code, scan_code, unicode_char, is_system_key);
+ return NativeWebKeyboardEvent(env, java_key_event, type, modifiers,
+ time_ms / 1000.0, key_code, scan_code,
+ unicode_char, is_system_key);
}
} // anonymous namespace
@@ -203,7 +207,8 @@ void ImeAdapterAndroid::SetComposingText(JNIEnv* env,
if (new_cursor_pos > 0)
new_cursor_pos = text16.length() + new_cursor_pos - 1;
- rwhi->ImeSetComposition(text16, underlines, new_cursor_pos, new_cursor_pos);
+ rwhi->ImeSetComposition(text16, underlines, gfx::Range::InvalidRange(),
+ new_cursor_pos, new_cursor_pos);
}
void ImeAdapterAndroid::CommitText(JNIEnv* env,
@@ -263,6 +268,31 @@ void ImeAdapterAndroid::SetEditableSelectionOffsets(
start, end));
}
+void ImeAdapterAndroid::SetCharacterBounds(
+ const std::vector<gfx::RectF>& character_bounds) {
+ JNIEnv* env = AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
+ if (obj.is_null())
+ return;
+
+ const size_t coordinates_array_size = character_bounds.size() * 4;
+ scoped_ptr<float[]> coordinates_array(new float[coordinates_array_size]);
+ for (size_t i = 0; i < character_bounds.size(); ++i) {
+ const gfx::RectF& rect = character_bounds[i];
+ const size_t coordinates_array_index = i * 4;
+ coordinates_array[coordinates_array_index + 0] = rect.x();
+ coordinates_array[coordinates_array_index + 1] = rect.y();
+ coordinates_array[coordinates_array_index + 2] = rect.right();
+ coordinates_array[coordinates_array_index + 3] = rect.bottom();
+ }
+ Java_ImeAdapter_setCharacterBounds(
+ env,
+ obj.obj(),
+ base::android::ToJavaFloatArray(env,
+ coordinates_array.get(),
+ coordinates_array_size).obj());
+}
+
void ImeAdapterAndroid::SetComposingRegion(JNIEnv*,
const JavaParamRef<jobject>&,
int start,
@@ -289,6 +319,22 @@ void ImeAdapterAndroid::DeleteSurroundingText(JNIEnv*,
rfh->ExtendSelectionAndDelete(before, after);
}
+bool ImeAdapterAndroid::RequestTextInputStateUpdate(
+ JNIEnv* env,
+ const JavaParamRef<jobject>&) {
+ RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+ if (!rwhi)
+ return false;
+ rwhi->Send(new InputMsg_RequestTextInputStateUpdate(rwhi->GetRoutingID()));
+ return true;
+}
+
+bool ImeAdapterAndroid::IsImeThreadEnabled(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>&) {
+ return base::FeatureList::IsEnabled(features::kImeThread);
+}
+
void ImeAdapterAndroid::ResetImeAdapter(JNIEnv* env,
const JavaParamRef<jobject>&) {
java_ime_adapter_.reset();
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.h b/chromium/content/browser/renderer_host/ime_adapter_android.h
index 0830f27254d..1f559c6ca77 100644
--- a/chromium/content/browser/renderer_host/ime_adapter_android.h
+++ b/chromium/content/browser/renderer_host/ime_adapter_android.h
@@ -7,7 +7,10 @@
#include <jni.h>
+#include <vector>
+
#include "base/android/jni_weak_ref.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace content {
@@ -75,10 +78,14 @@ class ImeAdapterAndroid {
int before,
int after);
void ResetImeAdapter(JNIEnv*, const base::android::JavaParamRef<jobject>&);
+ bool RequestTextInputStateUpdate(JNIEnv*,
+ const base::android::JavaParamRef<jobject>&);
+ bool IsImeThreadEnabled(JNIEnv*, const base::android::JavaParamRef<jobject>&);
// Called from native -> java
void CancelComposition();
void FocusedNodeChanged(bool is_editable_node);
+ void SetCharacterBounds(const std::vector<gfx::RectF>& rects);
private:
RenderWidgetHostImpl* GetRenderWidgetHostImpl();
diff --git a/chromium/content/browser/renderer_host/input/composited_scrolling_browsertest.cc b/chromium/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
index cbf48e8ae7a..fdca6bcfe9e 100644
--- a/chromium/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
@@ -84,7 +84,7 @@ class CompositedScrollingBrowserTest : public ContentBrowserTest {
RenderWidgetHostImpl* host = GetWidgetHost();
scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
- host->GetProcess()->AddFilter(frame_watcher.get());
+ frame_watcher->AttachTo(shell()->web_contents());
host->GetView()->SetSize(gfx::Size(400, 400));
base::string16 ready_title(base::ASCIIToUTF16("ready"));
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
index 15cda746b21..aa8856951d5 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -186,6 +186,9 @@ void GestureEventQueue::QueueAndForwardIfNecessary(
case WebInputEvent::GestureScrollUpdate:
QueueScrollOrPinchAndForwardIfNecessary(gesture_event);
return;
+ case WebInputEvent::GestureScrollBegin:
+ if (OnScrollBegin(gesture_event))
+ return;
default:
break;
}
@@ -195,6 +198,25 @@ void GestureEventQueue::QueueAndForwardIfNecessary(
client_->SendGestureEventImmediately(gesture_event);
}
+bool GestureEventQueue::OnScrollBegin(
+ const GestureEventWithLatencyInfo& gesture_event) {
+ // If a synthetic scroll begin is encountered, it can cancel out a previous
+ // synthetic scroll end. This allows a later gesture scroll update to coalesce
+ // with the previous one. crbug.com/607340.
+ bool synthetic = gesture_event.event.data.scrollBegin.synthetic;
+ bool have_unsent_events =
+ EventsInFlightCount() < coalesced_gesture_events_.size();
+ if (synthetic && have_unsent_events) {
+ GestureEventWithLatencyInfo* last_event = &coalesced_gesture_events_.back();
+ if (last_event->event.type == WebInputEvent::GestureScrollEnd &&
+ last_event->event.data.scrollEnd.synthetic) {
+ coalesced_gesture_events_.pop_back();
+ return true;
+ }
+ }
+ return false;
+}
+
void GestureEventQueue::ProcessGestureAck(InputEventAckState ack_result,
WebInputEvent::Type type,
const ui::LatencyInfo& latency) {
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.h b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
index 457a9ecb4cf..4df38e8e371 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
@@ -117,6 +117,8 @@ class CONTENT_EXPORT GestureEventQueue {
friend class GestureEventQueueTest;
friend class MockRenderWidgetHost;
+ bool OnScrollBegin(const GestureEventWithLatencyInfo& gesture_event);
+
// TODO(mohsen): There are a bunch of ShouldForward.../ShouldDiscard...
// methods that are getting confusing. This should be somehow fixed. Maybe
// while refactoring GEQ: http://crbug.com/148443.
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
index 44087274c4b..6b3234a7af5 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -1154,4 +1154,29 @@ TEST_F(GestureEventQueueTest, DebounceDropsDeferredEvents) {
}
}
+TEST_F(GestureEventQueueTest, CoalescesSyntheticScrollBeginEndEvents) {
+ // Test coalescing of only GestureScrollBegin/End events.
+ SimulateGestureEvent(WebInputEvent::GestureScrollUpdate,
+ blink::WebGestureDeviceTouchpad);
+ EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
+ EXPECT_EQ(1U, GestureEventQueueSize());
+
+ WebGestureEvent synthetic_end = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::GestureScrollEnd, blink::WebGestureDeviceTouchpad);
+ synthetic_end.data.scrollEnd.synthetic = true;
+
+ SimulateGestureEvent(synthetic_end);
+ EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+ EXPECT_EQ(2U, GestureEventQueueSize());
+
+ // Synthetic begin will remove the unsent synthetic end.
+ WebGestureEvent synthetic_begin = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::GestureScrollBegin, blink::WebGestureDeviceTouchpad);
+ synthetic_begin.data.scrollBegin.synthetic = true;
+
+ SimulateGestureEvent(synthetic_begin);
+ EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
+ EXPECT_EQ(1U, GestureEventQueueSize());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/input_router.h b/chromium/content/browser/renderer_host/input/input_router.h
index 5d64568962c..3b466cbb784 100644
--- a/chromium/content/browser/renderer_host/input/input_router.h
+++ b/chromium/content/browser/renderer_host/input/input_router.h
@@ -58,6 +58,10 @@ class InputRouter : public IPC::Listener {
// A scale factor to scale the coordinate in WebInputEvent from DIP
// to viewport.
virtual void SetDeviceScaleFactor(float device_scale_factor) = 0;
+
+ // Sets the frame tree node id of associated frame, used when tracing
+ // input event latencies to relate events to their target frames.
+ virtual void SetFrameTreeNodeId(int frameTreeNodeId) = 0;
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/input_router_client.h b/chromium/content/browser/renderer_host/input/input_router_client.h
index 34fdf0eb9b7..fffed702d63 100644
--- a/chromium/content/browser/renderer_host/input/input_router_client.h
+++ b/chromium/content/browser/renderer_host/input/input_router_client.h
@@ -53,6 +53,13 @@ class CONTENT_EXPORT InputRouterClient {
// Called when a renderer fling has terminated.
virtual void DidStopFlinging() = 0;
+
+ // Called when the input router generates an event. It is intended that the
+ // client will do some processing on |gesture_event| and then send it back
+ // to the InputRouter via SendGestureEvent.
+ virtual void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& gesture_event,
+ const ui::LatencyInfo& latency_info) = 0;
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl.cc b/chromium/content/browser/renderer_host/input/input_router_impl.cc
index dcae7142ff7..fcac73f6dde 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.cc
@@ -16,10 +16,10 @@
#include "content/browser/renderer_host/input/input_router_client.h"
#include "content/browser/renderer_host/input/touch_event_queue.h"
#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
-#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/common/content_constants_internal.h"
#include "content/common/edit_command.h"
#include "content/common/input/input_event_ack_state.h"
+#include "content/common/input/input_event_utils.h"
#include "content/common/input/touch_action.h"
#include "content/common/input/web_touch_event_traits.h"
#include "content/common/input_messages.h"
@@ -29,6 +29,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "ipc/ipc_sender.h"
+#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -52,6 +53,8 @@ const char* GetEventAckName(InputEventAckState ack_result) {
case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
+ case INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING:
+ return "SET_NON_BLOCKING";
}
DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
return "";
@@ -71,13 +74,16 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
client_(client),
ack_handler_(ack_handler),
routing_id_(routing_id),
+ frame_tree_node_id_(-1),
select_message_pending_(false),
move_caret_pending_(false),
mouse_move_pending_(false),
- mouse_wheel_pending_(false),
current_ack_source_(ACK_SOURCE_NONE),
flush_requested_(false),
active_renderer_fling_count_(0),
+ wheel_event_queue_(this,
+ UseGestureBasedWheelScrolling(),
+ kDefaultWheelScrollTransactionMs),
touch_event_queue_(this, config.touch_config),
gesture_event_queue_(this, this, config.gesture_config),
device_scale_factor_(1.f) {
@@ -124,38 +130,7 @@ void InputRouterImpl::SendMouseEvent(
void InputRouterImpl::SendWheelEvent(
const MouseWheelEventWithLatencyInfo& wheel_event) {
- if (mouse_wheel_pending_) {
- // If there's already a mouse wheel event waiting to be sent to the
- // renderer, add the new deltas to that event. Not doing so (e.g., by
- // dropping the old event, as for mouse moves) results in very slow
- // scrolling on the Mac.
- if (wheel_event.event.hasPreciseScrollingDeltas)
- DCHECK(wheel_event.event.canScroll);
- DCHECK(!(wheel_event.event.hasPreciseScrollingDeltas &&
- !wheel_event.event.canScroll));
- if (coalesced_mouse_wheel_events_.empty() ||
- (!coalesced_mouse_wheel_events_.empty() &&
- !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event))) {
- coalesced_mouse_wheel_events_.push_back(wheel_event);
- } else {
- coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
- TRACE_EVENT_INSTANT2("input", "InputRouterImpl::CoalescedWheelEvent",
- TRACE_EVENT_SCOPE_THREAD,
- "total_dx",
- coalesced_mouse_wheel_events_.back().event.deltaX,
- "total_dy",
- coalesced_mouse_wheel_events_.back().event.deltaY);
- }
- return;
- }
-
- mouse_wheel_pending_ = true;
- current_wheel_event_ = wheel_event;
-
- LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
- coalesced_mouse_wheel_events_.size());
-
- FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency);
+ wheel_event_queue_.QueueEvent(wheel_event);
}
void InputRouterImpl::SendKeyboardEvent(
@@ -181,6 +156,8 @@ void InputRouterImpl::SendGestureEvent(
if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
return;
+ wheel_event_queue_.OnGestureScrollEvent(gesture_event);
+
if (gesture_event.event.sourceDevice == blink::WebGestureDeviceTouchscreen)
touch_event_queue_.OnGestureScrollEvent(gesture_event);
@@ -251,14 +228,10 @@ void InputRouterImpl::RequestNotificationWhenFlushed() {
}
bool InputRouterImpl::HasPendingEvents() const {
- return !touch_event_queue_.empty() ||
- !gesture_event_queue_.empty() ||
- !key_queue_.empty() ||
- mouse_move_pending_ ||
- mouse_wheel_pending_ ||
- select_message_pending_ ||
- move_caret_pending_ ||
- active_renderer_fling_count_ > 0;
+ return !touch_event_queue_.empty() || !gesture_event_queue_.empty() ||
+ !key_queue_.empty() || mouse_move_pending_ ||
+ wheel_event_queue_.has_pending() || select_message_pending_ ||
+ move_caret_pending_ || active_renderer_fling_count_ > 0;
}
void InputRouterImpl::SetDeviceScaleFactor(float device_scale_factor) {
@@ -297,6 +270,18 @@ void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
ack_handler_->OnTouchEventAck(event, ack_result);
}
+void InputRouterImpl::OnFilteringTouchEvent(
+ const WebTouchEvent& touch_event) {
+ // The event stream given to the renderer is not guaranteed to be
+ // valid based on the current TouchEventStreamValidator rules. This event will
+ // never be given to the renderer, but in order to ensure that the event
+ // stream |output_stream_validator_| sees is valid, we give events which are
+ // filtered out to the validator. crbug.com/589111 proposes adding an
+ // additional validator for the events which are actually sent to the
+ // renderer.
+ output_stream_validator_.Validate(touch_event);
+}
+
void InputRouterImpl::OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) {
@@ -304,6 +289,23 @@ void InputRouterImpl::OnGestureEventAck(
ack_handler_->OnGestureEventAck(event, ack_result);
}
+void InputRouterImpl::ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency_info) {
+ client_->ForwardGestureEventWithLatencyInfo(event, latency_info);
+}
+
+void InputRouterImpl::SendMouseWheelEventImmediately(
+ const MouseWheelEventWithLatencyInfo& wheel_event) {
+ FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency);
+}
+
+void InputRouterImpl::OnMouseWheelEventAck(
+ const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) {
+ ack_handler_->OnWheelEventAck(event, ack_result);
+}
+
bool InputRouterImpl::SendSelectMessage(
scoped_ptr<IPC::Message> message) {
DCHECK(message->type() == InputMsg_SelectRange::ID ||
@@ -348,11 +350,12 @@ void InputRouterImpl::FilterAndSendWebInputEvent(
"InputRouterImpl::FilterAndSendWebInputEvent",
"type",
WebInputEventTraits::GetName(input_event.type));
- TRACE_EVENT_WITH_FLOW1("input,benchmark",
+ TRACE_EVENT_WITH_FLOW2("input,benchmark,devtools.timeline",
"LatencyInfo.Flow",
TRACE_ID_DONT_MANGLE(latency_info.trace_id()),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
- "step", "SendInputEventUI");
+ "step", "SendInputEventUI",
+ "frameTreeNodeId", frame_tree_node_id_);
// Any input event cancels a pending mouse move event.
next_mouse_move_.reset();
@@ -367,21 +370,14 @@ void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
if (OfferToClient(input_event, latency_info))
return;
- OfferToRenderer(input_event, latency_info);
-
- // Touch events should always indicate in the event whether they are
- // cancelable (respect ACK disposition) or not except touchmove.
- bool needs_synthetic_ack =
- !WebInputEventTraits::WillReceiveAckFromRenderer(input_event);
+ bool should_block = WebInputEventTraits::ShouldBlockEventStream(input_event);
+ OfferToRenderer(input_event, latency_info,
+ should_block
+ ? InputEventDispatchType::DISPATCH_TYPE_BLOCKING
+ : InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING);
- if (WebInputEvent::isTouchEventType(input_event.type) &&
- input_event.type != WebInputEvent::TouchMove) {
- const WebTouchEvent& touch = static_cast<const WebTouchEvent&>(input_event);
- DCHECK_EQ(needs_synthetic_ack, !touch.cancelable);
- }
-
- // The synthetic acks are sent immediately.
- if (needs_synthetic_ack) {
+ // Generate a synthetic ack if the event was sent so it doesn't block.
+ if (!should_block) {
ProcessInputEventAck(
input_event.type, INPUT_EVENT_ACK_STATE_IGNORED, latency_info,
WebInputEventTraits::GetUniqueTouchEventId(input_event),
@@ -418,18 +414,22 @@ bool InputRouterImpl::OfferToClient(const WebInputEvent& input_event,
}
bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
- const ui::LatencyInfo& latency_info) {
+ const ui::LatencyInfo& latency_info,
+ InputEventDispatchType dispatch_type) {
+ // This conversion is temporary. WebInputEvent should be generated
+ // directly from ui::Event with the viewport coordinates. See
+ // crbug.com/563730.
scoped_ptr<blink::WebInputEvent> event_in_viewport =
- ConvertWebInputEventToViewport(input_event, device_scale_factor_);
+ ui::ScaleWebInputEvent(input_event, device_scale_factor_);
const WebInputEvent* event_to_send =
event_in_viewport ? event_in_viewport.get() : &input_event;
if (Send(new InputMsg_HandleInputEvent(routing_id(), event_to_send,
- latency_info))) {
+ latency_info, dispatch_type))) {
// Ack messages for ignored ack event types should never be sent by the
// renderer. Consequently, such event types should not affect event time
// or in-flight event count metrics.
- if (WebInputEventTraits::WillReceiveAckFromRenderer(*event_to_send)) {
+ if (dispatch_type == InputEventDispatchType::DISPATCH_TYPE_BLOCKING) {
input_event_start_time_ = TimeTicks::Now();
client_->IncrementInFlightEventCount();
}
@@ -594,27 +594,7 @@ void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
const ui::LatencyInfo& latency) {
- // TODO(miletus): Add renderer side latency to each uncoalesced mouse
- // wheel event and add terminal component to each of them.
- current_wheel_event_.latency.AddNewLatencyFrom(latency);
-
- // Process the unhandled wheel event here before calling SendWheelEvent()
- // since it will mutate current_wheel_event_.
- ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
-
- // Mark the wheel event complete only after the ACKs have been handled above.
- // For example, ACKing the GesturePinchUpdate could cause another
- // GesturePinchUpdate to be sent, which should queue a wheel event rather than
- // send it immediately.
- mouse_wheel_pending_ = false;
-
- // Send the next (coalesced or synthetic) mouse wheel event.
- if (!coalesced_mouse_wheel_events_.empty()) {
- MouseWheelEventWithLatencyInfo next_wheel_event =
- coalesced_mouse_wheel_events_.front();
- coalesced_mouse_wheel_events_.pop_front();
- SendWheelEvent(next_wheel_event);
- }
+ wheel_event_queue_.ProcessMouseWheelAck(ack_result, latency);
}
void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
@@ -657,4 +637,8 @@ void InputRouterImpl::SignalFlushedIfNecessary() {
client_->DidFlush();
}
+void InputRouterImpl::SetFrameTreeNodeId(int frameTreeNodeId) {
+ frame_tree_node_id_ = frameTreeNodeId;
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl.h b/chromium/content/browser/renderer_host/input/input_router_impl.h
index 36f62b29256..dfa002f1cf6 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.h
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.h
@@ -14,9 +14,11 @@
#include "base/time/time.h"
#include "content/browser/renderer_host/input/gesture_event_queue.h"
#include "content/browser/renderer_host/input/input_router.h"
+#include "content/browser/renderer_host/input/mouse_wheel_event_queue.h"
#include "content/browser/renderer_host/input/touch_action_filter.h"
#include "content/browser/renderer_host/input/touch_event_queue.h"
#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
+#include "content/common/input/input_event_dispatch_type.h"
#include "content/common/input/input_event_stream_validator.h"
#include "content/public/browser/native_web_keyboard_event.h"
@@ -40,6 +42,7 @@ struct InputEventAck;
class CONTENT_EXPORT InputRouterImpl
: public NON_EXPORTED_BASE(InputRouter),
public NON_EXPORTED_BASE(GestureEventQueueClient),
+ public NON_EXPORTED_BASE(MouseWheelEventQueueClient),
public NON_EXPORTED_BASE(TouchEventQueueClient),
public NON_EXPORTED_BASE(TouchpadTapSuppressionControllerClient) {
public:
@@ -75,7 +78,9 @@ class CONTENT_EXPORT InputRouterImpl
// IPC::Listener
bool OnMessageReceived(const IPC::Message& message) override;
-private:
+ void SetFrameTreeNodeId(int frameTreeNodeId) override;
+
+ private:
friend class InputRouterImplTest;
// TouchpadTapSuppressionControllerClient
@@ -87,13 +92,24 @@ private:
const TouchEventWithLatencyInfo& touch_event) override;
void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
InputEventAckState ack_result) override;
+ void OnFilteringTouchEvent(
+ const blink::WebTouchEvent& touch_event) override;
- // GetureEventFilterClient
+ // GestureEventFilterClient
void SendGestureEventImmediately(
const GestureEventWithLatencyInfo& gesture_event) override;
void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) override;
+ // MouseWheelEventQueueClient
+ void SendMouseWheelEventImmediately(
+ const MouseWheelEventWithLatencyInfo& touch_event) override;
+ void OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& gesture_event,
+ const ui::LatencyInfo& latency_info) override;
+
bool SendMoveCaret(scoped_ptr<IPC::Message> message);
bool SendSelectMessage(scoped_ptr<IPC::Message> message);
bool Send(IPC::Message* message);
@@ -115,7 +131,8 @@ private:
// Returns true if |input_event| was successfully sent to the renderer
// as an async IPC Message.
bool OfferToRenderer(const blink::WebInputEvent& input_event,
- const ui::LatencyInfo& latency_info);
+ const ui::LatencyInfo& latency_info,
+ InputEventDispatchType dispatch_type);
// IPC message handlers
void OnInputEventAck(const InputEventAck& ack);
@@ -182,11 +199,11 @@ private:
int routing_id() const { return routing_id_; }
-
IPC::Sender* sender_;
InputRouterClient* client_;
InputAckHandler* ack_handler_;
int routing_id_;
+ int frame_tree_node_id_;
// (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK
// or MoveRangeSelectionExtent_ACK.
@@ -211,21 +228,6 @@ private:
scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move_;
MouseEventWithLatencyInfo current_mouse_move_;
- // (Similar to |mouse_move_pending_|.) True if a mouse wheel event was sent
- // and we are waiting for a corresponding ack.
- bool mouse_wheel_pending_;
- MouseWheelEventWithLatencyInfo current_wheel_event_;
-
- // (Similar to |next_mouse_move_|.) The next mouse wheel events to send.
- // Unlike mouse moves, mouse wheel events received while one is pending are
- // coalesced (by accumulating deltas) if they match the previous event in
- // modifiers. On the Mac, in particular, mouse wheel events are received at a
- // high rate; not waiting for the ack results in jankiness, and using the same
- // mechanism as for mouse moves (just dropping old events when multiple ones
- // would be queued) results in very slow scrolling.
- typedef std::deque<MouseWheelEventWithLatencyInfo> WheelEventQueue;
- WheelEventQueue coalesced_mouse_wheel_events_;
-
// A queue of keyboard events. We can't trust data from the renderer so we
// stuff key events into a queue and pop them out on ACK, feeding our copy
// back to whatever unhandled handler instead of the returned version.
@@ -248,6 +250,7 @@ private:
// to avoid races in bookkeeping when starting a new fling.
int active_renderer_fling_count_;
+ MouseWheelEventQueue wheel_event_queue_;
TouchEventQueue touch_event_queue_;
GestureEventQueue gesture_event_queue_;
TouchActionFilter touch_action_filter_;
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc b/chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc
index edf67f109a6..90af47fa711 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc
@@ -87,6 +87,9 @@ class NullInputRouterClient : public InputRouterClient {
void DidFlush() override {}
void DidOverscroll(const DidOverscrollParams& params) override {}
void DidStopFlinging() override {}
+ void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency_info) override {}
};
class NullIPCSender : public IPC::Sender {
@@ -239,7 +242,7 @@ class InputRouterImplPerfTest : public testing::Test {
void SendEventAckIfNecessary(const blink::WebInputEvent& event,
InputEventAckState ack_result) {
- if (!WebInputEventTraits::WillReceiveAckFromRenderer(event))
+ if (!WebInputEventTraits::ShouldBlockEventStream(event))
return;
InputEventAck ack(event.type, ack_result);
InputHostMsg_HandleInputEvent_ACK response(0, ack);
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc b/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 26b69e97c51..861ecaeefa8 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -167,6 +167,18 @@ class InputRouterImplTest : public testing::Test {
browser_context_.reset();
}
+ void SetUpForGestureBasedWheelScrolling(bool enabled) {
+ CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWheelGestures) &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableWheelGestures));
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ enabled ? switches::kEnableWheelGestures
+ : switches::kDisableWheelGestures);
+ TearDown();
+ SetUp();
+ }
+
void SetUpForTouchAckTimeoutTest(int desktop_timeout_ms,
int mobile_timeout_ms) {
config_.touch_config.desktop_touch_ack_timeout_delay =
@@ -936,6 +948,8 @@ TEST_F(InputRouterImplTest, AckedTouchEventState) {
#endif // defined(USE_AURA)
TEST_F(InputRouterImplTest, UnhandledWheelEvent) {
+ SetUpForGestureBasedWheelScrolling(false);
+
// Simulate wheel events.
SimulateWheelEvent(0, 0, 0, -5, 0, false); // sent directly
SimulateWheelEvent(0, 0, 0, -10, 0, false); // enqueued
@@ -959,18 +973,59 @@ TEST_F(InputRouterImplTest, UnhandledWheelEvent) {
InputMsg_HandleInputEvent::ID));
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ // Indicate that the wheel event was unhandled.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
// Check that the correct unhandled wheel event was received.
+ EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_handler_->ack_state());
+ EXPECT_EQ(ack_handler_->acked_wheel_event().deltaY, -10);
+}
+
+TEST_F(InputRouterImplTest, UnhandledWheelEventWithGestureScrolling) {
+ SetUpForGestureBasedWheelScrolling(true);
+
+ // Simulate wheel events.
+ SimulateWheelEvent(0, 0, 0, -5, 0, false); // sent directly
+ SimulateWheelEvent(0, 0, 0, -10, 0, false); // enqueued
+
+ // Check that only the first event was sent.
+ EXPECT_TRUE(
+ process_->sink().GetUniqueMessageMatching(InputMsg_HandleInputEvent::ID));
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Indicate that the wheel event was unhandled.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Check that the ack for the MouseWheel and ScrollBegin
+ // were processed.
+ EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount());
+
+ // There should be a ScrollBegin and ScrollUpdate, MouseWheel sent
+ EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
+
EXPECT_EQ(ack_handler_->acked_wheel_event().deltaY, -5);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Check that the correct unhandled wheel event was received.
+ EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_handler_->ack_state());
+ EXPECT_EQ(ack_handler_->acked_wheel_event().deltaY, -10);
}
TEST_F(InputRouterImplTest, TouchTypesIgnoringAck) {
OnHasTouchEventHandlers(true);
// Only acks for TouchCancel should always be ignored.
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(WebInputEvent::TouchStart)));
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(WebInputEvent::TouchMove)));
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(WebInputEvent::TouchEnd)));
// Precede the TouchCancel with an appropriate TouchStart;
@@ -1029,8 +1084,7 @@ TEST_F(InputRouterImplTest, GestureTypesIgnoringAck) {
WebInputEvent::GestureScrollEnd};
for (size_t i = 0; i < arraysize(eventTypes); ++i) {
WebInputEvent::Type type = eventTypes[i];
- if (WebInputEventTraits::WillReceiveAckFromRenderer(
- GetEventWithType(type))) {
+ if (WebInputEventTraits::ShouldBlockEventStream(GetEventWithType(type))) {
SimulateGestureEvent(type, blink::WebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
@@ -1060,7 +1114,7 @@ TEST_F(InputRouterImplTest, MouseTypesIgnoringAck) {
for (int i = start_type; i <= end_type; ++i) {
WebInputEvent::Type type = static_cast<WebInputEvent::Type>(i);
int expected_in_flight_event_count =
- !WebInputEventTraits::WillReceiveAckFromRenderer(GetEventWithType(type))
+ !WebInputEventTraits::ShouldBlockEventStream(GetEventWithType(type))
? 0
: 1;
@@ -1080,7 +1134,7 @@ TEST_F(InputRouterImplTest, MouseTypesIgnoringAck) {
}
// Guard against breaking changes to the list of ignored event ack types in
-// |WebInputEventTraits::WillReceiveAckFromRenderer|.
+// |WebInputEventTraits::ShouldBlockEventStream|.
TEST_F(InputRouterImplTest, RequiredEventAckTypes) {
const WebInputEvent::Type kRequiredEventAckTypes[] = {
WebInputEvent::MouseMove,
@@ -1098,7 +1152,7 @@ TEST_F(InputRouterImplTest, RequiredEventAckTypes) {
};
for (size_t i = 0; i < arraysize(kRequiredEventAckTypes); ++i) {
const WebInputEvent::Type required_ack_type = kRequiredEventAckTypes[i];
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(required_ack_type)));
}
}
@@ -1529,7 +1583,7 @@ TEST_F(InputRouterImplTest, DoubleTapGestureDependsOnFirstTap) {
blink::WebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
// This test will become invalid if GestureTap stops requiring an ack.
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(WebInputEvent::GestureTap)));
EXPECT_EQ(2, client_->in_flight_event_count());
SendInputEventACK(WebInputEvent::GestureTap,
@@ -1559,7 +1613,7 @@ TEST_F(InputRouterImplTest, DoubleTapGestureDependsOnFirstTap) {
SimulateGestureEvent(WebInputEvent::GestureDoubleTap,
blink::WebGestureDeviceTouchscreen);
// This test will become invalid if GestureDoubleTap stops requiring an ack.
- ASSERT_TRUE(WebInputEventTraits::WillReceiveAckFromRenderer(
+ ASSERT_TRUE(WebInputEventTraits::ShouldBlockEventStream(
GetEventWithType(WebInputEvent::GestureDoubleTap)));
EXPECT_EQ(1, client_->in_flight_event_count());
SendInputEventACK(WebInputEvent::GestureTap, INPUT_EVENT_ACK_STATE_CONSUMED);
@@ -1781,7 +1835,8 @@ TEST_F(InputRouterImplTest, TouchpadPinchAndScrollUpdate) {
EXPECT_EQ(1, client_->in_flight_event_count());
// Ack the wheel event.
- SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendInputEventACK(WebInputEvent::GesturePinchUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(0, client_->in_flight_event_count());
@@ -1824,6 +1879,38 @@ TEST_F(InputRouterImplTest, OverscrollDispatch) {
client_overscroll.current_fling_velocity);
}
+// Tests that touch event stream validation passes when events are filtered
+// out. See crbug.com/581231 for details.
+TEST_F(InputRouterImplTest, TouchValidationPassesWithFilteredInputEvents) {
+ // Touch sequence with touch handler.
+ OnHasTouchEventHandlers(true);
+ PressTouchPoint(1, 1);
+ uint32_t touch_press_event_id = SendTouchEvent();
+ SendTouchEventACK(WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ touch_press_event_id);
+
+ PressTouchPoint(1, 1);
+ touch_press_event_id = SendTouchEvent();
+ SendTouchEventACK(WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ touch_press_event_id);
+
+ // This event will be filtered out, since no consumer exists.
+ ReleaseTouchPoint(1);
+ uint32_t touch_release_event_id = SendTouchEvent();
+ SendTouchEventACK(WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
+ touch_release_event_id);
+
+ // If the validator didn't see the filtered out release event, it will crash
+ // now, upon seeing a press for a touch which it believes to be still pressed.
+ PressTouchPoint(1, 1);
+ touch_press_event_id = SendTouchEvent();
+ SendTouchEventACK(WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ touch_press_event_id);
+}
+
namespace {
class InputRouterImplScaleEventTest : public InputRouterImplTest {
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
index 07d3d17946e..3ff8a1dc909 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -61,6 +61,14 @@ void MockInputRouterClient::DidOverscroll(const DidOverscrollParams& params) {
void MockInputRouterClient::DidStopFlinging() {
}
+void MockInputRouterClient::ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& gesture_event,
+ const ui::LatencyInfo& latency_info) {
+ if (input_router_)
+ input_router_->SendGestureEvent(
+ GestureEventWithLatencyInfo(gesture_event, latency_info));
+}
+
bool MockInputRouterClient::GetAndResetFilterEventCalled() {
bool filter_input_event_called = filter_input_event_called_;
filter_input_event_called_ = false;
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.h b/chromium/content/browser/renderer_host/input/mock_input_router_client.h
index 3ae88350626..29bc4ce6bb8 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/chromium/content/browser/renderer_host/input/mock_input_router_client.h
@@ -31,6 +31,9 @@ class MockInputRouterClient : public InputRouterClient {
void DidFlush() override;
void DidOverscroll(const DidOverscrollParams& params) override;
void DidStopFlinging() override;
+ void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& gesture_event,
+ const ui::LatencyInfo& latency_info) override;
bool GetAndResetFilterEventCalled();
size_t GetAndResetDidFlushCount();
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
new file mode 100644
index 00000000000..b459b19aea1
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -0,0 +1,288 @@
+// 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 "content/browser/renderer_host/input/mouse_wheel_event_queue.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/trace_event/trace_event.h"
+
+using blink::WebGestureEvent;
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+using ui::LatencyInfo;
+
+namespace content {
+
+// This class represents a single queued mouse wheel event. Its main use
+// is that it is reported via trace events.
+class QueuedWebMouseWheelEvent : public MouseWheelEventWithLatencyInfo {
+ public:
+ QueuedWebMouseWheelEvent(const MouseWheelEventWithLatencyInfo& original_event)
+ : MouseWheelEventWithLatencyInfo(original_event) {
+ TRACE_EVENT_ASYNC_BEGIN0("input", "MouseWheelEventQueue::QueueEvent", this);
+ }
+
+ ~QueuedWebMouseWheelEvent() {
+ TRACE_EVENT_ASYNC_END0("input", "MouseWheelEventQueue::QueueEvent", this);
+ }
+
+ private:
+ bool original_can_scroll_;
+ DISALLOW_COPY_AND_ASSIGN(QueuedWebMouseWheelEvent);
+};
+
+MouseWheelEventQueue::MouseWheelEventQueue(MouseWheelEventQueueClient* client,
+ bool send_gestures,
+ int64_t scroll_transaction_ms)
+ : client_(client),
+ needs_scroll_begin_(true),
+ needs_scroll_end_(false),
+ send_gestures_(send_gestures),
+ scroll_transaction_ms_(scroll_transaction_ms),
+ scrolling_device_(blink::WebGestureDeviceUninitialized) {
+ DCHECK(client);
+}
+
+MouseWheelEventQueue::~MouseWheelEventQueue() {
+ if (!wheel_queue_.empty())
+ STLDeleteElements(&wheel_queue_);
+}
+
+void MouseWheelEventQueue::QueueEvent(
+ const MouseWheelEventWithLatencyInfo& event) {
+ TRACE_EVENT0("input", "MouseWheelEventQueue::QueueEvent");
+
+ if (event_sent_for_gesture_ack_ && !wheel_queue_.empty()) {
+ QueuedWebMouseWheelEvent* last_event = wheel_queue_.back();
+ if (last_event->CanCoalesceWith(event)) {
+ last_event->CoalesceWith(event);
+ TRACE_EVENT_INSTANT2("input", "MouseWheelEventQueue::CoalescedWheelEvent",
+ TRACE_EVENT_SCOPE_THREAD, "total_dx",
+ last_event->event.deltaX, "total_dy",
+ last_event->event.deltaY);
+ return;
+ }
+ }
+
+ wheel_queue_.push_back(new QueuedWebMouseWheelEvent(event));
+ TryForwardNextEventToRenderer();
+ LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", wheel_queue_.size());
+}
+
+void MouseWheelEventQueue::ProcessMouseWheelAck(
+ InputEventAckState ack_result,
+ const LatencyInfo& latency_info) {
+ TRACE_EVENT0("input", "MouseWheelEventQueue::ProcessMouseWheelAck");
+ if (!event_sent_for_gesture_ack_)
+ return;
+
+ event_sent_for_gesture_ack_->latency.AddNewLatencyFrom(latency_info);
+ client_->OnMouseWheelEventAck(*event_sent_for_gesture_ack_, ack_result);
+
+ // If event wasn't consumed then generate a gesture scroll for it.
+ if (send_gestures_ && ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
+ event_sent_for_gesture_ack_->event.canScroll &&
+ event_sent_for_gesture_ack_->event.resendingPluginId == -1 &&
+ (scrolling_device_ == blink::WebGestureDeviceUninitialized ||
+ scrolling_device_ == blink::WebGestureDeviceTouchpad)) {
+ WebGestureEvent scroll_update;
+ scroll_update.timeStampSeconds =
+ event_sent_for_gesture_ack_->event.timeStampSeconds;
+
+ scroll_update.x = event_sent_for_gesture_ack_->event.x;
+ scroll_update.y = event_sent_for_gesture_ack_->event.y;
+ scroll_update.globalX = event_sent_for_gesture_ack_->event.globalX;
+ scroll_update.globalY = event_sent_for_gesture_ack_->event.globalY;
+ scroll_update.type = WebInputEvent::GestureScrollUpdate;
+ scroll_update.sourceDevice = blink::WebGestureDeviceTouchpad;
+ scroll_update.resendingPluginId = -1;
+ scroll_update.data.scrollUpdate.deltaX =
+ event_sent_for_gesture_ack_->event.deltaX;
+ scroll_update.data.scrollUpdate.deltaY =
+ event_sent_for_gesture_ack_->event.deltaY;
+ // Only OSX populates the momentumPhase; so expect this to
+ // always be PhaseNone on all other platforms.
+ scroll_update.data.scrollUpdate.inertial =
+ event_sent_for_gesture_ack_->event.momentumPhase !=
+ blink::WebMouseWheelEvent::PhaseNone;
+ if (event_sent_for_gesture_ack_->event.scrollByPage) {
+ scroll_update.data.scrollUpdate.deltaUnits = WebGestureEvent::Page;
+
+ // Turn page scrolls into a *single* page scroll because
+ // the magnitude the number of ticks is lost when coalescing.
+ if (scroll_update.data.scrollUpdate.deltaX)
+ scroll_update.data.scrollUpdate.deltaX =
+ scroll_update.data.scrollUpdate.deltaX > 0 ? 1 : -1;
+ if (scroll_update.data.scrollUpdate.deltaY)
+ scroll_update.data.scrollUpdate.deltaY =
+ scroll_update.data.scrollUpdate.deltaY > 0 ? 1 : -1;
+ } else {
+ scroll_update.data.scrollUpdate.deltaUnits =
+ event_sent_for_gesture_ack_->event.hasPreciseScrollingDeltas
+ ? WebGestureEvent::PrecisePixels
+ : WebGestureEvent::Pixels;
+
+ if (event_sent_for_gesture_ack_->event.railsMode ==
+ WebInputEvent::RailsModeVertical)
+ scroll_update.data.scrollUpdate.deltaX = 0;
+ if (event_sent_for_gesture_ack_->event.railsMode ==
+ WebInputEvent::RailsModeHorizontal)
+ scroll_update.data.scrollUpdate.deltaY = 0;
+ }
+
+ bool current_phase_ended = false;
+ bool has_phase_info = false;
+
+ if (event_sent_for_gesture_ack_->event.phase !=
+ blink::WebMouseWheelEvent::PhaseNone ||
+ event_sent_for_gesture_ack_->event.momentumPhase !=
+ blink::WebMouseWheelEvent::PhaseNone) {
+ has_phase_info = true;
+ current_phase_ended = event_sent_for_gesture_ack_->event.phase ==
+ blink::WebMouseWheelEvent::PhaseEnded ||
+ event_sent_for_gesture_ack_->event.phase ==
+ blink::WebMouseWheelEvent::PhaseCancelled ||
+ event_sent_for_gesture_ack_->event.momentumPhase ==
+ blink::WebMouseWheelEvent::PhaseEnded ||
+ event_sent_for_gesture_ack_->event.momentumPhase ==
+ blink::WebMouseWheelEvent::PhaseCancelled;
+ }
+
+ bool needs_update = scroll_update.data.scrollUpdate.deltaX != 0 ||
+ scroll_update.data.scrollUpdate.deltaY != 0;
+
+ // If there is no update to send and the current phase is ended yet a GSB
+ // needs to be sent, this event sequence doesn't need to be generated
+ // because the events generated will be a GSB (non-synthetic) and GSE
+ // (non-synthetic). This situation arises when OSX generates double
+ // phase end information.
+ bool empty_sequence =
+ !needs_update && needs_scroll_begin_ && current_phase_ended;
+
+ if (needs_update || !empty_sequence) {
+ if (needs_scroll_begin_) {
+ // If no GSB has been sent, it will be a non-synthetic GSB.
+ SendScrollBegin(scroll_update, false);
+ } else if (has_phase_info) {
+ // If a GSB has been sent, generate a synthetic GSB if we have phase
+ // information. This should be removed once crbug.com/526463 is fully
+ // implemented.
+ SendScrollBegin(scroll_update, true);
+ }
+
+ if (needs_update) {
+ ui::LatencyInfo latency = ui::LatencyInfo();
+ latency.AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0,
+ 0);
+ client_->ForwardGestureEventWithLatencyInfo(scroll_update, latency);
+ }
+
+ if (current_phase_ended) {
+ // Non-synthetic GSEs are sent when the current phase is canceled or
+ // ended.
+ SendScrollEnd(scroll_update, false);
+ } else if (has_phase_info) {
+ // Generate a synthetic GSE for every update to force hit testing so
+ // that the non-latching behavior is preserved. Remove once
+ // crbug.com/526463 is fully implemented.
+ SendScrollEnd(scroll_update, true);
+ } else {
+ scroll_end_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(scroll_transaction_ms_),
+ base::Bind(&MouseWheelEventQueue::SendScrollEnd,
+ base::Unretained(this), scroll_update, false));
+ }
+ }
+ }
+
+ event_sent_for_gesture_ack_.reset();
+ TryForwardNextEventToRenderer();
+}
+
+void MouseWheelEventQueue::OnGestureScrollEvent(
+ const GestureEventWithLatencyInfo& gesture_event) {
+ if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
+ // If there is a current scroll going on and a new scroll that isn't
+ // wheel based cancel current one by sending a ScrollEnd.
+ if (scroll_end_timer_.IsRunning() &&
+ gesture_event.event.sourceDevice != blink::WebGestureDeviceTouchpad) {
+ base::Closure task = scroll_end_timer_.user_task();
+ scroll_end_timer_.Reset();
+ task.Run();
+ }
+ scrolling_device_ = gesture_event.event.sourceDevice;
+ } else if (scrolling_device_ == gesture_event.event.sourceDevice &&
+ (gesture_event.event.type ==
+ blink::WebInputEvent::GestureScrollEnd ||
+ gesture_event.event.type ==
+ blink::WebInputEvent::GestureFlingStart)) {
+ scrolling_device_ = blink::WebGestureDeviceUninitialized;
+ if (scroll_end_timer_.IsRunning())
+ scroll_end_timer_.Reset();
+ }
+}
+
+void MouseWheelEventQueue::TryForwardNextEventToRenderer() {
+ TRACE_EVENT0("input", "MouseWheelEventQueue::TryForwardNextEventToRenderer");
+
+ if (wheel_queue_.empty() || event_sent_for_gesture_ack_)
+ return;
+
+ event_sent_for_gesture_ack_.reset(wheel_queue_.front());
+ wheel_queue_.pop_front();
+
+ client_->SendMouseWheelEventImmediately(*event_sent_for_gesture_ack_);
+}
+
+void MouseWheelEventQueue::SendScrollEnd(WebGestureEvent update_event,
+ bool synthetic) {
+ DCHECK((synthetic && !needs_scroll_end_) || needs_scroll_end_);
+
+ WebGestureEvent scroll_end(update_event);
+ scroll_end.timeStampSeconds =
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+ scroll_end.type = WebInputEvent::GestureScrollEnd;
+ scroll_end.resendingPluginId = -1;
+ scroll_end.data.scrollEnd.synthetic = synthetic;
+ scroll_end.data.scrollEnd.inertial = update_event.data.scrollUpdate.inertial;
+ scroll_end.data.scrollEnd.deltaUnits =
+ update_event.data.scrollUpdate.deltaUnits;
+
+ if (!synthetic) {
+ needs_scroll_begin_ = true;
+ needs_scroll_end_ = false;
+
+ if (scroll_end_timer_.IsRunning())
+ scroll_end_timer_.Reset();
+ }
+ client_->ForwardGestureEventWithLatencyInfo(scroll_end, ui::LatencyInfo());
+}
+
+void MouseWheelEventQueue::SendScrollBegin(
+ const WebGestureEvent& gesture_update,
+ bool synthetic) {
+ DCHECK((synthetic && !needs_scroll_begin_) || needs_scroll_begin_);
+
+ WebGestureEvent scroll_begin(gesture_update);
+ scroll_begin.type = WebInputEvent::GestureScrollBegin;
+ scroll_begin.data.scrollBegin.synthetic = synthetic;
+ scroll_begin.data.scrollBegin.inertial =
+ gesture_update.data.scrollUpdate.inertial;
+ scroll_begin.data.scrollBegin.deltaXHint =
+ gesture_update.data.scrollUpdate.deltaX;
+ scroll_begin.data.scrollBegin.deltaYHint =
+ gesture_update.data.scrollUpdate.deltaY;
+ scroll_begin.data.scrollBegin.targetViewport = false;
+ scroll_begin.data.scrollBegin.deltaHintUnits =
+ gesture_update.data.scrollUpdate.deltaUnits;
+
+ needs_scroll_begin_ = false;
+ needs_scroll_end_ = true;
+ client_->ForwardGestureEventWithLatencyInfo(scroll_begin, ui::LatencyInfo());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.h
new file mode 100644
index 00000000000..5c5c51e9507
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -0,0 +1,110 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_EVENT_QUEUE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_EVENT_QUEUE_H_
+
+#include <deque>
+
+#include "base/time/time.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
+#include "content/common/content_export.h"
+#include "content/common/input/input_event_ack_state.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+
+// The duration in which a ScrollEnd will be sent after the last
+// ScrollUpdate was sent for wheel based gesture scrolls.
+// Set the default wheel transaction to 0ms until
+// crbug.com/526463 is fully implemented.
+const int64_t kDefaultWheelScrollTransactionMs = 0; // 100;
+
+class QueuedWebMouseWheelEvent;
+
+// Interface with which MouseWheelEventQueue can forward mouse wheel events,
+// and dispatch mouse wheel event responses.
+class CONTENT_EXPORT MouseWheelEventQueueClient {
+ public:
+ virtual ~MouseWheelEventQueueClient() {}
+
+ virtual void SendMouseWheelEventImmediately(
+ const MouseWheelEventWithLatencyInfo& event) = 0;
+ virtual void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency_info) = 0;
+ virtual void OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) = 0;
+};
+
+// A queue for throttling and coalescing mouse wheel events.
+class CONTENT_EXPORT MouseWheelEventQueue {
+ public:
+ // The |client| must outlive the MouseWheelEventQueue. |send_gestures|
+ // indicates whether mouse wheel events should generate
+ // Scroll[Begin|Update|End] on unhandled acknowledge events.
+ // |scroll_transaction_ms| is the duration in which the
+ // ScrollEnd should be sent after a ScrollUpdate.
+ MouseWheelEventQueue(MouseWheelEventQueueClient* client,
+ bool send_gestures,
+ int64_t scroll_transaction_ms);
+
+ ~MouseWheelEventQueue();
+
+ // Adds an event to the queue. The event may be coalesced with previously
+ // queued events (e.g. consecutive mouse-wheel events can be coalesced into a
+ // single mouse-wheel event). The event may also be immediately forwarded to
+ // the renderer (e.g. when there are no other queued mouse-wheel event).
+ void QueueEvent(const MouseWheelEventWithLatencyInfo& event);
+
+ // Notifies the queue that a mouse wheel event has been processed by the
+ // renderer.
+ void ProcessMouseWheelAck(InputEventAckState ack_result,
+ const ui::LatencyInfo& latency_info);
+
+ // When GestureScrollBegin is received, and it is a different source
+ // than mouse wheels terminate the current GestureScroll if there is one.
+ // When Gesture{ScrollEnd,FlingStart} is received, resume generating
+ // gestures.
+ void OnGestureScrollEvent(const GestureEventWithLatencyInfo& gesture_event);
+
+ bool has_pending() const WARN_UNUSED_RESULT {
+ return !wheel_queue_.empty() || event_sent_for_gesture_ack_;
+ }
+
+ size_t queued_size() const { return wheel_queue_.size(); }
+ bool event_in_flight() const {
+ return event_sent_for_gesture_ack_ != nullptr;
+ }
+
+ private:
+ void TryForwardNextEventToRenderer();
+ void SendScrollEnd(blink::WebGestureEvent update_event, bool synthetic);
+ void SendScrollBegin(const blink::WebGestureEvent& gesture_update,
+ bool synthetic);
+
+ MouseWheelEventQueueClient* client_;
+ base::OneShotTimer scroll_end_timer_;
+
+ typedef std::deque<QueuedWebMouseWheelEvent*> WheelEventQueue;
+ WheelEventQueue wheel_queue_;
+ scoped_ptr<QueuedWebMouseWheelEvent> event_sent_for_gesture_ack_;
+
+ // True if a non-synthetic GSB needs to be sent before a GSU is sent.
+ bool needs_scroll_begin_;
+
+ // True if a non-synthetic GSE needs to be sent because a non-synthetic
+ // GSB has been sent in the past.
+ bool needs_scroll_end_;
+
+ bool send_gestures_;
+ int64_t scroll_transaction_ms_;
+ blink::WebGestureDevice scrolling_device_;
+
+ DISALLOW_COPY_AND_ASSIGN(MouseWheelEventQueue);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_EVENT_QUEUE_H_
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
new file mode 100644
index 00000000000..c88761abb66
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -0,0 +1,547 @@
+// 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 "content/browser/renderer_host/input/mouse_wheel_event_queue.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/browser/renderer_host/input/timeout_monitor.h"
+#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using blink::WebGestureEvent;
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+
+namespace content {
+namespace {
+
+const float kWheelScrollX = 10;
+const float kWheelScrollY = 12;
+const float kWheelScrollGlobalX = 50;
+const float kWheelScrollGlobalY = 72;
+const int64_t kScrollEndTimeoutMs = 100;
+
+base::TimeDelta DefaultScrollEndTimeoutDelay() {
+ return base::TimeDelta::FromMilliseconds(kScrollEndTimeoutMs);
+}
+
+#define EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event) \
+ EXPECT_EQ(WebInputEvent::GestureScrollBegin, event->type); \
+ EXPECT_EQ(kWheelScrollX, event->x); \
+ EXPECT_EQ(kWheelScrollY, event->y); \
+ EXPECT_EQ(kWheelScrollGlobalX, event->globalX); \
+ EXPECT_EQ(kWheelScrollGlobalY, event->globalY); \
+ EXPECT_EQ(scroll_units, event->data.scrollBegin.deltaHintUnits);
+
+#define EXPECT_GESTURE_SCROLL_BEGIN(event) \
+ EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollBegin.synthetic); \
+ EXPECT_FALSE(event->data.scrollBegin.inertial);
+
+#define EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(event) \
+ EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
+ EXPECT_TRUE(event->data.scrollBegin.synthetic); \
+ EXPECT_FALSE(event->data.scrollBegin.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
+ EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollBegin.synthetic); \
+ EXPECT_TRUE(event->data.scrollBegin.inertial);
+
+#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
+ EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
+ EXPECT_TRUE(event->data.scrollBegin.synthetic); \
+ EXPECT_TRUE(event->data.scrollBegin.inertial);
+
+#define EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event) \
+ EXPECT_EQ(WebInputEvent::GestureScrollUpdate, event->type); \
+ EXPECT_EQ(scroll_units, event->data.scrollUpdate.deltaUnits); \
+ EXPECT_EQ(kWheelScrollX, event->x); \
+ EXPECT_EQ(kWheelScrollY, event->y); \
+ EXPECT_EQ(kWheelScrollGlobalX, event->globalX); \
+ EXPECT_EQ(kWheelScrollGlobalY, event->globalY);
+
+#define EXPECT_GESTURE_SCROLL_UPDATE(event) \
+ EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollUpdate.inertial);
+
+#define EXPECT_GESTURE_SCROLL_UPDATE(event) \
+ EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollUpdate.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(event) \
+ EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
+ EXPECT_TRUE(event->data.scrollUpdate.inertial);
+
+#define EXPECT_GESTURE_SCROLL_END_IMPL(event) \
+ EXPECT_EQ(WebInputEvent::GestureScrollEnd, event->type); \
+ EXPECT_EQ(scroll_units, event->data.scrollEnd.deltaUnits); \
+ EXPECT_EQ(kWheelScrollX, event->x); \
+ EXPECT_EQ(kWheelScrollY, event->y); \
+ EXPECT_EQ(kWheelScrollGlobalX, event->globalX); \
+ EXPECT_EQ(kWheelScrollGlobalY, event->globalY);
+
+#define EXPECT_GESTURE_SCROLL_END(event) \
+ EXPECT_GESTURE_SCROLL_END_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollEnd.synthetic); \
+ EXPECT_FALSE(event->data.scrollEnd.inertial);
+
+#define EXPECT_SYNTHETIC_GESTURE_SCROLL_END(event) \
+ EXPECT_GESTURE_SCROLL_END_IMPL(event); \
+ EXPECT_TRUE(event->data.scrollEnd.synthetic); \
+ EXPECT_FALSE(event->data.scrollEnd.inertial);
+
+#define EXPECT_INERTIAL_GESTURE_SCROLL_END(event) \
+ EXPECT_GESTURE_SCROLL_END_IMPL(event); \
+ EXPECT_FALSE(event->data.scrollEnd.synthetic); \
+ EXPECT_TRUE(event->data.scrollEnd.inertial);
+
+#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(event) \
+ EXPECT_GESTURE_SCROLL_END_IMPL(event); \
+ EXPECT_TRUE(event->data.scrollEnd.synthetic); \
+ EXPECT_TRUE(event->data.scrollEnd.inertial);
+
+#define EXPECT_MOUSE_WHEEL(event) \
+ EXPECT_EQ(WebInputEvent::MouseWheel, event->type);
+
+} // namespace
+
+class MouseWheelEventQueueTest : public testing::Test,
+ public MouseWheelEventQueueClient {
+ public:
+ MouseWheelEventQueueTest()
+ : acked_event_count_(0),
+ last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {
+ SetUpForGestureTesting(false);
+ }
+
+ ~MouseWheelEventQueueTest() override {}
+
+ // MouseWheelEventQueueClient
+ void SendMouseWheelEventImmediately(
+ const MouseWheelEventWithLatencyInfo& event) override {
+ WebMouseWheelEvent* cloned_event = new WebMouseWheelEvent();
+ scoped_ptr<WebInputEvent> cloned_event_holder(cloned_event);
+ *cloned_event = event.event;
+ sent_events_.push_back(std::move(cloned_event_holder));
+ }
+
+ void ForwardGestureEventWithLatencyInfo(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency_info) override {
+ WebGestureEvent* cloned_event = new WebGestureEvent();
+ scoped_ptr<WebInputEvent> cloned_event_holder(cloned_event);
+ *cloned_event = event;
+ sent_events_.push_back(std::move(cloned_event_holder));
+ }
+
+ void OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
+ ++acked_event_count_;
+ last_acked_event_ = event.event;
+ last_acked_event_state_ = ack_result;
+ }
+
+ protected:
+ void SetUpForGestureTesting(bool send_gestures) {
+ queue_.reset(
+ new MouseWheelEventQueue(this, send_gestures, kScrollEndTimeoutMs));
+ }
+
+ size_t queued_event_count() const { return queue_->queued_size(); }
+
+ bool event_in_flight() const { return queue_->event_in_flight(); }
+
+ std::vector<scoped_ptr<WebInputEvent>>& all_sent_events() {
+ return sent_events_;
+ }
+
+ const scoped_ptr<WebInputEvent>& sent_input_event(size_t index) {
+ return sent_events_[index];
+ }
+ const WebGestureEvent* sent_gesture_event(size_t index) {
+ return static_cast<WebGestureEvent*>(sent_events_[index].get());
+ }
+
+ const WebMouseWheelEvent& acked_event() const { return last_acked_event_; }
+
+ size_t GetAndResetSentEventCount() {
+ size_t count = sent_events_.size();
+ sent_events_.clear();
+ return count;
+ }
+
+ size_t GetAndResetAckedEventCount() {
+ size_t count = acked_event_count_;
+ acked_event_count_ = 0;
+ return count;
+ }
+
+ void SendMouseWheelEventAck(InputEventAckState ack_result) {
+ queue_->ProcessMouseWheelAck(ack_result, ui::LatencyInfo());
+ }
+
+ void SendMouseWheel(float x,
+ float y,
+ float global_x,
+ float global_y,
+ float dX,
+ float dY,
+ int modifiers,
+ bool high_precision,
+ WebInputEvent::RailsMode rails_mode) {
+ WebMouseWheelEvent event = SyntheticWebMouseWheelEventBuilder::Build(
+ x, y, global_x, global_y, dX, dY, modifiers, high_precision);
+ event.railsMode = rails_mode;
+ queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
+ }
+
+ void SendMouseWheel(float x,
+ float y,
+ float global_x,
+ float global_y,
+ float dX,
+ float dY,
+ int modifiers,
+ bool high_precision) {
+ SendMouseWheel(x, y, global_x, global_y, dX, dY, modifiers, high_precision,
+ WebInputEvent::RailsModeFree);
+ }
+ void SendMouseWheelWithPhase(
+ float x,
+ float y,
+ float global_x,
+ float global_y,
+ float dX,
+ float dY,
+ int modifiers,
+ bool high_precision,
+ blink::WebMouseWheelEvent::Phase phase,
+ blink::WebMouseWheelEvent::Phase momentum_phase) {
+ WebMouseWheelEvent event = SyntheticWebMouseWheelEventBuilder::Build(
+ x, y, global_x, global_y, dX, dY, modifiers, high_precision);
+ event.phase = phase;
+ event.momentumPhase = momentum_phase;
+ queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
+ }
+
+ void SendGestureEvent(WebInputEvent::Type type) {
+ WebGestureEvent event;
+ event.type = type;
+ event.sourceDevice = blink::WebGestureDeviceTouchscreen;
+ queue_->OnGestureScrollEvent(
+ GestureEventWithLatencyInfo(event, ui::LatencyInfo()));
+ }
+
+ static void RunTasksAndWait(base::TimeDelta delay) {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), delay);
+ base::MessageLoop::current()->Run();
+ }
+
+ void GestureSendingTest(bool high_precision) {
+ const WebGestureEvent::ScrollUnits scroll_units =
+ high_precision ? WebGestureEvent::PrecisePixels
+ : WebGestureEvent::Pixels;
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, high_precision);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // The second mouse wheel should not be sent since one is already in
+ // queue.
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 5, 5, 0, high_precision);
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event and release the next
+ // mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(3U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_MOUSE_WHEEL(sent_input_event(2));
+ EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+ RunTasksAndWait(DefaultScrollEndTimeoutDelay() * 2);
+ EXPECT_EQ(1U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
+ }
+
+ void PhaseGestureSendingTest(bool high_precision) {
+ const WebGestureEvent::ScrollUnits scroll_units =
+ high_precision ? WebGestureEvent::PrecisePixels
+ : WebGestureEvent::Pixels;
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, high_precision,
+ WebMouseWheelEvent::PhaseBegan,
+ WebMouseWheelEvent::PhaseNone);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(3U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
+ EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 5, 5, 0, high_precision,
+ WebMouseWheelEvent::PhaseChanged,
+ WebMouseWheelEvent::PhaseNone);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(3U, all_sent_events().size());
+ EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
+ EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 0, 0, 0, high_precision,
+ WebMouseWheelEvent::PhaseEnded,
+ WebMouseWheelEvent::PhaseNone);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_END(sent_gesture_event(1));
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+ // Send a double phase end; OSX does it consistently.
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 0, 0, 0, high_precision,
+ WebMouseWheelEvent::PhaseEnded,
+ WebMouseWheelEvent::PhaseNone);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, all_sent_events().size());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 5, 5, 0, high_precision,
+ WebMouseWheelEvent::PhaseNone,
+ WebMouseWheelEvent::PhaseBegan);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(3U, all_sent_events().size());
+ EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
+ EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 5, 5, 0, high_precision,
+ WebMouseWheelEvent::PhaseNone,
+ WebMouseWheelEvent::PhaseChanged);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(3U, all_sent_events().size());
+ EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
+ EXPECT_EQ(3U, GetAndResetSentEventCount());
+
+ SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 0, 0, 0, high_precision,
+ WebMouseWheelEvent::PhaseNone,
+ WebMouseWheelEvent::PhaseEnded);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(1));
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+ }
+
+ scoped_ptr<MouseWheelEventQueue> queue_;
+ std::vector<scoped_ptr<WebInputEvent>> sent_events_;
+ size_t acked_event_count_;
+ InputEventAckState last_acked_event_state_;
+ base::MessageLoopForUI message_loop_;
+ WebMouseWheelEvent last_acked_event_;
+};
+
+// Tests that mouse wheel events are queued properly.
+TEST_F(MouseWheelEventQueueTest, Basic) {
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // The second mouse wheel should not be sent since one is already in queue.
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 5, 5, 0, false);
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the first mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+
+ // Receive an ACK for the second mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+}
+
+TEST_F(MouseWheelEventQueueTest, GestureSending) {
+ SetUpForGestureTesting(true);
+ GestureSendingTest(false);
+}
+
+TEST_F(MouseWheelEventQueueTest, GestureSendingPrecisePixels) {
+ SetUpForGestureTesting(true);
+ GestureSendingTest(false);
+}
+
+TEST_F(MouseWheelEventQueueTest, GestureSendingWithPhaseInformation) {
+ SetUpForGestureTesting(true);
+ PhaseGestureSendingTest(false);
+}
+
+TEST_F(MouseWheelEventQueueTest,
+ GestureSendingWithPhaseInformationPrecisePixels) {
+ SetUpForGestureTesting(true);
+ PhaseGestureSendingTest(true);
+}
+
+TEST_F(MouseWheelEventQueueTest, GestureSendingInterrupted) {
+ SetUpForGestureTesting(true);
+ const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::Pixels;
+
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+ // Ensure that a gesture scroll begin terminates the current scroll event.
+ SendGestureEvent(WebInputEvent::GestureScrollBegin);
+ EXPECT_EQ(1U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // New mouse wheel events won't cause gestures because a scroll
+ // is already in progress by another device.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, all_sent_events().size());
+
+ SendGestureEvent(WebInputEvent::GestureScrollEnd);
+ EXPECT_EQ(0U, all_sent_events().size());
+
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+}
+
+TEST_F(MouseWheelEventQueueTest, GestureRailScrolling) {
+ SetUpForGestureTesting(true);
+ const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::Pixels;
+
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false,
+ WebInputEvent::RailsModeHorizontal);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_EQ(1U, sent_gesture_event(1)->data.scrollUpdate.deltaX);
+ EXPECT_EQ(0U, sent_gesture_event(1)->data.scrollUpdate.deltaY);
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+ RunTasksAndWait(DefaultScrollEndTimeoutDelay() * 2);
+ EXPECT_EQ(1U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 1, 1, 0, false,
+ WebInputEvent::RailsModeVertical);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::MouseWheel, acked_event().type);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
+ EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
+ EXPECT_EQ(0U, sent_gesture_event(1)->data.scrollUpdate.deltaX);
+ EXPECT_EQ(1U, sent_gesture_event(1)->data.scrollUpdate.deltaY);
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/non_blocking_event_browsertest.cc b/chromium/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
new file mode 100644
index 00000000000..431d1986b75
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
@@ -0,0 +1,218 @@
+// 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 <utility>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/common/input_messages.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.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 "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/event_switches.h"
+#include "ui/events/latency_info.h"
+
+using blink::WebInputEvent;
+
+namespace {
+
+// This value has to be larger than the height of the device this test is
+// executed on, otherwise the device will be unable to scroll thus failing
+// tests.
+const int kWebsiteHeight = 10000;
+
+const char kNonBlockingEventDataURL[] =
+ "data:text/html;charset=utf-8,"
+ "<!DOCTYPE html>"
+ "<meta name='viewport' content='width=device-width'/>"
+ "<style>"
+ "html, body {"
+ " margin: 0;"
+ "}"
+ ".spacer { height: 10000px; }"
+ "</style>"
+ "<div class=spacer></div>"
+ "<script>"
+ " document.addEventListener('wheel', function(e) { while(true) {} }, "
+ "{'passive': true});"
+ " document.addEventListener('touchstart', function(e) { while(true) {} }, "
+ "{'passive': true});"
+ " document.title='ready';"
+ "</script>";
+
+const char kPassiveTouchStartBlockingTouchEndDataURL[] =
+ "data:text/html;charset=utf-8,"
+ "<!DOCTYPE html>"
+ "<meta name='viewport' content='width=device-width'/>"
+ "<style>"
+ "html, body {"
+ " margin: 0;"
+ "}"
+ ".spacer { height: 10000px; }"
+ "</style>"
+ "<div class=spacer></div>"
+ "<script>"
+ " document.addEventListener('touchstart', function(e) { while(true) {} }, "
+ "{'passive': true});"
+ " document.addEventListener('touchend', function(e) { while(true) {} });"
+ " document.title='ready';"
+ "</script>";
+
+} // namespace
+
+namespace content {
+
+class NonBlockingEventBrowserTest : public ContentBrowserTest {
+ public:
+ NonBlockingEventBrowserTest() {}
+ ~NonBlockingEventBrowserTest() override {}
+
+ RenderWidgetHostImpl* GetWidgetHost() {
+ return RenderWidgetHostImpl::From(
+ shell()->web_contents()->GetRenderViewHost()->GetWidget());
+ }
+
+ void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
+ EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+ }
+
+ protected:
+ void LoadURL(const char* page_data) {
+ const GURL data_url(page_data);
+ NavigateToURL(shell(), data_url);
+
+ RenderWidgetHostImpl* host = GetWidgetHost();
+ host->GetView()->SetSize(gfx::Size(400, 400));
+
+ base::string16 ready_title(base::ASCIIToUTF16("ready"));
+ TitleWatcher watcher(shell()->web_contents(), ready_title);
+ ignore_result(watcher.WaitAndGetTitle());
+
+ MainThreadFrameObserver main_thread_sync(host);
+ main_thread_sync.Wait();
+ }
+
+ // ContentBrowserTest:
+ void SetUpCommandLine(base::CommandLine* cmd) override {
+ // TODO(dtapuska): Remove this switch once wheel-gestures ships.
+ cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+ cmd->AppendSwitch(switches::kEnableWheelGestures);
+ }
+
+ int ExecuteScriptAndExtractInt(const std::string& script) {
+ int value = 0;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(), "domAutomationController.send(" + script + ")",
+ &value));
+ return value;
+ }
+
+ int GetScrollTop() {
+ return ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop");
+ }
+
+ void DoWheelScroll() {
+ EXPECT_EQ(0, GetScrollTop());
+
+ int scrollHeight =
+ ExecuteScriptAndExtractInt("document.documentElement.scrollHeight");
+ EXPECT_EQ(kWebsiteHeight, scrollHeight);
+
+ scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
+ frame_watcher->AttachTo(shell()->web_contents());
+ scoped_refptr<InputMsgWatcher> input_msg_watcher(
+ new InputMsgWatcher(GetWidgetHost(), blink::WebInputEvent::MouseWheel));
+
+ GetWidgetHost()->ForwardWheelEvent(
+ SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true));
+
+ // Runs until we get the InputMsgAck callback
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING,
+ input_msg_watcher->WaitForAck());
+
+ // Expect that the compositor scrolled at least one pixel while the
+ // main thread was in a busy loop.
+ while (frame_watcher->LastMetadata().root_scroll_offset.y() <= 0)
+ frame_watcher->WaitFrames(1);
+ }
+
+ void DoTouchScroll() {
+ EXPECT_EQ(0, GetScrollTop());
+
+ int scrollHeight =
+ ExecuteScriptAndExtractInt("document.documentElement.scrollHeight");
+ EXPECT_EQ(kWebsiteHeight, scrollHeight);
+
+ scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
+ frame_watcher->AttachTo(shell()->web_contents());
+
+ SyntheticSmoothScrollGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ params.anchor = gfx::PointF(50, 50);
+ params.distances.push_back(gfx::Vector2d(0, -45));
+
+ scoped_ptr<SyntheticSmoothScrollGesture> gesture(
+ new SyntheticSmoothScrollGesture(params));
+ GetWidgetHost()->QueueSyntheticGesture(
+ std::move(gesture),
+ base::Bind(&NonBlockingEventBrowserTest::OnSyntheticGestureCompleted,
+ base::Unretained(this)));
+
+ // Expect that the compositor scrolled at least one pixel while the
+ // main thread was in a busy loop.
+ while (frame_watcher->LastMetadata().root_scroll_offset.y() <= 0)
+ frame_watcher->WaitFrames(1);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NonBlockingEventBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(NonBlockingEventBrowserTest, MouseWheel) {
+ LoadURL(kNonBlockingEventDataURL);
+ DoWheelScroll();
+}
+
+// Disabled on MacOS because it doesn't support touch input.
+#if defined(OS_MACOSX)
+#define MAYBE_TouchStart DISABLED_TouchStart
+#else
+#define MAYBE_TouchStart TouchStart
+#endif
+IN_PROC_BROWSER_TEST_F(NonBlockingEventBrowserTest, MAYBE_TouchStart) {
+ LoadURL(kNonBlockingEventDataURL);
+ DoTouchScroll();
+}
+
+// Disabled on MacOS because it doesn't support touch input.
+#if defined(OS_MACOSX)
+#define MAYBE_PassiveTouchStartBlockingTouchEnd \
+ DISABLED_PassiveTouchStartBlockingTouchEnd
+#else
+#define MAYBE_PassiveTouchStartBlockingTouchEnd \
+ PassiveTouchStartBlockingTouchEnd
+#endif
+IN_PROC_BROWSER_TEST_F(NonBlockingEventBrowserTest,
+ MAYBE_PassiveTouchStartBlockingTouchEnd) {
+ LoadURL(kPassiveTouchStartBlockingTouchEndDataURL);
+ DoTouchScroll();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
index 8fc03c71376..b0ba89f77e5 100644
--- a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -78,6 +78,9 @@ void UpdateLatencyCoordinates(const WebInputEvent& event,
void ComputeInputLatencyHistograms(WebInputEvent::Type type,
int64_t latency_component_id,
const LatencyInfo& latency) {
+ if (latency.coalesced())
+ return;
+
LatencyInfo::LatencyComponent rwh_component;
if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
latency_component_id, &rwh_component)) {
@@ -157,26 +160,24 @@ void ComputeScrollLatencyHistograms(
const LatencyInfo::LatencyComponent& gpu_swap_end_component,
int64_t latency_component_id,
const LatencyInfo& latency) {
+ DCHECK(!latency.coalesced());
+ if (latency.coalesced())
+ return;
+
DCHECK(!gpu_swap_begin_component.event_time.is_null());
DCHECK(!gpu_swap_end_component.event_time.is_null());
- LatencyInfo::LatencyComponent first_original_component, original_component;
+ LatencyInfo::LatencyComponent original_component;
if (latency.FindLatency(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- latency_component_id, &first_original_component)) {
+ latency_component_id, &original_component)) {
// This UMA metric tracks the time between the final frame swap for the
// first scroll event in a sequence and the original timestamp of that
// scroll event's underlying touch event.
- for (size_t i = 0; i < first_original_component.event_count; i++) {
+ for (size_t i = 0; i < original_component.event_count; i++) {
UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
"Event.Latency.TouchToFirstScrollUpdateSwapBegin",
- first_original_component, gpu_swap_begin_component);
- // TODO(brianderson): Remove this version once we have enough overlapping
- // data with the metric above. crbug.com/478845
- UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
- "Event.Latency.TouchToFirstScrollUpdateSwap",
- first_original_component, gpu_swap_end_component);
+ original_component, gpu_swap_begin_component);
}
- original_component = first_original_component;
} else if (!latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
latency_component_id, &original_component)) {
@@ -184,17 +185,11 @@ void ComputeScrollLatencyHistograms(
}
// This UMA metric tracks the time from when the original touch event is
- // created (averaged if there are multiple) to when the scroll gesture
- // results in final frame swap.
+ // created to when the scroll gesture results in final frame swap.
for (size_t i = 0; i < original_component.event_count; i++) {
UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
"Event.Latency.TouchToScrollUpdateSwapBegin", original_component,
gpu_swap_begin_component);
- // TODO(brianderson): Remove this version once we have enough overlapping
- // data with the metric above. crbug.com/478845
- UMA_HISTOGRAM_TOUCH_TO_SCROLL_LATENCY(
- "Event.Latency.TouchToScrollUpdateSwap", original_component,
- gpu_swap_end_component);
}
// TODO(miletus): Add validation for making sure the following components
@@ -292,7 +287,7 @@ RenderWidgetHostLatencyTracker::RenderWidgetHostLatencyTracker()
: last_event_id_(0),
latency_component_id_(0),
device_scale_factor_(1),
- has_seent_first_gesture_scroll_update_(false) {
+ has_seen_first_gesture_scroll_update_(false) {
}
RenderWidgetHostLatencyTracker::~RenderWidgetHostLatencyTracker() {
@@ -345,7 +340,7 @@ void RenderWidgetHostLatencyTracker::OnInputEvent(
UpdateLatencyCoordinates(event, device_scale_factor_, latency);
if (event.type == blink::WebInputEvent::GestureScrollBegin) {
- has_seent_first_gesture_scroll_update_ = false;
+ has_seen_first_gesture_scroll_update_ = false;
} else if (event.type == blink::WebInputEvent::GestureScrollUpdate) {
// Make a copy of the INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT with a
// different name INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
@@ -354,14 +349,14 @@ void RenderWidgetHostLatencyTracker::OnInputEvent(
if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
&original_component)) {
latency->AddLatencyNumberWithTimestamp(
- has_seent_first_gesture_scroll_update_
+ has_seen_first_gesture_scroll_update_
? ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT
: ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
latency_component_id_, original_component.sequence_number,
original_component.event_time, original_component.event_count);
}
- has_seent_first_gesture_scroll_update_ = true;
+ has_seen_first_gesture_scroll_update_ = true;
}
}
@@ -432,6 +427,16 @@ void RenderWidgetHostLatencyTracker::OnSwapCompositorFrame(
void RenderWidgetHostLatencyTracker::OnFrameSwapped(
const LatencyInfo& latency) {
+ // Don't report frame latency on wheel events. Previously they were only
+ // reported on touch metrics and we need to be consistent across reporting
+ // metrics.
+ LatencyInfo::LatencyComponent mouse_wheel_scroll_update_component;
+ if (latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_GENERATE_SCROLL_UPDATE_FROM_MOUSE_WHEEL, 0,
+ &mouse_wheel_scroll_update_component)) {
+ return;
+ }
+
LatencyInfo::LatencyComponent gpu_swap_end_component;
if (!latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
index 6df155fe792..633e4e878da 100644
--- a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
@@ -64,7 +64,7 @@ class CONTENT_EXPORT RenderWidgetHostLatencyTracker {
int64_t last_event_id_;
int64_t latency_component_id_;
float device_scale_factor_;
- bool has_seent_first_gesture_scroll_update_;
+ bool has_seen_first_gesture_scroll_update_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostLatencyTracker);
};
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
index baeb15cb755..32497449e01 100644
--- a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/histogram_tester.h"
#include "content/browser/renderer_host/input/render_widget_host_latency_tracker.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/public/browser/native_web_keyboard_event.h"
@@ -12,73 +13,170 @@ using blink::WebInputEvent;
namespace content {
namespace {
-const int kTestRoutingId = 3;
-const int kTestProcessId = 1;
+void AddFakeComponents(const RenderWidgetHostLatencyTracker& tracker,
+ ui::LatencyInfo* latency) {
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0, base::TimeTicks::Now(), 1);
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ tracker.latency_component_id(), 0, base::TimeTicks::Now(), 1);
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+}
+
+void AddRenderingScheduledComponent(ui::LatencyInfo* latency, bool main) {
+ if (main) {
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+
+ } else {
+ latency->AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT, 0, 0,
+ base::TimeTicks::Now(), 1);
+ }
+}
} // namespace
-TEST(RenderWidgetHostLatencyTrackerTest, Basic) {
- RenderWidgetHostLatencyTracker tracker;
- tracker.Initialize(kTestRoutingId, kTestProcessId);
+class RenderWidgetHostLatencyTrackerTest : public testing::Test {
+ public:
+ RenderWidgetHostLatencyTrackerTest() {
+ tracker_.Initialize(kTestRoutingId, kTestProcessId);
+ ResetHistograms();
+ }
- {
- auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
- 5.f, -5.f, 0, blink::WebGestureDeviceTouchscreen);
- scroll.timeStampSeconds =
- (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
- ui::LatencyInfo scroll_latency;
- tracker.OnInputEvent(scroll, &scroll_latency);
- EXPECT_TRUE(
- scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
- EXPECT_TRUE(
- scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0, nullptr));
- EXPECT_EQ(1U, scroll_latency.input_coordinates_size());
+ ::testing::AssertionResult HistogramSizeEq(const char* histogram_name,
+ int size) {
+ uint64_t histogram_size =
+ histogram_tester_->GetAllSamples(histogram_name).size();
+ if (static_cast<uint64_t>(size) == histogram_size) {
+ return ::testing::AssertionSuccess();
+ } else {
+ return ::testing::AssertionFailure() << histogram_name << " expected "
+ << size << " entries, but had "
+ << histogram_size;
+ }
}
- {
- auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
- blink::WebMouseWheelEvent::PhaseChanged);
- wheel.timeStampSeconds =
- (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
- ui::LatencyInfo wheel_latency;
- tracker.OnInputEvent(wheel, &wheel_latency);
- EXPECT_TRUE(
- wheel_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
- EXPECT_TRUE(
- wheel_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0, nullptr));
- EXPECT_EQ(1U, wheel_latency.input_coordinates_size());
+ RenderWidgetHostLatencyTracker* tracker() { return &tracker_; }
+ void ResetHistograms() {
+ histogram_tester_.reset(new base::HistogramTester());
}
- {
- SyntheticWebTouchEvent touch;
- touch.PressPoint(0, 0);
- touch.PressPoint(1, 1);
- ui::LatencyInfo touch_latency;
- tracker.OnInputEvent(touch, &touch_latency);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostLatencyTrackerTest);
+ const int kTestRoutingId = 3;
+ const int kTestProcessId = 1;
+ scoped_ptr<base::HistogramTester> histogram_tester_;
+ RenderWidgetHostLatencyTracker tracker_;
+};
+
+TEST_F(RenderWidgetHostLatencyTrackerTest, TestHistograms) {
+ for (bool rendering_on_main : { false, true }) {
+ ResetHistograms();
+ {
+ auto scroll = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
+ 5.f, -5.f, 0, blink::WebGestureDeviceTouchscreen);
+ scroll.timeStampSeconds =
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+ ui::LatencyInfo scroll_latency;
+ AddFakeComponents(*tracker(), &scroll_latency);
+ AddRenderingScheduledComponent(&scroll_latency, rendering_on_main);
+ tracker()->OnInputEvent(scroll, &scroll_latency);
+ EXPECT_TRUE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker()->latency_component_id(), nullptr));
+ EXPECT_TRUE(scroll_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, nullptr));
+ EXPECT_EQ(1U, scroll_latency.input_coordinates_size());
+ tracker()->OnInputEventAck(scroll, &scroll_latency);
+ }
+
+ {
+ auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
+ blink::WebMouseWheelEvent::PhaseChanged);
+ wheel.timeStampSeconds =
+ (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+ ui::LatencyInfo wheel_latency;
+ AddFakeComponents(*tracker(), &wheel_latency);
+ AddRenderingScheduledComponent(&wheel_latency, rendering_on_main);
+ tracker()->OnInputEvent(wheel, &wheel_latency);
+ EXPECT_TRUE(wheel_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker()->latency_component_id(), nullptr));
+ EXPECT_TRUE(wheel_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, nullptr));
+ EXPECT_EQ(1U, wheel_latency.input_coordinates_size());
+ tracker()->OnInputEventAck(wheel, &wheel_latency);
+ }
+
+ {
+ SyntheticWebTouchEvent touch;
+ touch.PressPoint(0, 0);
+ touch.PressPoint(1, 1);
+ ui::LatencyInfo touch_latency;
+ AddFakeComponents(*tracker(), &touch_latency);
+ AddRenderingScheduledComponent(&touch_latency, rendering_on_main);
+ tracker()->OnInputEvent(touch, &touch_latency);
+ EXPECT_TRUE(touch_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ tracker()->latency_component_id(), nullptr));
+ EXPECT_TRUE(touch_latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, nullptr));
+ EXPECT_EQ(2U, touch_latency.input_coordinates_size());
+ tracker()->OnInputEventAck(touch, &touch_latency);
+ tracker()->OnFrameSwapped(touch_latency);
+ }
+
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.WheelUI", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.TouchUI", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.WheelAcked", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.TouchAcked", 1));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.TouchToFirstScrollUpdateSwapBegin", 1));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.TouchToScrollUpdateSwapBegin", 1));
EXPECT_TRUE(
- touch_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Main",
+ rendering_on_main ? 1 : 0));
EXPECT_TRUE(
- touch_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
- 0, nullptr));
- EXPECT_EQ(2U, touch_latency.input_coordinates_size());
+ HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Impl",
+ rendering_on_main ? 0 : 1));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.ScrollUpdate.HandledToRendererSwap_Main",
+ rendering_on_main ? 1 : 0));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.ScrollUpdate.HandledToRendererSwap_Impl",
+ rendering_on_main ? 0 : 1));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified", 1));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.ScrollUpdate.GpuSwap", 1));
}
}
-TEST(RenderWidgetHostLatencyTrackerTest,
- LatencyTerminatedOnAckIfRenderingNotScheduled) {
- RenderWidgetHostLatencyTracker tracker;
- tracker.Initialize(kTestRoutingId, kTestProcessId);
-
+TEST_F(RenderWidgetHostLatencyTrackerTest,
+ LatencyTerminatedOnAckIfRenderingNotScheduled) {
{
auto scroll = SyntheticWebGestureEventBuilder::BuildScrollBegin(5.f, -5.f);
ui::LatencyInfo scroll_latency;
- tracker.OnInputEvent(scroll, &scroll_latency);
- tracker.OnInputEventAck(scroll, &scroll_latency);
+ AddFakeComponents(*tracker(), &scroll_latency);
+ // Don't include the rendering schedule component, since we're testing the
+ // case where rendering isn't scheduled.
+ tracker()->OnInputEvent(scroll, &scroll_latency);
+ tracker()->OnInputEventAck(scroll, &scroll_latency);
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0, nullptr));
EXPECT_TRUE(scroll_latency.terminated());
@@ -88,8 +186,9 @@ TEST(RenderWidgetHostLatencyTrackerTest,
auto wheel = SyntheticWebMouseWheelEventBuilder::Build(
blink::WebMouseWheelEvent::PhaseChanged);
ui::LatencyInfo wheel_latency;
- tracker.OnInputEvent(wheel, &wheel_latency);
- tracker.OnInputEventAck(wheel, &wheel_latency);
+ AddFakeComponents(*tracker(), &wheel_latency);
+ tracker()->OnInputEvent(wheel, &wheel_latency);
+ tracker()->OnInputEventAck(wheel, &wheel_latency);
EXPECT_TRUE(wheel_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_WHEEL_COMPONENT, 0, nullptr));
EXPECT_TRUE(wheel_latency.terminated());
@@ -99,19 +198,22 @@ TEST(RenderWidgetHostLatencyTrackerTest,
SyntheticWebTouchEvent touch;
touch.PressPoint(0, 0);
ui::LatencyInfo touch_latency;
- tracker.OnInputEvent(touch, &touch_latency);
- tracker.OnInputEventAck(touch, &touch_latency);
+ AddFakeComponents(*tracker(), &touch_latency);
+ tracker()->OnInputEvent(touch, &touch_latency);
+ tracker()->OnInputEventAck(touch, &touch_latency);
EXPECT_TRUE(touch_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, nullptr));
EXPECT_TRUE(touch_latency.terminated());
+ tracker()->OnFrameSwapped(touch_latency);
}
{
auto mouse_move = SyntheticWebMouseEventBuilder::Build(
blink::WebMouseEvent::MouseMove);
ui::LatencyInfo mouse_latency;
- tracker.OnInputEvent(mouse_move, &mouse_latency);
- tracker.OnInputEventAck(mouse_move, &mouse_latency);
+ AddFakeComponents(*tracker(), &mouse_latency);
+ tracker()->OnInputEvent(mouse_move, &mouse_latency);
+ tracker()->OnInputEventAck(mouse_move, &mouse_latency);
EXPECT_TRUE(mouse_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, nullptr));
EXPECT_TRUE(mouse_latency.terminated());
@@ -121,25 +223,44 @@ TEST(RenderWidgetHostLatencyTrackerTest,
auto key_event = SyntheticWebKeyboardEventBuilder::Build(
blink::WebKeyboardEvent::Char);
ui::LatencyInfo key_latency;
- tracker.OnInputEvent(key_event, &key_latency);
- tracker.OnInputEventAck(key_event, &key_latency);
+ AddFakeComponents(*tracker(), &key_latency);
+ tracker()->OnInputEvent(key_event, &key_latency);
+ tracker()->OnInputEventAck(key_event, &key_latency);
EXPECT_TRUE(key_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_TERMINATED_KEYBOARD_COMPONENT, 0, nullptr));
EXPECT_TRUE(key_latency.terminated());
}
-}
-TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
- RenderWidgetHostLatencyTracker tracker;
- tracker.Initialize(kTestRoutingId, kTestProcessId);
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.WheelUI", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.TouchUI", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.WheelAcked", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.Browser.TouchAcked", 1));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.TouchToFirstScrollUpdateSwapBegin", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.TouchToScrollUpdateSwapBegin", 1));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Main", 0));
+ EXPECT_TRUE(
+ HistogramSizeEq("Event.Latency.ScrollUpdate.TouchToHandled_Impl", 0));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.HandledToRendererSwap_Main", 0));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.HandledToRendererSwap_Impl", 0));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified", 0));
+ EXPECT_TRUE(HistogramSizeEq(
+ "Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap", 0));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.ScrollUpdate.GpuSwap", 0));
+}
+TEST_F(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
{
auto event =
SyntheticWebMouseWheelEventBuilder::Build(0, 0, -5, 0, 0, true);
event.x = 100;
event.y = 200;
ui::LatencyInfo latency_info;
- tracker.OnInputEvent(event, &latency_info);
+ tracker()->OnInputEvent(event, &latency_info);
EXPECT_EQ(1u, latency_info.input_coordinates_size());
EXPECT_EQ(100, latency_info.input_coordinates()[0].x);
EXPECT_EQ(200, latency_info.input_coordinates()[0].y);
@@ -150,7 +271,7 @@ TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
event.x = 300;
event.y = 400;
ui::LatencyInfo latency_info;
- tracker.OnInputEvent(event, &latency_info);
+ tracker()->OnInputEvent(event, &latency_info);
EXPECT_EQ(1u, latency_info.input_coordinates_size());
EXPECT_EQ(300, latency_info.input_coordinates()[0].x);
EXPECT_EQ(400, latency_info.input_coordinates()[0].y);
@@ -162,7 +283,7 @@ TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
event.x = 500;
event.y = 600;
ui::LatencyInfo latency_info;
- tracker.OnInputEvent(event, &latency_info);
+ tracker()->OnInputEvent(event, &latency_info);
EXPECT_EQ(1u, latency_info.input_coordinates_size());
EXPECT_EQ(500, latency_info.input_coordinates()[0].x);
EXPECT_EQ(600, latency_info.input_coordinates()[0].y);
@@ -174,7 +295,7 @@ TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
event.PressPoint(900, 1000);
event.PressPoint(1100, 1200); // LatencyInfo only holds two coordinates.
ui::LatencyInfo latency_info;
- tracker.OnInputEvent(event, &latency_info);
+ tracker()->OnInputEvent(event, &latency_info);
EXPECT_EQ(2u, latency_info.input_coordinates_size());
EXPECT_EQ(700, latency_info.input_coordinates()[0].x);
EXPECT_EQ(800, latency_info.input_coordinates()[0].y);
@@ -186,23 +307,20 @@ TEST(RenderWidgetHostLatencyTrackerTest, InputCoordinatesPopulated) {
NativeWebKeyboardEvent event;
event.type = blink::WebKeyboardEvent::KeyDown;
ui::LatencyInfo latency_info;
- tracker.OnInputEvent(event, &latency_info);
+ tracker()->OnInputEvent(event, &latency_info);
EXPECT_EQ(0u, latency_info.input_coordinates_size());
}
}
-TEST(RenderWidgetHostLatencyTrackerTest, ScrollLatency) {
- RenderWidgetHostLatencyTracker tracker;
- tracker.Initialize(kTestRoutingId, kTestProcessId);
-
+TEST_F(RenderWidgetHostLatencyTrackerTest, ScrollLatency) {
auto scroll_begin = SyntheticWebGestureEventBuilder::BuildScrollBegin(5, -5);
ui::LatencyInfo scroll_latency;
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
0);
- tracker.OnInputEvent(scroll_begin, &scroll_latency);
+ tracker()->OnInputEvent(scroll_begin, &scroll_latency);
EXPECT_TRUE(
scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_EQ(2U, scroll_latency.latency_components().size());
// The first GestureScrollUpdate should be provided with
@@ -212,35 +330,35 @@ TEST(RenderWidgetHostLatencyTrackerTest, ScrollLatency) {
scroll_latency = ui::LatencyInfo();
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
0);
- tracker.OnInputEvent(first_scroll_update, &scroll_latency);
+ tracker()->OnInputEvent(first_scroll_update, &scroll_latency);
EXPECT_TRUE(
scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_FALSE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_EQ(3U, scroll_latency.latency_components().size());
- // Subseqeunt GestureScrollUpdates should be provided with
+ // Subsequent GestureScrollUpdates should be provided with
// INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
auto scroll_update = SyntheticWebGestureEventBuilder::BuildScrollUpdate(
-5.f, 5.f, 0, blink::WebGestureDeviceTouchscreen);
scroll_latency = ui::LatencyInfo();
scroll_latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
0);
- tracker.OnInputEvent(scroll_update, &scroll_latency);
+ tracker()->OnInputEvent(scroll_update, &scroll_latency);
EXPECT_TRUE(
scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_FALSE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_TRUE(scroll_latency.FindLatency(
ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
- tracker.latency_component_id(), nullptr));
+ tracker()->latency_component_id(), nullptr));
EXPECT_EQ(3U, scroll_latency.latency_components().size());
}
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
index ebe8712e15c..a6aa6bd3c7e 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
+#include "content/browser/renderer_host/input/synthetic_pointer_action.h"
#include "content/browser/renderer_host/input/synthetic_smooth_drag_gesture.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
@@ -42,6 +43,9 @@ scoped_ptr<SyntheticGesture> SyntheticGesture::Create(
case SyntheticGestureParams::TAP_GESTURE:
return CreateGesture<SyntheticTapGesture,
SyntheticTapGestureParams>(gesture_params);
+ case SyntheticGestureParams::POINTER_ACTION:
+ return CreateGesture<SyntheticPointerAction,
+ SyntheticPointerActionParams>(gesture_params);
}
NOTREACHED() << "Invalid synthetic gesture type";
return scoped_ptr<SyntheticGesture>();
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_gesture.h
index 626bd15aa65..4177b067c49 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture.h
@@ -41,8 +41,6 @@ class CONTENT_EXPORT SyntheticGesture {
GESTURE_RESULT_MAX = GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED
};
- enum PointerActionType { PRESS, MOVE, RELEASE };
-
// Update the state of the gesture and forward the appropriate events to the
// platform. This function is called repeatedly by the synthetic gesture
// controller until it stops returning GESTURE_RUNNING.
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.h b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.h
index aeef18f5024..f7b03c2fd79 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.h
@@ -60,7 +60,7 @@ class CONTENT_EXPORT SyntheticGestureController {
~GestureAndCallbackQueue();
void Push(scoped_ptr<SyntheticGesture> gesture,
const OnGestureCompleteCallback& callback) {
- gestures_.push_back(gesture.release());
+ gestures_.push_back(std::move(gesture));
callbacks_.push(callback);
}
void Pop() {
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
index 9369bfdfdc8..c1e36823b7e 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
@@ -1470,55 +1470,56 @@ TEST_F(SyntheticGestureControllerTest, TapGestureMouse) {
TEST_F(SyntheticGestureControllerTest, PointerTouchAction) {
CreateControllerAndTarget<MockSyntheticPointerTouchActionTarget>();
+ SyntheticPointerActionParams params = SyntheticPointerActionParams(
+ SyntheticPointerActionParams::PointerActionType::PRESS);
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ params.set_index(0);
+ params.set_position(gfx::PointF(54, 89));
SyntheticTouchPointer synthetic_pointer;
- gfx::PointF position(54, 89);
- scoped_ptr<SyntheticPointerAction> gesture(new SyntheticPointerAction(
- SyntheticGestureParams::TOUCH_INPUT, SyntheticGesture::PRESS,
- &synthetic_pointer, position));
+ scoped_ptr<SyntheticPointerAction> gesture(
+ new SyntheticPointerAction(params, &synthetic_pointer));
QueueSyntheticGesture(std::move(gesture));
FlushInputUntilComplete();
MockSyntheticPointerTouchActionTarget* pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::TouchStart);
- EXPECT_EQ(pointer_touch_target->positions(0), position);
+ EXPECT_EQ(pointer_touch_target->positions(0), params.position());
EXPECT_EQ(pointer_touch_target->states(0), WebTouchPoint::StatePressed);
ASSERT_EQ(pointer_touch_target->touch_length(), 1U);
- position.SetPoint(79, 132);
- gesture.reset(new SyntheticPointerAction(SyntheticGestureParams::TOUCH_INPUT,
- SyntheticGesture::PRESS,
- &synthetic_pointer, position));
+ params.set_index(1);
+ params.set_position(gfx::PointF(79, 132));
+ gesture.reset(new SyntheticPointerAction(params, &synthetic_pointer));
QueueSyntheticGesture(std::move(gesture));
FlushInputUntilComplete();
pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::TouchStart);
- EXPECT_EQ(pointer_touch_target->indexes(1), 1);
- EXPECT_EQ(pointer_touch_target->positions(1), position);
+ EXPECT_EQ(pointer_touch_target->indexes(1), params.index());
+ EXPECT_EQ(pointer_touch_target->positions(1), params.position());
EXPECT_EQ(pointer_touch_target->states(1), WebTouchPoint::StatePressed);
ASSERT_EQ(pointer_touch_target->touch_length(), 2U);
- int index = 1;
- position.SetPoint(133, 156);
- gesture.reset(new SyntheticPointerAction(
- SyntheticGestureParams::TOUCH_INPUT, SyntheticGesture::MOVE,
- &synthetic_pointer, position, index));
+ params.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::MOVE);
+ params.set_position(gfx::PointF(133, 156));
+ gesture.reset(new SyntheticPointerAction(params, &synthetic_pointer));
QueueSyntheticGesture(std::move(gesture));
FlushInputUntilComplete();
pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::TouchMove);
- EXPECT_EQ(pointer_touch_target->positions(1), position);
+ EXPECT_EQ(pointer_touch_target->positions(1), params.position());
EXPECT_EQ(pointer_touch_target->states(1), WebTouchPoint::StateMoved);
ASSERT_EQ(pointer_touch_target->touch_length(), 2U);
- gesture.reset(new SyntheticPointerAction(
- SyntheticGestureParams::TOUCH_INPUT, SyntheticGesture::RELEASE,
- &synthetic_pointer, position, index));
+ params.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::RELEASE);
+ gesture.reset(new SyntheticPointerAction(params, &synthetic_pointer));
QueueSyntheticGesture(std::move(gesture));
FlushInputUntilComplete();
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
index 2577e3f5497..6353f342631 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -11,26 +11,24 @@
namespace content {
SyntheticPointerAction::SyntheticPointerAction(
- SyntheticGestureParams::GestureSourceType gesture_source_type,
- PointerActionType pointer_action_type,
- SyntheticPointer* synthetic_pointer,
- gfx::PointF position,
- int index)
- : gesture_source_type_(gesture_source_type),
- pointer_action_type_(pointer_action_type),
- position_(position),
- index_(index),
- synthetic_pointer_(synthetic_pointer) {}
+ const SyntheticPointerActionParams& params)
+ : params_(params) {}
+
+SyntheticPointerAction::SyntheticPointerAction(
+ const SyntheticPointerActionParams& params,
+ SyntheticPointer* synthetic_pointer)
+ : params_(params), synthetic_pointer_(synthetic_pointer) {}
SyntheticPointerAction::~SyntheticPointerAction() {}
SyntheticGesture::Result SyntheticPointerAction::ForwardInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
- if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT)
- gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
+ if (params_.gesture_source_type == SyntheticGestureParams::DEFAULT_INPUT)
+ params_.gesture_source_type =
+ target->GetDefaultSyntheticGestureSourceType();
- DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
+ DCHECK_NE(params_.gesture_source_type, SyntheticGestureParams::DEFAULT_INPUT);
ForwardTouchOrMouseInputEvents(timestamp, target);
return SyntheticGesture::GESTURE_FINISHED;
@@ -39,17 +37,20 @@ SyntheticGesture::Result SyntheticPointerAction::ForwardInputEvents(
void SyntheticPointerAction::ForwardTouchOrMouseInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
- switch (pointer_action_type_) {
- case SyntheticGesture::PRESS:
- synthetic_pointer_->Press(position_.x(), position_.y(), target,
- timestamp);
+ switch (params_.pointer_action_type()) {
+ case SyntheticPointerActionParams::PointerActionType::PRESS:
+ synthetic_pointer_->Press(params_.position().x(), params_.position().y(),
+ target, timestamp);
+ break;
+ case SyntheticPointerActionParams::PointerActionType::MOVE:
+ synthetic_pointer_->Move(params_.index(), params_.position().x(),
+ params_.position().y(), target, timestamp);
break;
- case SyntheticGesture::MOVE:
- synthetic_pointer_->Move(index_, position_.x(), position_.y(), target,
- timestamp);
+ case SyntheticPointerActionParams::PointerActionType::RELEASE:
+ synthetic_pointer_->Release(params_.index(), target, timestamp);
break;
- case SyntheticGesture::RELEASE:
- synthetic_pointer_->Release(index_, target, timestamp);
+ default:
+ NOTREACHED();
break;
}
synthetic_pointer_->DispatchEvent(target, timestamp);
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.h b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.h
index d1907764c8a..23b23fa421b 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.h
@@ -10,17 +10,15 @@
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_pointer.h"
#include "content/common/content_export.h"
+#include "content/common/input/synthetic_pointer_action_params.h"
namespace content {
class CONTENT_EXPORT SyntheticPointerAction : public SyntheticGesture {
public:
- SyntheticPointerAction(
- SyntheticGestureParams::GestureSourceType gesture_source_type,
- PointerActionType pointer_action_type,
- SyntheticPointer* synthetic_pointer,
- gfx::PointF position,
- int index = 0);
+ explicit SyntheticPointerAction(const SyntheticPointerActionParams& params);
+ SyntheticPointerAction(const SyntheticPointerActionParams& params,
+ SyntheticPointer* synthetic_pointer);
~SyntheticPointerAction() override;
SyntheticGesture::Result ForwardInputEvents(
@@ -31,10 +29,7 @@ class CONTENT_EXPORT SyntheticPointerAction : public SyntheticGesture {
SyntheticGestureTarget* target);
private:
- SyntheticGestureParams::GestureSourceType gesture_source_type_;
- PointerActionType pointer_action_type_;
- gfx::PointF position_;
- int index_;
+ SyntheticPointerActionParams params_;
SyntheticPointer* synthetic_pointer_;
DISALLOW_COPY_AND_ASSIGN(SyntheticPointerAction);
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
index 3ddb0a34caf..6a9264d2f66 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
@@ -42,6 +42,9 @@ SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams()
prevent_fling(true),
add_slop(true) {}
+SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams(
+ const SyntheticSmoothMoveGestureParams& other) = default;
+
SyntheticSmoothMoveGestureParams::~SyntheticSmoothMoveGestureParams() {}
SyntheticSmoothMoveGesture::SyntheticSmoothMoveGesture(
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
index 577a8c03e81..28be20eb50f 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
@@ -24,6 +24,8 @@ namespace content {
class CONTENT_EXPORT SyntheticSmoothMoveGestureParams {
public:
SyntheticSmoothMoveGestureParams();
+ SyntheticSmoothMoveGestureParams(
+ const SyntheticSmoothMoveGestureParams& other);
~SyntheticSmoothMoveGestureParams();
enum InputType { MOUSE_DRAG_INPUT, MOUSE_WHEEL_INPUT, TOUCH_INPUT };
diff --git a/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc b/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
index 72c8bc99086..a1a9e8378e1 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -94,7 +94,7 @@ class TouchActionBrowserTest : public ContentBrowserTest {
RenderWidgetHostImpl* host = GetWidgetHost();
scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher());
- host->GetProcess()->AddFilter(frame_watcher.get());
+ frame_watcher->AttachTo(shell()->web_contents());
host->GetView()->SetSize(gfx::Size(400, 400));
base::string16 ready_title(base::ASCIIToUTF16("ready"));
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.cc b/chromium/content/browser/renderer_host/input/touch_emulator.cc
index af8e6031918..1417c637d6e 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.cc
@@ -250,7 +250,7 @@ void TouchEmulator::HandleEmulatedTouchEvent(blink::WebTouchEvent event) {
if (is_sequence_start)
emulated_stream_active_sequence_count_++;
- event.causesScrollingIfUncanceled = result.did_generate_scroll;
+ event.movedBeyondSlopRegion = result.moved_beyond_slop_region;
client_->ForwardEmulatedTouchEvent(event);
}
@@ -449,6 +449,7 @@ void TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
point.screenPosition.y = mouse_event.globalY;
point.tiltX = 0;
point.tiltY = 0;
+ point.pointerType = blink::WebPointerProperties::PointerType::Touch;
}
bool TouchEmulator::InPinchGestureMode() const {
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.h b/chromium/content/browser/renderer_host/input/touch_emulator.h
index d02494547a6..c4fd18f74b4 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.h
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.h
@@ -30,7 +30,7 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
// Note that TouchEmulator should always listen to touch events and their acks
// (even in disabled state) to track native stream presence.
- bool enabled() const { return gesture_provider_; }
+ bool enabled() const { return !!gesture_provider_; }
// Returns |true| if the event was consumed. Consumed event should not
// propagate any further.
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc b/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
index 0062a2f6b52..04cb8191960 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -62,8 +62,11 @@ class TouchEmulatorTest : public testing::Test,
EXPECT_EQ(1U, event.touchesLength);
EXPECT_EQ(last_mouse_x_, event.touches[0].position.x);
EXPECT_EQ(last_mouse_y_, event.touches[0].position.y);
- bool expected_cancelable = event.type != WebInputEvent::TouchCancel;
- EXPECT_EQ(expected_cancelable, !!event.cancelable);
+ WebInputEvent::DispatchType expected_dispatch_type =
+ event.type == WebInputEvent::TouchCancel
+ ? WebInputEvent::EventNonBlocking
+ : WebInputEvent::Blocking;
+ EXPECT_EQ(expected_dispatch_type, event.dispatchType);
if (ack_touches_synchronously_) {
emulator()->HandleTouchEventAck(
event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
diff --git a/chromium/content/browser/renderer_host/input/touch_event_queue.cc b/chromium/content/browser/renderer_host/input/touch_event_queue.cc
index 550b46bfc47..9f6e3b2f6be 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.cc
@@ -46,8 +46,7 @@ TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent(
bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
return (event.type == WebInputEvent::TouchStart ||
event.type == WebInputEvent::TouchMove) &&
- WebInputEventTraits::WillReceiveAckFromRenderer(event) &&
- event.cancelable;
+ event.dispatchType == WebInputEvent::Blocking;
}
// Compare all properties of touch points to determine the state.
@@ -310,7 +309,7 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
if (suppressing_touchmoves_) {
if (event.touchesLength > 1) {
suppressing_touchmoves_ = false;
- } else if (event.causesScrollingIfUncanceled) {
+ } else if (event.movedBeyondSlopRegion) {
suppressing_touchmoves_ = false;
} else {
// No sane slop region should be larger than 60 DIPs.
@@ -467,6 +466,7 @@ void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) {
// yields identical results, but this avoids unnecessary allocations.
PreFilterResult filter_result = FilterBeforeForwarding(event.event);
if (filter_result != FORWARD_TO_RENDERER) {
+ client_->OnFilteringTouchEvent(event.event);
client_->OnTouchEventAck(event,
filter_result == ACK_WITH_NO_CONSUMER_EXISTS
? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
@@ -537,8 +537,10 @@ void TouchEventQueue::TryForwardNextEventToRenderer() {
// If there are queued touch events, then try to forward them to the renderer
// immediately, or ACK the events back to the client if appropriate.
while (!touch_queue_.empty()) {
- PreFilterResult filter_result =
- FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event);
+ const WebTouchEvent& event = touch_queue_.front()->coalesced_event().event;
+ PreFilterResult filter_result = FilterBeforeForwarding(event);
+ if (filter_result != FORWARD_TO_RENDERER)
+ client_->OnFilteringTouchEvent(event);
switch (filter_result) {
case ACK_WITH_NO_CONSUMER_EXISTS:
PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
@@ -601,7 +603,9 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
if (pending_async_touchmove_) {
if (pending_async_touchmove_->CanCoalesceWith(touch)) {
pending_async_touchmove_->CoalesceWith(touch);
- pending_async_touchmove_->event.cancelable = !send_touch_events_async_;
+ pending_async_touchmove_->event.dispatchType =
+ send_touch_events_async_ ? WebInputEvent::EventNonBlocking
+ : WebInputEvent::Blocking;
touch = *pending_async_touchmove_;
pending_async_touchmove_.reset();
} else {
@@ -614,7 +618,7 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
// platform scrolling and JS pinching. Touchend events, however, remain
// uncancelable, mitigating the risk of jank when transitioning to a fling.
if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart)
- touch.event.cancelable = false;
+ touch.event.dispatchType = WebInputEvent::EventNonBlocking;
SendTouchEventImmediately(&touch);
}
@@ -623,7 +627,7 @@ void TouchEventQueue::FlushPendingAsyncTouchmove() {
DCHECK(!dispatching_touch_);
scoped_ptr<TouchEventWithLatencyInfo> touch =
std::move(pending_async_touchmove_);
- touch->event.cancelable = false;
+ touch->event.dispatchType = WebInputEvent::EventNonBlocking;
touch_queue_.push_front(new CoalescedWebTouchEvent(*touch, true));
SendTouchEventImmediately(touch.get());
}
@@ -695,7 +699,7 @@ bool TouchEventQueue::IsAckTimeoutEnabled() const {
}
bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
- return pending_async_touchmove_;
+ return !!pending_async_touchmove_;
}
bool TouchEventQueue::IsTimeoutRunningForTesting() const {
@@ -783,7 +787,7 @@ void TouchEventQueue::SendTouchEventImmediately(
// timeout should not be started and the count also should not be increased.
if (dispatching_touch_) {
if (touch->event.type == WebInputEvent::TouchMove &&
- !touch->event.cancelable) {
+ touch->event.dispatchType != WebInputEvent::Blocking) {
// When we send out a uncancelable touch move, we increase the count and
// we do not process input event ack any more, we will just ack to client
// and wait for the ack from render. Also we will remove it from the front
diff --git a/chromium/content/browser/renderer_host/input/touch_event_queue.h b/chromium/content/browser/renderer_host/input/touch_event_queue.h
index 4b69d98bbcc..8a19586c618 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.h
@@ -35,6 +35,9 @@ class CONTENT_EXPORT TouchEventQueueClient {
virtual void OnTouchEventAck(
const TouchEventWithLatencyInfo& event,
InputEventAckState ack_result) = 0;
+
+ virtual void OnFilteringTouchEvent(
+ const blink::WebTouchEvent& touch_event) = 0;
};
// A queue for throttling and coalescing touch-events.
diff --git a/chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc
index f1091d48172..f2362b2bb18 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -84,6 +84,9 @@ class TouchEventQueueTest : public testing::Test,
}
}
+ void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override {
+ }
+
protected:
void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
slop_length_dips_ = slop_length_dips;
@@ -105,17 +108,16 @@ class TouchEventQueueTest : public testing::Test,
void SendTouchEvent(WebTouchEvent event) {
if (slop_length_dips_) {
- event.causesScrollingIfUncanceled = false;
+ event.movedBeyondSlopRegion = false;
if (WebTouchEventTraits::IsTouchSequenceStart(event))
anchor_ = event.touches[0].position;
if (event.type == WebInputEvent::TouchMove) {
gfx::Vector2dF delta = anchor_ - event.touches[0].position;
if (delta.LengthSquared() > slop_length_dips_ * slop_length_dips_)
- event.causesScrollingIfUncanceled = true;
+ event.movedBeyondSlopRegion = true;
}
} else {
- event.causesScrollingIfUncanceled =
- event.type == WebInputEvent::TouchMove;
+ event.movedBeyondSlopRegion = event.type == WebInputEvent::TouchMove;
}
queue_->QueueEvent(TouchEventWithLatencyInfo(event, ui::LatencyInfo()));
}
@@ -190,7 +192,7 @@ class TouchEventQueueTest : public testing::Test,
point.radiusX = radius_x;
point.radiusY = radius_y;
touch_event_.touches[index].state = WebTouchPoint::StateMoved;
- touch_event_.causesScrollingIfUncanceled = true;
+ touch_event_.movedBeyondSlopRegion = true;
WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
touch_event_.timeStampSeconds,
&touch_event_);
@@ -203,7 +205,7 @@ class TouchEventQueueTest : public testing::Test,
WebTouchPoint& point = touch_event_.touches[index];
point.rotationAngle = rotation_angle;
touch_event_.touches[index].state = WebTouchPoint::StateMoved;
- touch_event_.causesScrollingIfUncanceled = true;
+ touch_event_.movedBeyondSlopRegion = true;
WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
touch_event_.timeStampSeconds,
&touch_event_);
@@ -216,7 +218,7 @@ class TouchEventQueueTest : public testing::Test,
WebTouchPoint& point = touch_event_.touches[index];
point.force = force;
touch_event_.touches[index].state = WebTouchPoint::StateMoved;
- touch_event_.causesScrollingIfUncanceled = true;
+ touch_event_.movedBeyondSlopRegion = true;
WebTouchEventTraits::ResetType(WebInputEvent::TouchMove,
touch_event_.timeStampSeconds,
&touch_event_);
@@ -354,7 +356,7 @@ TEST_F(TouchEventQueueTest, Basic) {
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type);
- EXPECT_TRUE(acked_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, acked_event().dispatchType);
// Receive an ACK for the second touch-event.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
@@ -362,7 +364,7 @@ TEST_F(TouchEventQueueTest, Basic) {
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type);
- EXPECT_TRUE(acked_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, acked_event().dispatchType);
}
// Tests that touch-events with multiple points are queued properly.
@@ -1070,7 +1072,7 @@ TEST_F(TouchEventQueueTest, TouchTimeoutBasic) {
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(IsTimeoutRunning());
EXPECT_EQ(WebInputEvent::TouchCancel, sent_event().type);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1092,7 +1094,7 @@ TEST_F(TouchEventQueueTest, TouchTimeoutBasic) {
// Subsequent events should be handled normally.
PressTouchPoint(0, 1);
EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
@@ -1608,7 +1610,7 @@ TEST_F(TouchEventQueueTest, AsyncTouch) {
MoveTouchPoint(0, 10, 5+i);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1668,9 +1670,9 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_EQ(WebInputEvent::TouchMove, all_sent_events()[0].type);
- EXPECT_FALSE(all_sent_events()[0].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[0].dispatchType);
EXPECT_EQ(WebInputEvent::TouchEnd, all_sent_events()[1].type);
- EXPECT_FALSE(all_sent_events()[1].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[1].dispatchType);
EXPECT_EQ(2U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, queued_event_count());
@@ -1730,7 +1732,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
MoveTouchPoint(0, 0, 15);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
@@ -1747,9 +1749,9 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_EQ(WebInputEvent::TouchMove, all_sent_events()[0].type);
- EXPECT_FALSE(all_sent_events()[0].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[0].dispatchType);
EXPECT_EQ(WebInputEvent::TouchStart, all_sent_events()[1].type);
- EXPECT_TRUE(all_sent_events()[1].cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, all_sent_events()[1].dispatchType);
EXPECT_EQ(2U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, queued_event_count());
@@ -1775,7 +1777,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
// The pending touchmove should be coalesced with the next (now synchronous)
// touchmove.
MoveTouchPoint(0, 0, 26);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
EXPECT_EQ(WebTouchPoint::StateMoved, sent_event().touches[0].state);
@@ -1791,14 +1793,14 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
ReleaseTouchPoint(0);
EXPECT_EQ(3U, queued_event_count());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(WebInputEvent::TouchEnd, sent_event().type);
EXPECT_EQ(2U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(WebInputEvent::TouchEnd, sent_event().type);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1854,11 +1856,11 @@ TEST_F(TouchEventQueueTest, AsyncTouchFlushedByTouchEnd) {
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_EQ(WebInputEvent::TouchMove, all_sent_events()[0].type);
- EXPECT_FALSE(all_sent_events()[0].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[0].dispatchType);
EXPECT_EQ(0, all_sent_events()[0].touches[0].position.x);
EXPECT_EQ(0, all_sent_events()[0].touches[0].position.y);
EXPECT_EQ(WebInputEvent::TouchEnd, all_sent_events()[1].type);
- EXPECT_FALSE(all_sent_events()[1].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[1].dispatchType);
EXPECT_EQ(2U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
@@ -1900,7 +1902,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
MoveTouchPoint(0, 5, 5);
EXPECT_FALSE(IsTimeoutRunning());
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1910,7 +1912,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
MoveTouchPoint(0, 20, 5);
EXPECT_TRUE(IsTimeoutRunning());
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetSentEventCount());
// The timeout should fire, disabling touch forwarding until both acks are
@@ -1923,7 +1925,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
// Ack'ing the original event should trigger a cancel event.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1976,9 +1978,9 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_EQ(WebInputEvent::TouchMove, all_sent_events()[0].type);
- EXPECT_FALSE(all_sent_events()[0].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[0].dispatchType);
EXPECT_EQ(WebInputEvent::TouchCancel, all_sent_events()[1].type);
- EXPECT_FALSE(all_sent_events()[1].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[1].dispatchType);
EXPECT_EQ(2U, GetAndResetSentEventCount());
// Sending the ack is because the async touchmove is not ready for
// dispatching send the ack immediately.
@@ -2064,7 +2066,7 @@ TEST_F(TouchEventQueueTest, SendNextThrottledAsyncTouchMoveAfterAck) {
// Dispatch the touch move event when sufficient time has passed.
MoveTouchPoint(0, 0, 40);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
// When we dispatch an async touchmove, we do not put it back to the queue
// any more and we will ack to client right away.
EXPECT_EQ(0U, queued_event_count());
@@ -2124,7 +2126,7 @@ TEST_F(TouchEventQueueTest, SendNextAsyncTouchMoveAfterAckAndTimeExpire) {
AdvanceTouchTime(kMinSecondsBetweenThrottledTouchmoves + 0.1);
MoveTouchPoint(0, 0, 40);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
// When we dispatch an async touchmove, we do not put it back to the queue
// any more and we will ack to client right away.
EXPECT_EQ(0U, queued_event_count());
@@ -2147,7 +2149,7 @@ TEST_F(TouchEventQueueTest, SendNextAsyncTouchMoveAfterAckAndTimeExpire) {
MoveTouchPoint(0, 0, 50);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
@@ -2182,7 +2184,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchFlushedByNonTouchMove) {
AdvanceTouchTime(kMinSecondsBetweenThrottledTouchmoves + 0.1);
MoveTouchPoint(0, 0, 40);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
// When we dispatch an async touchmove, we do not put it back to the queue
// any more and we will ack to client right away.
EXPECT_EQ(0U, queued_event_count());
@@ -2208,13 +2210,13 @@ TEST_F(TouchEventQueueTest, AsyncTouchFlushedByNonTouchMove) {
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_EQ(WebInputEvent::TouchMove, all_sent_events()[0].type);
- EXPECT_FALSE(all_sent_events()[0].cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, all_sent_events()[0].dispatchType);
EXPECT_EQ(10 + 10 * i, all_sent_events()[0].touches[0].position.x);
EXPECT_EQ(10 + 10 * i, all_sent_events()[0].touches[0].position.y);
EXPECT_EQ(static_cast<size_t>(i + 2),
uncancelable_touch_moves_pending_ack_count());
EXPECT_EQ(WebInputEvent::TouchStart, all_sent_events()[1].type);
- EXPECT_TRUE(all_sent_events()[1].cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, all_sent_events()[1].dispatchType);
EXPECT_EQ(2U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
@@ -2260,7 +2262,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchFlushedByNonTouchMove) {
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
@@ -2296,7 +2298,7 @@ TEST_F(TouchEventQueueTest, DoNotIncreaseIfClientConsumeAsyncTouchMove) {
AdvanceTouchTime(kMinSecondsBetweenThrottledTouchmoves + 0.1);
MoveTouchPoint(0, 0, 40);
EXPECT_FALSE(HasPendingAsyncTouchMove());
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
// When we dispatch an async touchmove, we do not put it back to the queue
// any more and we will ack to client right away.
EXPECT_EQ(0U, queued_event_count());
@@ -2322,7 +2324,7 @@ TEST_F(TouchEventQueueTest, DoNotIncreaseIfClientConsumeAsyncTouchMove) {
MoveTouchPoint(0, 0, 50);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
@@ -2347,7 +2349,7 @@ TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
MoveTouchPoint(0, 60, 5);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetSentEventCount());
MoveTouchPoint(0, 20, 5);
@@ -2358,7 +2360,7 @@ TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Touch move event is throttled.
@@ -2372,39 +2374,39 @@ TEST_F(TouchEventQueueTest, TouchStartCancelableDuringScroll) {
// active scroll sequence.
PressTouchPoint(0, 1);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
MoveTouchPoint(0, 20, 5);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
SendGestureEvent(blink::WebInputEvent::GestureScrollBegin);
SendGestureEvent(blink::WebInputEvent::GestureScrollUpdate);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
// Even though scrolling has begun, touchstart events should be cancelable,
// allowing, for example, customized pinch processing.
PressTouchPoint(10, 11);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
// As the touch start was consumed, touchmoves should no longer be throttled.
MoveTouchPoint(1, 11, 11);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
// With throttling disabled, touchend and touchmove events should also be
// cancelable.
MoveTouchPoint(1, 12, 12);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ReleaseTouchPoint(1);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
// If subsequent touchmoves aren't consumed, the generated scroll events
@@ -2412,17 +2414,17 @@ TEST_F(TouchEventQueueTest, TouchStartCancelableDuringScroll) {
MoveTouchPoint(0, 25, 5);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
SendGestureEvent(blink::WebInputEvent::GestureScrollUpdate);
- EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
AdvanceTouchTime(kMinSecondsBetweenThrottledTouchmoves + 0.1);
MoveTouchPoint(0, 30, 5);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
// The touchend will be uncancelable during an active scroll sequence.
ReleaseTouchPoint(0);
- EXPECT_FALSE(sent_event().cancelable);
+ EXPECT_NE(WebInputEvent::Blocking, sent_event().dispatchType);
ASSERT_EQ(1U, GetAndResetSentEventCount());
}
diff --git a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
index 2c68ac71ac2..7ff1dd06701 100644
--- a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -19,6 +19,7 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.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 "content/shell/browser/shell.h"
@@ -88,54 +89,6 @@ const char kTouchEventDataURL[] =
namespace content {
-class InputEventMessageFilter : public BrowserMessageFilter {
- public:
- InputEventMessageFilter()
- : BrowserMessageFilter(InputMsgStart),
- type_(WebInputEvent::Undefined),
- state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
-
- void WaitForAck(WebInputEvent::Type type) {
- base::RunLoop run_loop;
- base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
- base::AutoReset<WebInputEvent::Type> reset_type(&type_, type);
- run_loop.Run();
- }
-
- InputEventAckState last_ack_state() const { return state_; }
-
- protected:
- ~InputEventMessageFilter() override {}
-
- private:
- void ReceivedEventAck(WebInputEvent::Type type, InputEventAckState state) {
- if (type_ == type) {
- state_ = state;
- quit_.Run();
- }
- }
-
- // BrowserMessageFilter:
- bool OnMessageReceived(const IPC::Message& message) override {
- if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) {
- InputHostMsg_HandleInputEvent_ACK::Param params;
- InputHostMsg_HandleInputEvent_ACK::Read(&message, &params);
- WebInputEvent::Type type = base::get<0>(params).type;
- InputEventAckState ack = base::get<0>(params).state;
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&InputEventMessageFilter::ReceivedEventAck,
- this, type, ack));
- }
- return false;
- }
-
- base::Closure quit_;
- WebInputEvent::Type type_;
- InputEventAckState state_;
-
- DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilter);
-};
-
class TouchInputBrowserTest : public ContentBrowserTest {
public:
TouchInputBrowserTest() {}
@@ -146,33 +99,27 @@ class TouchInputBrowserTest : public ContentBrowserTest {
shell()->web_contents()->GetRenderViewHost()->GetWidget());
}
- InputEventMessageFilter* filter() { return filter_.get(); }
+ scoped_refptr<InputMsgWatcher> AddFilter(blink::WebInputEvent::Type type) {
+ return new InputMsgWatcher(GetWidgetHost(), type);
+ }
protected:
- void LoadURLAndAddFilter() {
+ void LoadURL() {
const GURL data_url(kTouchEventDataURL);
NavigateToURL(shell(), data_url);
- WebContentsImpl* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
- web_contents->GetRenderViewHost()->GetWidget());
+ RenderWidgetHostImpl* host = GetWidgetHost();
host->GetView()->SetSize(gfx::Size(400, 400));
// The page is loaded in the renderer, wait for a new frame to arrive.
while (!host->ScheduleComposite())
GiveItSomeTime();
-
- filter_ = new InputEventMessageFilter();
- host->GetProcess()->AddFilter(filter_.get());
}
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
}
-
- scoped_refptr<InputEventMessageFilter> filter_;
};
#if defined(OS_MACOSX)
@@ -182,17 +129,16 @@ class TouchInputBrowserTest : public ContentBrowserTest {
#define MAYBE_TouchNoHandler TouchNoHandler
#endif
IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
- LoadURLAndAddFilter();
+ LoadURL();
SyntheticWebTouchEvent touch;
// A press on |first| should be acked with NO_CONSUMER_EXISTS since there is
// no touch-handler on it.
touch.PressPoint(25, 25);
+ scoped_refptr<InputMsgWatcher> filter = AddFilter(WebInputEvent::TouchStart);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchStart);
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
- filter()->last_ack_state());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, filter->WaitForAck());
// If a touch-press is acked with NO_CONSUMER_EXISTS, then subsequent
// touch-points don't need to be dispatched until the touch point is released.
@@ -208,20 +154,21 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
#define MAYBE_TouchHandlerNoConsume TouchHandlerNoConsume
#endif
IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerNoConsume) {
- LoadURLAndAddFilter();
+ LoadURL();
SyntheticWebTouchEvent touch;
// Press on |second| should be acked with NOT_CONSUMED since there is a
// touch-handler on |second|, but it doesn't consume the event.
touch.PressPoint(125, 25);
+ scoped_refptr<InputMsgWatcher> filter = AddFilter(WebInputEvent::TouchStart);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchStart);
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter->WaitForAck());
+ filter = AddFilter(WebInputEvent::TouchEnd);
touch.ReleasePoint(0);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchEnd);
touch.ResetPoints();
+ filter->WaitForAck();
}
#if defined(OS_CHROMEOS)
@@ -231,19 +178,20 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerNoConsume) {
#define MAYBE_TouchHandlerConsume TouchHandlerConsume
#endif
IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerConsume) {
- LoadURLAndAddFilter();
+ LoadURL();
SyntheticWebTouchEvent touch;
// Press on |third| should be acked with CONSUMED since the touch-handler on
// |third| consimes the event.
touch.PressPoint(25, 125);
+ scoped_refptr<InputMsgWatcher> filter = AddFilter(WebInputEvent::TouchStart);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchStart);
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter()->last_ack_state());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter->WaitForAck());
touch.ReleasePoint(0);
+ filter = AddFilter(WebInputEvent::TouchEnd);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchEnd);
+ filter->WaitForAck();
}
#if defined(OS_CHROMEOS)
@@ -256,21 +204,20 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerConsume) {
#define MAYBE_MultiPointTouchPress MultiPointTouchPress
#endif
IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_MultiPointTouchPress) {
- LoadURLAndAddFilter();
+ LoadURL();
SyntheticWebTouchEvent touch;
// Press on |first|, which sould be acked with NO_CONSUMER_EXISTS. Then press
// on |third|. That point should be acked with CONSUMED.
touch.PressPoint(25, 25);
+ scoped_refptr<InputMsgWatcher> filter = AddFilter(WebInputEvent::TouchStart);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchStart);
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
- filter()->last_ack_state());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, filter->WaitForAck());
touch.PressPoint(25, 125);
+ filter = AddFilter(WebInputEvent::TouchStart);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
- filter()->WaitForAck(WebInputEvent::TouchStart);
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter()->last_ack_state());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, filter->WaitForAck());
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
index b59cc2bd010..348b5e6fea0 100644
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
+#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/run_loop.h"
@@ -17,6 +18,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
+#include "ui/gfx/switches.h"
#include "ui/touch_selection/touch_selection_controller_test_api.h"
namespace content {
@@ -153,6 +155,23 @@ class TouchSelectionControllerClientAuraTest : public ContentBrowserTest {
"empty_textfield()");
}
+ RenderWidgetHostViewAura* GetRenderWidgetHostViewAura() {
+ return static_cast<RenderWidgetHostViewAura*>(
+ shell()->web_contents()->GetRenderWidgetHostView());
+ }
+
+ TestTouchSelectionControllerClientAura* selection_controller_client() {
+ return selection_controller_client_;
+ }
+
+ void InitSelectionController() {
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
+ selection_controller_client_ =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client_));
+ }
+
private:
void SetUpOnMainThread() override {
ContentBrowserTest::SetUpOnMainThread();
@@ -162,11 +181,15 @@ class TouchSelectionControllerClientAuraTest : public ContentBrowserTest {
void TearDownOnMainThread() override {
menu_runner_ = nullptr;
+ selection_controller_client_ = nullptr;
ContentBrowserTest::TearDownOnMainThread();
}
scoped_ptr<TestTouchSelectionMenuRunner> menu_runner_;
+ TestTouchSelectionControllerClientAura* selection_controller_client_ =
+ nullptr;
+
DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientAuraTest);
};
@@ -175,21 +198,15 @@ class TouchSelectionControllerClientAuraTest : public ContentBrowserTest {
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicSelection) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
// Long-press on the text and wait for handles to appear.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
gfx::PointF point;
@@ -199,7 +216,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicSelection) {
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
rwhva->OnGestureEvent(&long_press);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
// Check that selection is active and the quick menu is showing.
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
@@ -214,36 +231,29 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
BasicInsertionFollowedByTapsOnHandle) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
ui::test::EventGeneratorDelegate* generator_delegate =
ui::test::EventGenerator::default_delegate;
- ui::test::EventGenerator generator(
- web_contents->GetContentNativeView()->GetRootWindow());
+ gfx::NativeView native_view = rwhva->GetNativeView();
+ ui::test::EventGenerator generator(native_view->GetRootWindow());
// Tap inside the textfield and wait for the insertion handle to appear.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::INSERTION_HANDLE_SHOWN);
gfx::PointF point_f;
ASSERT_TRUE(GetPointInsideTextfield(&point_f));
gfx::Point point = gfx::ToRoundedPoint(point_f);
- generator_delegate->ConvertPointFromTarget(
- web_contents->GetContentNativeView(), &point);
+ generator_delegate->ConvertPointFromTarget(native_view, &point);
generator.GestureTapAt(point);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
// Check that insertion is active, but the quick menu is not showing.
EXPECT_EQ(ui::TouchSelectionController::INSERTION_ACTIVE,
@@ -253,8 +263,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
// Tap on the insertion handle; the quick menu should appear.
gfx::Point handle_center = gfx::ToRoundedPoint(
rwhva->selection_controller()->GetStartHandleRect().CenterPoint());
- generator_delegate->ConvertPointFromTarget(
- web_contents->GetContentNativeView(), &handle_center);
+ generator_delegate->ConvertPointFromTarget(native_view, &handle_center);
generator.GestureTapAt(handle_center);
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
@@ -269,14 +278,9 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
EmptyTextfieldInsertionOnTap) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
// Clear textfield contents.
ASSERT_TRUE(EmptyTextfield());
@@ -286,7 +290,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
// Tap inside the textfield and wait for the insertion cursor.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_ESTABLISHED);
gfx::PointF point;
@@ -297,7 +301,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
tap_details);
rwhva->OnGestureEvent(&tap);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
// Check that insertion is not active and the quick menu is not showing.
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
@@ -310,21 +314,15 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
QuickMenuHiddenOnTouch) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
// Long-press on the text and wait for selection handles to appear.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
gfx::PointF point;
@@ -334,15 +332,14 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
rwhva->OnGestureEvent(&long_press);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
- ui::test::EventGenerator generator(
- web_contents->GetContentNativeView()->GetRootWindow(),
- web_contents->GetContentNativeView());
+ ui::test::EventGenerator generator(rwhva->GetNativeView()->GetRootWindow(),
+ rwhva->GetNativeView());
// Put the first finger down: the quick menu should get hidden.
generator.PressTouchId(0);
@@ -373,14 +370,9 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
ui::TouchSelectionControllerTestApi selection_controller_test_api(
rwhva->selection_controller());
@@ -389,7 +381,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) {
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
// Long-press on the text and wait for selection handles to appear.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
gfx::PointF point;
@@ -399,7 +391,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) {
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
rwhva->OnGestureEvent(&long_press);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
rwhva->selection_controller()->active_status());
@@ -452,21 +444,15 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
HiddenAfterOverscroll) {
// Set the page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
- WebContents* web_contents =
- static_cast<WebContentsImpl*>(shell()->web_contents());
- RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
- web_contents->GetRenderWidgetHostView());
- TestTouchSelectionControllerClientAura* selection_controller_client =
- new TestTouchSelectionControllerClientAura(rwhva);
- rwhva->SetSelectionControllerClientForTest(
- make_scoped_ptr(selection_controller_client));
+ InitSelectionController();
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
// Long-press on the text and wait for touch handles to appear.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
gfx::PointF point;
@@ -476,7 +462,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
rwhva->OnGestureEvent(&long_press);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
rwhva->selection_controller()->active_status());
@@ -484,7 +470,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
// Scroll such that an overscroll is initiated and wait for it to complete:
// touch selection should not be active at the end.
- selection_controller_client->InitWaitForSelectionEvent(
+ selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_CLEARED);
ui::GestureEvent scroll_begin(
@@ -502,11 +488,182 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
rwhva->OnGestureEvent(&scroll_end);
- selection_controller_client->Wait();
+ selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
}
+class TouchSelectionControllerClientAuraScaleFactorTest
+ : public TouchSelectionControllerClientAuraTest {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
+ }
+};
+
+#if defined(OS_WIN)
+// High DPI tests are disabled on Windows due to crbug.com/545547.
+#define MAYBE_SelectionHandleCoordinates DISABLED_SelectionHandleCoordinates
+#define MAYBE_InsertionHandleCoordinates DISABLED_InsertionHandleCoordinates
+#else
+#define MAYBE_SelectionHandleCoordinates SelectionHandleCoordinates
+#define MAYBE_InsertionHandleCoordinates InsertionHandleCoordinates
+#endif
+
+// Tests that selection handles are properly positioned at 2x DSF.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
+ MAYBE_SelectionHandleCoordinates) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
+ InitSelectionController();
+
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+ EXPECT_EQ(2.f, rwhva->current_device_scale_factor());
+
+ // Long-press on the text and wait for handles to appear.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_SHOWN);
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideText(&point));
+ ui::GestureEvent long_press(
+ point.x(), point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ rwhva->OnGestureEvent(&long_press);
+ selection_controller_client()->Wait();
+
+ // Check that selection is active and the quick menu is showing.
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+ const ui::TouchSelectionController* controller =
+ GetRenderWidgetHostViewAura()->selection_controller();
+
+ gfx::PointF start_top = controller->start().edge_top();
+
+ // The selection start should be uppper left, and selection end should be
+ // upper right.
+ EXPECT_LT(controller->start().edge_top().x(), point.x());
+ EXPECT_LT(controller->start().edge_bottom().x(), point.x());
+
+ EXPECT_LT(point.x(), controller->end().edge_top().x());
+ EXPECT_LT(point.x(), controller->end().edge_bottom().x());
+
+ // Handles are created below the selection. The top position should roughly
+ // be within the handle size from the touch position.
+ float handle_size = controller->start().edge_bottom().y() -
+ controller->start().edge_top().y();
+ float handle_max_bottom = point.y() + handle_size;
+ EXPECT_GT(handle_max_bottom, controller->start().edge_top().y());
+ EXPECT_GT(handle_max_bottom, controller->end().edge_top().y());
+
+ gfx::Point handle_point = gfx::ToRoundedPoint(
+ rwhva->selection_controller()->GetStartHandleRect().CenterPoint());
+
+ // Move the selection handle. Touch the handle first.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLE_DRAG_STARTED);
+ ui::TouchEvent touch_down(ui::ET_TOUCH_PRESSED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_down);
+ selection_controller_client()->Wait();
+
+ // Move it.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_MOVED);
+ handle_point.Offset(10, 0);
+ ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_move);
+ selection_controller_client()->Wait();
+
+ // Then release.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLE_DRAG_STOPPED);
+ ui::TouchEvent touch_up(ui::ET_TOUCH_RELEASED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_up);
+ selection_controller_client()->Wait();
+
+ // The handle should have moved to right.
+ EXPECT_EQ(start_top.y(), controller->start().edge_top().y());
+ EXPECT_LT(start_top.x(), controller->start().edge_top().x());
+
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+}
+
+// Tests that insertion handles are properly positioned at 2x DSF.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraScaleFactorTest,
+ MAYBE_InsertionHandleCoordinates) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));
+ InitSelectionController();
+
+ RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
+
+ // Tap inside the textfield and wait for the insertion cursor.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::INSERTION_HANDLE_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideTextfield(&point));
+ ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
+ tap_details.set_tap_count(1);
+ ui::GestureEvent tap(point.x(), point.y(), 0, ui::EventTimeForNow(),
+ tap_details);
+ rwhva->OnGestureEvent(&tap);
+
+ selection_controller_client()->Wait();
+
+ EXPECT_EQ(ui::TouchSelectionController::INSERTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+
+ gfx::RectF initial_handle_rect =
+ rwhva->selection_controller()->GetStartHandleRect();
+
+ // Move the insertion handle. Touch the handle first.
+ gfx::Point handle_point =
+ gfx::ToRoundedPoint(initial_handle_rect.CenterPoint());
+
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::INSERTION_HANDLE_DRAG_STARTED);
+ ui::TouchEvent touch_down(ui::ET_TOUCH_PRESSED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_down);
+ selection_controller_client()->Wait();
+
+ // Move it.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::INSERTION_HANDLE_MOVED);
+ handle_point.Offset(10, 0);
+ ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_move);
+ selection_controller_client()->Wait();
+
+ // Then release.
+ selection_controller_client()->InitWaitForSelectionEvent(
+ ui::INSERTION_HANDLE_DRAG_STOPPED);
+ ui::TouchEvent touch_up(ui::ET_TOUCH_RELEASED, handle_point, 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_up);
+ selection_controller_client()->Wait();
+
+ gfx::RectF moved_handle_rect =
+ rwhva->selection_controller()->GetStartHandleRect();
+
+ // The handle should have moved to right.
+ EXPECT_EQ(initial_handle_rect.y(), moved_handle_rect.y());
+ EXPECT_LT(initial_handle_rect.x(), moved_handle_rect.x());
+
+ EXPECT_EQ(ui::TouchSelectionController::INSERTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc b/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
index 791422d38de..a5ffc019ad9 100644
--- a/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
+++ b/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.cc
@@ -45,7 +45,7 @@ bool TouchscreenTapSuppressionController::FilterTapEvent(
return true;
case WebInputEvent::GestureTapUnconfirmed:
- return stashed_tap_down_;
+ return !!stashed_tap_down_;
case WebInputEvent::GestureTapCancel:
case WebInputEvent::GestureTap:
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
index 3fb06bb9082..c0ffc1b0683 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
@@ -4,8 +4,11 @@
#include "content/browser/renderer_host/input/web_input_event_builders_android.h"
+#include <android/input.h>
+
#include "base/logging.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
+#include "ui/events/android/key_event_utils.h"
#include "ui/events/android/motion_event_android.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
@@ -18,6 +21,7 @@ using blink::WebKeyboardEvent;
using blink::WebGestureEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
+using blink::WebPointerProperties;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
@@ -25,7 +29,41 @@ namespace content {
namespace {
-ui::DomKey GetDomKeyFromEvent(int keycode, int unicode_character) {
+int WebInputEventToAndroidModifier(int web_modifier) {
+ int android_modifier = 0;
+ // Currently only Shift, CapsLock are used, add other modifiers if required.
+ if (web_modifier & WebInputEvent::ShiftKey)
+ android_modifier |= AMETA_SHIFT_ON;
+ if (web_modifier & WebInputEvent::CapsLockOn)
+ android_modifier |= AMETA_CAPS_LOCK_ON;
+ return android_modifier;
+}
+
+ui::DomKey GetDomKeyFromEvent(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& android_key_event,
+ int keycode,
+ int modifiers,
+ int unicode_character) {
+ // Synthetic key event, not enough information to get DomKey.
+ if (android_key_event.is_null() && !unicode_character)
+ return ui::DomKey::UNIDENTIFIED;
+
+ if (!unicode_character && env) {
+ // According to spec |kAllowedModifiers| should be Shift and AltGr, however
+ // Android doesn't have AltGr key and ImeAdapter::getModifiers won't pass it
+ // either.
+ // According to discussion we want to honor CapsLock and possibly NumLock as
+ // well. https://github.com/w3c/uievents/issues/70
+ const int kAllowedModifiers =
+ WebInputEvent::ShiftKey | WebInputEvent::CapsLockOn;
+ int fallback_modifiers =
+ WebInputEventToAndroidModifier(modifiers & kAllowedModifiers);
+
+ unicode_character = ui::events::android::GetKeyEventUnicodeChar(
+ env, android_key_event, fallback_modifiers);
+ }
+
ui::DomKey key = ui::GetDomKeyFromAndroidEvent(keycode, unicode_character);
if (key != ui::DomKey::NONE)
return key;
@@ -34,13 +72,16 @@ ui::DomKey GetDomKeyFromEvent(int keycode, int unicode_character) {
} // namespace
-WebKeyboardEvent WebKeyboardEventBuilder::Build(WebInputEvent::Type type,
- int modifiers,
- double time_sec,
- int keycode,
- int scancode,
- int unicode_character,
- bool is_system_key) {
+WebKeyboardEvent WebKeyboardEventBuilder::Build(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& android_key_event,
+ WebInputEvent::Type type,
+ int modifiers,
+ double time_sec,
+ int keycode,
+ int scancode,
+ int unicode_character,
+ bool is_system_key) {
DCHECK(WebInputEvent::isKeyboardEventType(type));
WebKeyboardEvent result;
@@ -55,7 +96,8 @@ WebKeyboardEvent WebKeyboardEventBuilder::Build(WebInputEvent::Type type,
result.modifiers |= DomCodeToWebInputEventModifiers(dom_code);
result.nativeKeyCode = keycode;
result.domCode = static_cast<int>(dom_code);
- result.domKey = GetDomKeyFromEvent(keycode, unicode_character);
+ result.domKey = GetDomKeyFromEvent(env, android_key_event, keycode, modifiers,
+ unicode_character);
result.unmodifiedText[0] = unicode_character;
if (result.windowsKeyCode == ui::VKEY_RETURN) {
// This is the same behavior as GTK:
@@ -70,17 +112,21 @@ WebKeyboardEvent WebKeyboardEventBuilder::Build(WebInputEvent::Type type,
return result;
}
-WebMouseEvent WebMouseEventBuilder::Build(blink::WebInputEvent::Type type,
- WebMouseEvent::Button button,
- double time_sec,
- int window_x,
- int window_y,
- int modifiers,
- int click_count) {
+WebMouseEvent WebMouseEventBuilder::Build(
+ WebInputEvent::Type type,
+ WebMouseEvent::Button button,
+ double time_sec,
+ int window_x,
+ int window_y,
+ int modifiers,
+ int click_count,
+ WebPointerProperties::PointerType pointer_type) {
+
DCHECK(WebInputEvent::isMouseEventType(type));
WebMouseEvent result;
result.type = type;
+ result.pointerType = pointer_type;
result.x = window_x;
result.y = window_y;
result.windowX = window_x;
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.h b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.h
index 5ade65a3cbf..b6bcf44c7e1 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.h
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.h
@@ -7,6 +7,8 @@
#include <jni.h>
+#include "base/android/scoped_java_ref.h"
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
namespace ui {
@@ -17,13 +19,15 @@ namespace content {
class WebMouseEventBuilder {
public:
- static blink::WebMouseEvent Build(blink::WebInputEvent::Type type,
- blink::WebMouseEvent::Button button,
- double time_sec,
- int window_x,
- int window_y,
- int modifiers,
- int click_count);
+ static blink::WebMouseEvent Build(
+ blink::WebInputEvent::Type type,
+ blink::WebMouseEvent::Button button,
+ double time_sec,
+ int window_x,
+ int window_y,
+ int modifiers,
+ int click_count,
+ blink::WebPointerProperties::PointerType pointer_type);
};
class WebMouseWheelEventBuilder {
@@ -36,15 +40,18 @@ class WebMouseWheelEventBuilder {
int window_y);
};
-class WebKeyboardEventBuilder {
+class CONTENT_EXPORT WebKeyboardEventBuilder {
public:
- static blink::WebKeyboardEvent Build(blink::WebInputEvent::Type type,
- int modifiers,
- double time_sec,
- int keycode,
- int scancode,
- int unicode_character,
- bool is_system_key);
+ static blink::WebKeyboardEvent Build(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& android_key_event,
+ blink::WebInputEvent::Type type,
+ int modifiers,
+ double time_sec,
+ int keycode,
+ int scancode,
+ int unicode_character,
+ bool is_system_key);
};
class WebGestureEventBuilder {
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc b/chromium/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc
new file mode 100644
index 00000000000..3e047d850ef
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc
@@ -0,0 +1,169 @@
+// 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 "content/browser/renderer_host/input/web_input_event_builders_android.h"
+
+#include <android/input.h>
+#include <android/keycodes.h>
+
+#include "base/android/jni_android.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/android/key_event_utils.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+using blink::WebKeyboardEvent;
+
+namespace {
+
+const int kCombiningAccent = 0x80000000;
+const int kCombiningAccentMask = 0x7fffffff;
+const int kCompositionKeyCode = 229;
+
+WebKeyboardEvent CreateFakeWebKeyboardEvent(JNIEnv* env,
+ int key_code,
+ int web_modifier,
+ int unicode_character) {
+ ScopedJavaLocalRef<jobject> keydown_event =
+ ui::events::android::CreateKeyEvent(env, ui::MotionEvent::ACTION_DOWN,
+ key_code);
+
+ WebKeyboardEvent web_event = content::WebKeyboardEventBuilder::Build(
+ env, keydown_event, WebKeyboardEvent::KeyDown, web_modifier, 0, key_code,
+ 0, unicode_character, false);
+ return web_event;
+}
+
+} // anonymous namespace
+
+class WebInputEventBuilderAndroidTest : public testing::Test {};
+
+// This test case is based on VirtualKeyboard layout.
+// https://github.com/android/platform_frameworks_base/blob/master/data/keyboards/Virtual.kcm
+TEST(WebInputEventBuilderAndroidTest, DomKeyCtrlShift) {
+ JNIEnv* env = AttachCurrentThread();
+
+ struct DomKeyTestCase {
+ int key_code;
+ int character;
+ int shift_character;
+ } table[] = {
+ {AKEYCODE_0, '0', ')'}, {AKEYCODE_1, '1', '!'}, {AKEYCODE_2, '2', '@'},
+ {AKEYCODE_3, '3', '#'}, {AKEYCODE_4, '4', '$'}, {AKEYCODE_5, '5', '%'},
+ {AKEYCODE_6, '6', '^'}, {AKEYCODE_7, '7', '&'}, {AKEYCODE_8, '8', '*'},
+ {AKEYCODE_9, '9', '('}, {AKEYCODE_A, 'a', 'A'}, {AKEYCODE_B, 'b', 'B'},
+ {AKEYCODE_C, 'c', 'C'}, {AKEYCODE_D, 'd', 'D'}, {AKEYCODE_E, 'e', 'E'},
+ {AKEYCODE_F, 'f', 'F'}, {AKEYCODE_G, 'g', 'G'}, {AKEYCODE_H, 'h', 'H'},
+ {AKEYCODE_I, 'i', 'I'}, {AKEYCODE_J, 'j', 'J'}, {AKEYCODE_K, 'k', 'K'},
+ {AKEYCODE_L, 'l', 'L'}, {AKEYCODE_M, 'm', 'M'}, {AKEYCODE_N, 'n', 'N'},
+ {AKEYCODE_O, 'o', 'O'}, {AKEYCODE_P, 'p', 'P'}, {AKEYCODE_Q, 'q', 'Q'},
+ {AKEYCODE_R, 'r', 'R'}, {AKEYCODE_S, 's', 'S'}, {AKEYCODE_T, 't', 'T'},
+ {AKEYCODE_U, 'u', 'U'}, {AKEYCODE_V, 'v', 'V'}, {AKEYCODE_W, 'w', 'W'},
+ {AKEYCODE_X, 'x', 'X'}, {AKEYCODE_Y, 'y', 'Y'}, {AKEYCODE_Z, 'z', 'Z'}};
+
+ for (const DomKeyTestCase& entry : table) {
+ // Tests DomKey without modifier.
+ WebKeyboardEvent web_event =
+ CreateFakeWebKeyboardEvent(env, entry.key_code, 0, entry.character);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey)
+ << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey);
+
+ // Tests DomKey with Ctrl.
+ web_event = CreateFakeWebKeyboardEvent(env, entry.key_code,
+ WebKeyboardEvent::ControlKey, 0);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey)
+ << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey);
+
+ // Tests DomKey with Ctrl and Shift.
+ web_event = CreateFakeWebKeyboardEvent(
+ env, entry.key_code,
+ WebKeyboardEvent::ControlKey | WebKeyboardEvent::ShiftKey, 0);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.shift_character),
+ web_event.domKey)
+ << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey);
+ }
+}
+
+// This test case is based on VirtualKeyboard layout.
+// https://github.com/android/platform_frameworks_base/blob/master/data/keyboards/Virtual.kcm
+TEST(WebInputEventBuilderAndroidTest, DomKeyCtrlAlt) {
+ JNIEnv* env = AttachCurrentThread();
+
+ struct DomKeyTestCase {
+ int key_code;
+ int character;
+ int alt_character;
+ } table[] = {{AKEYCODE_0, '0', 0}, {AKEYCODE_1, '1', 0},
+ {AKEYCODE_2, '2', 0}, {AKEYCODE_3, '3', 0},
+ {AKEYCODE_4, '4', 0}, {AKEYCODE_5, '5', 0},
+ {AKEYCODE_6, '6', 0}, {AKEYCODE_7, '7', 0},
+ {AKEYCODE_8, '8', 0}, {AKEYCODE_9, '9', 0},
+ {AKEYCODE_A, 'a', 0}, {AKEYCODE_B, 'b', 0},
+ {AKEYCODE_C, 'c', u'\u00e7'}, {AKEYCODE_D, 'd', 0},
+ {AKEYCODE_E, 'e', u'\u0301'}, {AKEYCODE_F, 'f', 0},
+ {AKEYCODE_G, 'g', 0}, {AKEYCODE_H, 'h', 0},
+ {AKEYCODE_I, 'i', u'\u0302'}, {AKEYCODE_J, 'j', 0},
+ {AKEYCODE_K, 'k', 0}, {AKEYCODE_L, 'l', 0},
+ {AKEYCODE_M, 'm', 0}, {AKEYCODE_N, 'n', u'\u0303'},
+ {AKEYCODE_O, 'o', 0}, {AKEYCODE_P, 'p', 0},
+ {AKEYCODE_Q, 'q', 0}, {AKEYCODE_R, 'r', 0},
+ {AKEYCODE_S, 's', u'\u00df'}, {AKEYCODE_T, 't', 0},
+ {AKEYCODE_U, 'u', u'\u0308'}, {AKEYCODE_V, 'v', 0},
+ {AKEYCODE_W, 'w', 0}, {AKEYCODE_X, 'x', 0},
+ {AKEYCODE_Y, 'y', 0}, {AKEYCODE_Z, 'z', 0}};
+
+ for (const DomKeyTestCase& entry : table) {
+ // Tests DomKey with Alt.
+ WebKeyboardEvent web_event = CreateFakeWebKeyboardEvent(
+ env, entry.key_code, WebKeyboardEvent::AltKey, entry.alt_character);
+ ui::DomKey expected_alt_dom_key;
+ if (entry.alt_character == 0)
+ expected_alt_dom_key = ui::DomKey::FromCharacter(entry.character);
+ else if (entry.alt_character & kCombiningAccent)
+ expected_alt_dom_key = ui::DomKey::DeadKeyFromCombiningCharacter(
+ entry.alt_character & kCombiningAccentMask);
+ else
+ expected_alt_dom_key = ui::DomKey::FromCharacter(entry.alt_character);
+ EXPECT_EQ(expected_alt_dom_key, web_event.domKey)
+ << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey);
+
+ // Tests DomKey with Ctrl and Alt.
+ web_event = CreateFakeWebKeyboardEvent(
+ env, entry.key_code,
+ WebKeyboardEvent::ControlKey | WebKeyboardEvent::AltKey, 0);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey)
+ << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey);
+ }
+}
+
+// Testing AKEYCODE_LAST_CHANNEL because it's overlapping with
+// COMPOSITION_KEY_CODE (both 229).
+TEST(WebInputEventBuilderAndroidTest, LastChannelKey) {
+ JNIEnv* env = AttachCurrentThread();
+
+ // AKEYCODE_LAST_CHANNEL (229) is not defined in minimum NDK.
+ WebKeyboardEvent web_event =
+ CreateFakeWebKeyboardEvent(env, 229, 0, 0);
+ EXPECT_EQ(229, web_event.nativeKeyCode);
+ EXPECT_EQ(ui::KeyboardCode::VKEY_UNKNOWN, web_event.windowsKeyCode);
+ EXPECT_EQ(static_cast<int>(ui::DomCode::NONE), web_event.domCode);
+ EXPECT_EQ(ui::DomKey::MEDIA_LAST, web_event.domKey);
+}
+
+// Synthetic key event should produce DomKey::UNIDENTIFIED.
+TEST(WebInputEventBuilderAndroidTest, DomKeySyntheticEvent) {
+ WebKeyboardEvent web_event = content::WebKeyboardEventBuilder::Build(
+ nullptr, nullptr, WebKeyboardEvent::KeyDown, 0, 0, kCompositionKeyCode, 0,
+ 0, false);
+ EXPECT_EQ(kCompositionKeyCode, web_event.nativeKeyCode);
+ EXPECT_EQ(ui::KeyboardCode::VKEY_UNKNOWN, web_event.windowsKeyCode);
+ EXPECT_EQ(static_cast<int>(ui::DomCode::NONE), web_event.domCode);
+ EXPECT_EQ(ui::DomKey::UNIDENTIFIED, web_event.domKey);
+}
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
index 82386ed5450..2e8ea376b85 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -39,6 +39,7 @@
#include "base/strings/string_util.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
@@ -516,9 +517,8 @@ int ModifiersFromEvent(NSEvent* event) {
void SetWebEventLocationFromEventInView(blink::WebMouseEvent* result,
NSEvent* event,
NSView* view) {
- NSPoint window_local = [event locationInWindow];
-
- NSPoint screen_local = [[view window] convertBaseToScreen:window_local];
+ NSPoint screen_local = ui::ConvertPointFromWindowToScreen(
+ [view window], [event locationInWindow]);
result->globalX = screen_local.x;
// Flip y.
NSScreen* primary_screen = ([[NSScreen screens] count] > 0)
@@ -529,7 +529,8 @@ void SetWebEventLocationFromEventInView(blink::WebMouseEvent* result,
else
result->globalY = screen_local.y;
- NSPoint content_local = [view convertPoint:window_local fromView:nil];
+ NSPoint content_local =
+ [view convertPoint:[event locationInWindow] fromView:nil];
result->x = content_local.x;
result->y = [view frame].size.height - content_local.y; // Flip y.
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
index 3c8c5a284b5..555fecb141d 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
@@ -112,7 +112,8 @@ TEST(WebInputEventBuilderMacTest, ControlSequence) {
EXPECT_EQ(ui::VKEY_OEM_4, web_event.windowsKeyCode);
EXPECT_EQ(ui::DomCode::BRACKET_LEFT,
static_cast<ui::DomCode>(web_event.domCode));
- EXPECT_EQ(ui::DomKey::FromCharacter(0x1b), web_event.domKey);
+ // Will only pass on US layout.
+ EXPECT_EQ(ui::DomKey::FromCharacter('['), web_event.domKey);
}
// Test that numpad keys get mapped correctly.
@@ -246,3 +247,188 @@ TEST(WebInputEventBuilderMacTest, SystemKeyEvents) {
webEvent = WebKeyboardEventBuilder::Build(macEvent);
EXPECT_TRUE(webEvent.isSystemKey);
}
+
+// Test conversion from key combination with Control to DomKey.
+// TODO(chongz): Move DomKey tests for all platforms into one place.
+// http://crbug.com/587589
+// This test case only works for U.S. layout.
+TEST(WebInputEventBuilderMacTest, DomKeyCtrlShift) {
+ struct DomKeyTestCase {
+ int mac_key_code;
+ unichar character;
+ unichar shift_character;
+ } table[] = {
+ {kVK_ANSI_0, '0', ')'}, {kVK_ANSI_1, '1', '!'}, {kVK_ANSI_2, '2', '@'},
+ {kVK_ANSI_3, '3', '#'}, {kVK_ANSI_4, '4', '$'}, {kVK_ANSI_5, '5', '%'},
+ {kVK_ANSI_6, '6', '^'}, {kVK_ANSI_7, '7', '&'}, {kVK_ANSI_8, '8', '*'},
+ {kVK_ANSI_9, '9', '('}, {kVK_ANSI_A, 'a', 'A'}, {kVK_ANSI_B, 'b', 'B'},
+ {kVK_ANSI_C, 'c', 'C'}, {kVK_ANSI_D, 'd', 'D'}, {kVK_ANSI_E, 'e', 'E'},
+ {kVK_ANSI_F, 'f', 'F'}, {kVK_ANSI_G, 'g', 'G'}, {kVK_ANSI_H, 'h', 'H'},
+ {kVK_ANSI_I, 'i', 'I'}, {kVK_ANSI_J, 'j', 'J'}, {kVK_ANSI_K, 'k', 'K'},
+ {kVK_ANSI_L, 'l', 'L'}, {kVK_ANSI_M, 'm', 'M'}, {kVK_ANSI_N, 'n', 'N'},
+ {kVK_ANSI_O, 'o', 'O'}, {kVK_ANSI_P, 'p', 'P'}, {kVK_ANSI_Q, 'q', 'Q'},
+ {kVK_ANSI_R, 'r', 'R'}, {kVK_ANSI_S, 's', 'S'}, {kVK_ANSI_T, 't', 'T'},
+ {kVK_ANSI_U, 'u', 'U'}, {kVK_ANSI_V, 'v', 'V'}, {kVK_ANSI_W, 'w', 'W'},
+ {kVK_ANSI_X, 'x', 'X'}, {kVK_ANSI_Y, 'y', 'Y'}, {kVK_ANSI_Z, 'z', 'Z'}};
+
+ for (const DomKeyTestCase& entry : table) {
+ // Tests ctrl_dom_key.
+ NSEvent* mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.character,
+ NSControlKeyMask, NSKeyDown);
+ WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey);
+ // Tests ctrl_shift_dom_key.
+ mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.shift_character,
+ NSControlKeyMask | NSShiftKeyMask, NSKeyDown);
+ web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.shift_character),
+ web_event.domKey);
+ }
+}
+
+// This test case only works for U.S. layout.
+TEST(WebInputEventBuilderMacTest, DomKeyCtrlAlt) {
+ struct DomKeyTestCase {
+ int mac_key_code;
+ unichar alt_character;
+ unichar ctrl_alt_character;
+ } table[] = {{kVK_ANSI_0, u"º"[0], u"0"[0]}, {kVK_ANSI_1, u"¡"[0], u"1"[0]},
+ {kVK_ANSI_2, u"™"[0], u"2"[0]}, {kVK_ANSI_3, u"£"[0], u"3"[0]},
+ {kVK_ANSI_4, u"¢"[0], u"4"[0]}, {kVK_ANSI_5, u"∞"[0], u"5"[0]},
+ {kVK_ANSI_6, u"§"[0], u"6"[0]}, {kVK_ANSI_7, u"¶"[0], u"7"[0]},
+ {kVK_ANSI_8, u"•"[0], u"8"[0]}, {kVK_ANSI_9, u"ª"[0], u"9"[0]},
+ {kVK_ANSI_A, u"å"[0], u"å"[0]}, {kVK_ANSI_B, u"∫"[0], u"∫"[0]},
+ {kVK_ANSI_C, u"ç"[0], u"ç"[0]}, {kVK_ANSI_D, u"∂"[0], u"∂"[0]},
+ {kVK_ANSI_F, u"ƒ"[0], u"ƒ"[0]}, {kVK_ANSI_G, u"©"[0], u"©"[0]},
+ {kVK_ANSI_H, u"˙"[0], u"˙"[0]}, {kVK_ANSI_J, u"∆"[0], u"∆"[0]},
+ {kVK_ANSI_K, u"˚"[0], u"˚"[0]}, {kVK_ANSI_L, u"¬"[0], u"¬"[0]},
+ {kVK_ANSI_M, u"µ"[0], u"µ"[0]}, {kVK_ANSI_O, u"ø"[0], u"ø"[0]},
+ {kVK_ANSI_P, u"Ï€"[0], u"Ï€"[0]}, {kVK_ANSI_Q, u"Å“"[0], u"Å“"[0]},
+ {kVK_ANSI_R, u"®"[0], u"®"[0]}, {kVK_ANSI_S, u"ß"[0], u"ß"[0]},
+ {kVK_ANSI_T, u"†"[0], u"†"[0]}, {kVK_ANSI_V, u"√"[0], u"√"[0]},
+ {kVK_ANSI_W, u"∑"[0], u"∑"[0]}, {kVK_ANSI_X, u"≈"[0], u"≈"[0]},
+ {kVK_ANSI_Y, u"¥"[0], u"¥"[0]}, {kVK_ANSI_Z, u"Ω"[0], u"Ω"[0]}};
+
+ for (const DomKeyTestCase& entry : table) {
+ // Tests alt_dom_key.
+ NSEvent* mac_event = BuildFakeKeyEvent(
+ entry.mac_key_code, entry.alt_character, NSAlternateKeyMask, NSKeyDown);
+ WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.alt_character), web_event.domKey)
+ << "a " << entry.alt_character;
+ // Tests ctrl_alt_dom_key.
+ mac_event =
+ BuildFakeKeyEvent(entry.mac_key_code, entry.ctrl_alt_character,
+ NSControlKeyMask | NSAlternateKeyMask, NSKeyDown);
+ web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(ui::DomKey::FromCharacter(entry.ctrl_alt_character),
+ web_event.domKey)
+ << "a_c " << entry.ctrl_alt_character;
+ }
+
+ struct DeadDomKeyTestCase {
+ int mac_key_code;
+ unichar alt_accent_character;
+ } dead_key_table[] = {{kVK_ANSI_E, u"´"[0]},
+ {kVK_ANSI_I, u"ˆ"[0]},
+ {kVK_ANSI_N, u"˜"[0]},
+ {kVK_ANSI_U, u"¨"[0]}};
+
+ for (const DeadDomKeyTestCase& entry : dead_key_table) {
+ // Tests alt_accent_character.
+ NSEvent* mac_event =
+ BuildFakeKeyEvent(entry.mac_key_code, 0, NSAlternateKeyMask, NSKeyDown);
+ WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(
+ ui::DomKey::DeadKeyFromCombiningCharacter(entry.alt_accent_character),
+ web_event.domKey)
+ << "a " << entry.alt_accent_character;
+
+ // Tests alt_accent_character with ctrl.
+ mac_event =
+ BuildFakeKeyEvent(entry.mac_key_code, 0,
+ NSControlKeyMask | NSAlternateKeyMask, NSKeyDown);
+ web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(
+ ui::DomKey::DeadKeyFromCombiningCharacter(entry.alt_accent_character),
+ web_event.domKey)
+ << "a_c " << entry.alt_accent_character;
+ }
+}
+
+TEST(WebInputEventBuilderMacTest, DomKeyNonPrintable) {
+ struct DomKeyTestCase {
+ int mac_key_code;
+ unichar character;
+ ui::DomKey dom_key;
+ } table[] = {
+ {kVK_Return, kReturnCharCode, ui::DomKey::ENTER},
+ {kVK_Tab, kTabCharCode, ui::DomKey::TAB},
+ {kVK_Delete, kBackspaceCharCode, ui::DomKey::BACKSPACE},
+ {kVK_Escape, kEscapeCharCode, ui::DomKey::ESCAPE},
+ {kVK_F1, NSF1FunctionKey, ui::DomKey::F1},
+ {kVK_F2, NSF2FunctionKey, ui::DomKey::F2},
+ {kVK_F3, NSF3FunctionKey, ui::DomKey::F3},
+ {kVK_F4, NSF4FunctionKey, ui::DomKey::F4},
+ {kVK_F5, NSF5FunctionKey, ui::DomKey::F5},
+ {kVK_F6, NSF6FunctionKey, ui::DomKey::F6},
+ {kVK_F7, NSF7FunctionKey, ui::DomKey::F7},
+ {kVK_F8, NSF8FunctionKey, ui::DomKey::F8},
+ {kVK_F9, NSF9FunctionKey, ui::DomKey::F9},
+ {kVK_F10, NSF10FunctionKey, ui::DomKey::F10},
+ {kVK_F11, NSF11FunctionKey, ui::DomKey::F11},
+ {kVK_F12, NSF12FunctionKey, ui::DomKey::F12},
+ {kVK_F13, NSF13FunctionKey, ui::DomKey::F13},
+ {kVK_F14, NSF14FunctionKey, ui::DomKey::F14},
+ {kVK_F15, NSF15FunctionKey, ui::DomKey::F15},
+ {kVK_F16, NSF16FunctionKey, ui::DomKey::F16},
+ {kVK_F17, NSF17FunctionKey, ui::DomKey::F17},
+ {kVK_F18, NSF18FunctionKey, ui::DomKey::F18},
+ {kVK_F19, NSF19FunctionKey, ui::DomKey::F19},
+ {kVK_F20, NSF20FunctionKey, ui::DomKey::F20},
+ {kVK_Help, kHelpCharCode, ui::DomKey::HELP},
+ {kVK_Home, NSHomeFunctionKey, ui::DomKey::HOME},
+ {kVK_PageUp, NSPageUpFunctionKey, ui::DomKey::PAGE_UP},
+ {kVK_ForwardDelete, NSDeleteFunctionKey, ui::DomKey::DEL},
+ {kVK_End, NSEndFunctionKey, ui::DomKey::END},
+ {kVK_PageDown, NSPageDownFunctionKey, ui::DomKey::PAGE_DOWN},
+ {kVK_LeftArrow, NSLeftArrowFunctionKey, ui::DomKey::ARROW_LEFT},
+ {kVK_RightArrow, NSRightArrowFunctionKey, ui::DomKey::ARROW_RIGHT},
+ {kVK_DownArrow, NSDownArrowFunctionKey, ui::DomKey::ARROW_DOWN},
+ {kVK_UpArrow, NSUpArrowFunctionKey, ui::DomKey::ARROW_UP}};
+
+ for (const DomKeyTestCase& entry : table) {
+ // Tests non-printable key.
+ NSEvent* mac_event =
+ BuildFakeKeyEvent(entry.mac_key_code, entry.character, 0, NSKeyDown);
+ WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(entry.dom_key, web_event.domKey) << entry.mac_key_code;
+ // Tests non-printable key with Shift.
+ mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.character,
+ NSShiftKeyMask, NSKeyDown);
+ web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(entry.dom_key, web_event.domKey) << "s " << entry.mac_key_code;
+ }
+}
+
+TEST(WebInputEventBuilderMacTest, DomKeyFlagsChanged) {
+ struct DomKeyTestCase {
+ int mac_key_code;
+ ui::DomKey dom_key;
+ } table[] = {{kVK_Command, ui::DomKey::META},
+ {kVK_Shift, ui::DomKey::SHIFT},
+ {kVK_RightShift, ui::DomKey::SHIFT},
+ {kVK_CapsLock, ui::DomKey::CAPS_LOCK},
+ {kVK_Option, ui::DomKey::ALT},
+ {kVK_RightOption, ui::DomKey::ALT},
+ {kVK_Control, ui::DomKey::CONTROL},
+ {kVK_RightControl, ui::DomKey::CONTROL},
+ {kVK_Function, ui::DomKey::FN}};
+
+ for (const DomKeyTestCase& entry : table) {
+ NSEvent* mac_event =
+ BuildFakeKeyEvent(entry.mac_key_code, 0, 0, NSFlagsChanged);
+ WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+ EXPECT_EQ(entry.dom_key, web_event.domKey) << entry.mac_key_code;
+ }
+}
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util.cc b/chromium/content/browser/renderer_host/input/web_input_event_util.cc
index 579e243e274..9368a26a5dd 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util.cc
@@ -14,7 +14,6 @@
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event_constants.h"
#include "ui/events/gesture_detection/gesture_event_data.h"
-#include "ui/events/gesture_detection/motion_event.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
@@ -22,7 +21,6 @@ using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebTouchEvent;
using blink::WebTouchPoint;
-using ui::MotionEvent;
namespace content {
@@ -70,112 +68,4 @@ blink::WebInputEvent::Modifiers DomCodeToWebInputEventModifiers(
return static_cast<blink::WebInputEvent::Modifiers>(0);
}
-// This coversino is temporary. WebInputEvent should be generated
-// directly fromui::Event with the viewport coordinates. See
-// crbug.com/563730.
-scoped_ptr<blink::WebInputEvent> ConvertWebInputEventToViewport(
- const blink::WebInputEvent& event,
- float scale) {
- scoped_ptr<blink::WebInputEvent> scaled_event;
- if (scale == 1.f)
- return scaled_event;
- if (event.type == blink::WebMouseEvent::MouseWheel) {
- blink::WebMouseWheelEvent* wheel_event = new blink::WebMouseWheelEvent;
- scaled_event.reset(wheel_event);
- *wheel_event = static_cast<const blink::WebMouseWheelEvent&>(event);
- wheel_event->x *= scale;
- wheel_event->y *= scale;
- wheel_event->deltaX *= scale;
- wheel_event->deltaY *= scale;
- wheel_event->wheelTicksX *= scale;
- wheel_event->wheelTicksY *= scale;
- } else if (blink::WebInputEvent::isMouseEventType(event.type)) {
- blink::WebMouseEvent* mouse_event = new blink::WebMouseEvent;
- scaled_event.reset(mouse_event);
- *mouse_event = static_cast<const blink::WebMouseEvent&>(event);
- mouse_event->x *= scale;
- mouse_event->y *= scale;
- mouse_event->windowX = mouse_event->x;
- mouse_event->windowY = mouse_event->y;
- mouse_event->movementX *= scale;
- mouse_event->movementY *= scale;
- } else if (blink::WebInputEvent::isTouchEventType(event.type)) {
- blink::WebTouchEvent* touch_event = new blink::WebTouchEvent;
- scaled_event.reset(touch_event);
- *touch_event = static_cast<const blink::WebTouchEvent&>(event);
- for (unsigned i = 0; i < touch_event->touchesLength; i++) {
- touch_event->touches[i].position.x *= scale;
- touch_event->touches[i].position.y *= scale;
- touch_event->touches[i].radiusX *= scale;
- touch_event->touches[i].radiusY *= scale;
- }
- } else if (blink::WebInputEvent::isGestureEventType(event.type)) {
- blink::WebGestureEvent* gesture_event = new blink::WebGestureEvent;
- scaled_event.reset(gesture_event);
- *gesture_event = static_cast<const blink::WebGestureEvent&>(event);
- gesture_event->x *= scale;
- gesture_event->y *= scale;
- switch (gesture_event->type) {
- case blink::WebInputEvent::GestureScrollUpdate:
- gesture_event->data.scrollUpdate.deltaX *= scale;
- gesture_event->data.scrollUpdate.deltaY *= scale;
- break;
- case blink::WebInputEvent::GestureScrollBegin:
- gesture_event->data.scrollBegin.deltaXHint *= scale;
- gesture_event->data.scrollBegin.deltaYHint *= scale;
- break;
-
- case blink::WebInputEvent::GesturePinchUpdate:
- // Scale in pinch gesture is DSF agnostic.
- break;
-
- case blink::WebInputEvent::GestureDoubleTap:
- case blink::WebInputEvent::GestureTap:
- case blink::WebInputEvent::GestureTapUnconfirmed:
- gesture_event->data.tap.width *= scale;
- gesture_event->data.tap.height *= scale;
- break;
-
- case blink::WebInputEvent::GestureTapDown:
- gesture_event->data.tapDown.width *= scale;
- gesture_event->data.tapDown.height *= scale;
- break;
-
- case blink::WebInputEvent::GestureShowPress:
- gesture_event->data.showPress.width *= scale;
- gesture_event->data.showPress.height *= scale;
- break;
-
- case blink::WebInputEvent::GestureLongPress:
- case blink::WebInputEvent::GestureLongTap:
- gesture_event->data.longPress.width *= scale;
- gesture_event->data.longPress.height *= scale;
- break;
-
- case blink::WebInputEvent::GestureTwoFingerTap:
- gesture_event->data.twoFingerTap.firstFingerWidth *= scale;
- gesture_event->data.twoFingerTap.firstFingerHeight *= scale;
- break;
-
- case blink::WebInputEvent::GestureFlingStart:
- gesture_event->data.flingStart.velocityX *= scale;
- gesture_event->data.flingStart.velocityY *= scale;
- break;
-
- // These event does not have location data.
- case blink::WebInputEvent::GesturePinchBegin:
- case blink::WebInputEvent::GesturePinchEnd:
- case blink::WebInputEvent::GestureTapCancel:
- case blink::WebInputEvent::GestureFlingCancel:
- case blink::WebInputEvent::GestureScrollEnd:
- break;
-
- // TODO(oshima): Find out if ContextMenu needs to be scaled.
- default:
- break;
- }
- }
- return scaled_event;
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util.h b/chromium/content/browser/renderer_host/input/web_input_event_util.h
index 8cc3e45af40..b7963a38e28 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util.h
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util.h
@@ -15,7 +15,6 @@ namespace ui {
enum class DomCode;
struct GestureEventData;
struct GestureEventDetails;
-class MotionEvent;
}
namespace content {
@@ -25,10 +24,6 @@ int WebEventModifiersToEventFlags(int modifiers);
blink::WebInputEvent::Modifiers DomCodeToWebInputEventModifiers(
ui::DomCode code);
-CONTENT_EXPORT scoped_ptr<blink::WebInputEvent> ConvertWebInputEventToViewport(
- const blink::WebInputEvent& event,
- float scale);
-
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_WEB_INPUT_EVENT_UTIL_H_
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
index 77810308059..20dce73ec21 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
@@ -125,12 +125,4 @@ TEST(WebInputEventUtilTest, ScrollUpdateConversion) {
EXPECT_TRUE(web_event.data.scrollUpdate.previousUpdateInSequencePrevented);
}
-TEST(WebInputEventUtilTest, NoScalingWith1DSF) {
- auto event =
- SyntheticWebMouseEventBuilder::Build(blink::WebInputEvent::MouseMove,
- 10, 10, 0);
- EXPECT_FALSE(ConvertWebInputEventToViewport(event, 1.f));
- EXPECT_TRUE(ConvertWebInputEventToViewport(event, 2.f));
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 9e2305747a5..3412b33cde8 100644
--- a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
+#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
@@ -96,6 +97,10 @@ void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
host_->OnLegacyWindowDestroyed();
host_ = NULL;
}
+
+ // Re-enable flicks for just a moment
+ base::win::EnableFlicks(hwnd);
+
delete this;
}
@@ -136,6 +141,9 @@ bool LegacyRenderWidgetHostHWND::Init() {
if (direct_manipulation_helper_)
direct_manipulation_helper_->Initialize(hwnd());
+ // Disable pen flicks (http://crbug.com/506977)
+ base::win::DisableFlicks(hwnd());
+
return !!SUCCEEDED(hr);
}
@@ -181,7 +189,7 @@ LRESULT LegacyRenderWidgetHostHWND::OnGetObject(UINT message,
return static_cast<LRESULT>(0L);
base::win::ScopedComPtr<IAccessible> root(
- manager->GetRoot()->ToBrowserAccessibilityWin());
+ ToBrowserAccessibilityWin(manager->GetRoot()));
return LresultFromObject(IID_IAccessible, w_param,
static_cast<IAccessible*>(root.Detach()));
}
diff --git a/chromium/content/browser/renderer_host/media/OWNERS b/chromium/content/browser/renderer_host/media/OWNERS
index b77671af71b..111357356a4 100644
--- a/chromium/content/browser/renderer_host/media/OWNERS
+++ b/chromium/content/browser/renderer_host/media/OWNERS
@@ -1,6 +1,4 @@
-dalecurtis@chromium.org
-ddorwin@chromium.org
-xhwang@chromium.org
+file://media/OWNERS
# WebRTC OWNERS.
perkj@chromium.org
diff --git a/chromium/content/browser/renderer_host/media/audio_input_debug_writer.cc b/chromium/content/browser/renderer_host/media/audio_input_debug_writer.cc
index 5a500b49365..7866c651a34 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_debug_writer.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_debug_writer.cc
@@ -3,22 +3,150 @@
// found in the LICENSE file.
#include "content/browser/renderer_host/media/audio_input_debug_writer.h"
-
+#include <stdint.h>
+#include <array>
#include <utility>
-
+#include "base/logging.h"
+#include "base/sys_byteorder.h"
#include "content/public/browser/browser_thread.h"
#include "media/base/audio_bus.h"
namespace content {
-AudioInputDebugWriter::AudioInputDebugWriter(base::File file)
- : file_(std::move(file)), interleaved_data_size_(0), weak_factory_(this) {}
+namespace {
+
+// Windows WAVE format header
+// Byte order: Little-endian
+// Offset Length Content
+// 0 4 "RIFF"
+// 4 4 <file length - 8>
+// 8 4 "WAVE"
+// 12 4 "fmt "
+// 16 4 <length of the fmt data> (=16)
+// 20 2 <WAVE file encoding tag>
+// 22 2 <channels>
+// 24 4 <sample rate>
+// 28 4 <bytes per second> (sample rate * block align)
+// 32 2 <block align> (channels * bits per sample / 8)
+// 34 2 <bits per sample>
+// 36 4 "data"
+// 40 4 <sample data size(n)>
+// 44 (n) <sample data>
+
+// We write 16 bit PCM only.
+static const uint16_t kBytesPerSample = 2;
+
+static const uint32_t kWavHeaderSize = 44;
+static const uint32_t kFmtChunkSize = 16;
+// 4 bytes for ID + 4 bytes for size.
+static const uint32_t kChunkHeaderSize = 8;
+static const uint16_t kWavFormatPcm = 1;
+
+static const char kRiff[] = {'R', 'I', 'F', 'F'};
+static const char kWave[] = {'W', 'A', 'V', 'E'};
+static const char kFmt[] = {'f', 'm', 't', ' '};
+static const char kData[] = {'d', 'a', 't', 'a'};
+
+typedef std::array<char, kWavHeaderSize> WavHeaderBuffer;
+
+class CharBufferWriter {
+ public:
+ CharBufferWriter(char* buf, int max_size)
+ : buf_(buf), max_size_(max_size), size_(0) {}
+
+ void Write(const char* data, int data_size) {
+ CHECK_LE(size_ + data_size, max_size_);
+ memcpy(&buf_[size_], data, data_size);
+ size_ += data_size;
+ }
+
+ void Write(const char(&data)[4]) { Write(static_cast<const char*>(data), 4); }
+
+ void WriteLE16(uint16_t data) {
+ uint16_t val = base::ByteSwapToLE16(data);
+ Write(reinterpret_cast<const char*>(&val), sizeof(val));
+ }
+
+ void WriteLE32(uint32_t data) {
+ uint32_t val = base::ByteSwapToLE32(data);
+ Write(reinterpret_cast<const char*>(&val), sizeof(val));
+ }
+
+ private:
+ char* buf_;
+ const int max_size_;
+ int size_;
+
+ DISALLOW_COPY_AND_ASSIGN(CharBufferWriter);
+};
+
+// Writes Wave header to the specified address, there should be at least
+// kWavHeaderSize bytes allocated for it.
+void WriteWavHeader(WavHeaderBuffer* buf,
+ uint32_t channels,
+ uint32_t sample_rate,
+ uint64_t samples) {
+ // We'll need to add (kWavHeaderSize - kChunkHeaderSize) to payload to
+ // calculate Riff chunk size.
+ static const uint32_t kMaxBytesInPayload =
+ std::numeric_limits<uint32_t>::max() -
+ (kWavHeaderSize - kChunkHeaderSize);
+ const uint64_t bytes_in_payload_64 = samples * kBytesPerSample;
+
+ // In case payload is too large and causes uint32_t overflow, we just specify
+ // the maximum possible value; all the payload above that count will be
+ // interpreted as garbage.
+ const uint32_t bytes_in_payload = bytes_in_payload_64 > kMaxBytesInPayload
+ ? kMaxBytesInPayload
+ : bytes_in_payload_64;
+ LOG_IF(WARNING, bytes_in_payload < bytes_in_payload_64)
+ << "Number of samples is too large and will be clipped by Wave header,"
+ << " all the data above " << kMaxBytesInPayload
+ << " bytes will appear as junk";
+ const uint32_t block_align = channels * kBytesPerSample;
+ const uint32_t byte_rate = channels * sample_rate * kBytesPerSample;
+ const uint32_t riff_chunk_size =
+ bytes_in_payload + kWavHeaderSize - kChunkHeaderSize;
+
+ CharBufferWriter writer(&(*buf)[0], kWavHeaderSize);
+
+ writer.Write(kRiff);
+ writer.WriteLE32(riff_chunk_size);
+ writer.Write(kWave);
+ writer.Write(kFmt);
+ writer.WriteLE32(kFmtChunkSize);
+ writer.WriteLE16(kWavFormatPcm);
+ writer.WriteLE16(channels);
+ writer.WriteLE32(sample_rate);
+ writer.WriteLE32(byte_rate);
+ writer.WriteLE16(block_align);
+ writer.WriteLE16(kBytesPerSample * 8);
+ writer.Write(kData);
+ writer.WriteLE32(bytes_in_payload);
+}
+
+} // namespace
+
+AudioInputDebugWriter::AudioInputDebugWriter(
+ base::File file,
+ const media::AudioParameters& params)
+ : file_(std::move(file)),
+ samples_(0),
+ params_(params),
+ interleaved_data_size_(0),
+ weak_factory_(this) {
+ DCHECK_EQ(params.bits_per_sample(), kBytesPerSample * 8);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&AudioInputDebugWriter::WriteHeader,
+ weak_factory_.GetWeakPtr()));
+}
AudioInputDebugWriter::~AudioInputDebugWriter() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ WriteHeader();
}
-void AudioInputDebugWriter::Write(scoped_ptr<media::AudioBus> data) {
+void AudioInputDebugWriter::Write(std::unique_ptr<media::AudioBus> data) {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
@@ -27,19 +155,43 @@ void AudioInputDebugWriter::Write(scoped_ptr<media::AudioBus> data) {
base::Passed(&data)));
}
-void AudioInputDebugWriter::DoWrite(scoped_ptr<media::AudioBus> data) {
+void AudioInputDebugWriter::DoWrite(std::unique_ptr<media::AudioBus> data) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
// Convert to 16 bit audio and write to file.
int data_size = data->frames() * data->channels();
if (!interleaved_data_ || interleaved_data_size_ < data_size) {
interleaved_data_.reset(new int16_t[data_size]);
interleaved_data_size_ = data_size;
}
+ samples_ += data_size;
data->ToInterleaved(data->frames(), sizeof(interleaved_data_[0]),
interleaved_data_.get());
+
+#ifndef ARCH_CPU_LITTLE_ENDIAN
+ static_assert(sizeof(interleaved_data_[0]) == sizeof(uint16_t),
+ "Only 2 bytes per channel is supported.");
+ for (int i = 0; i < data_size; ++i)
+ interleaved_data_[i] = base::ByteSwapToLE16(interleaved_data_[i]);
+#endif
+
file_.WriteAtCurrentPos(reinterpret_cast<char*>(interleaved_data_.get()),
data_size * sizeof(interleaved_data_[0]));
}
+// This method is called twice: on construction of AudioInputDebugWriter size of
+// the data is unknown, so the header is written with zero sizes; then on
+// destruction it is re-written with the actual size info accumulated throughout
+// its lifetime.
+void AudioInputDebugWriter::WriteHeader() {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+
+ WavHeaderBuffer buf;
+ WriteWavHeader(&buf, params_.channels(), params_.sample_rate(), samples_);
+ file_.Write(0, &buf[0], kWavHeaderSize);
+
+ // Write() does not move the cursor if file is not in APPEND mode; Seek() so
+ // that the header is not overwritten by the following writes.
+ file_.Seek(base::File::FROM_BEGIN, kWavHeaderSize);
+}
+
} // namspace content
diff --git a/chromium/content/browser/renderer_host/media/audio_input_debug_writer.h b/chromium/content/browser/renderer_host/media/audio_input_debug_writer.h
index 13977756877..0741001d99c 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_debug_writer.h
+++ b/chromium/content/browser/renderer_host/media/audio_input_debug_writer.h
@@ -7,13 +7,16 @@
#include <stdint.h>
+#include <memory>
+
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/move.h"
+#include "content/common/content_export.h"
#include "media/audio/audio_input_writer.h"
+#include "media/audio/audio_parameters.h"
namespace media {
@@ -28,24 +31,37 @@ namespace content {
// thread. Must be destroyed on the FILE thread. Write call can be made on any
// thread. This object must be unregistered in Write caller before destroyed.
// When created, it takes ownership of |file|.
-class AudioInputDebugWriter : public media::AudioInputWriter {
+class CONTENT_EXPORT AudioInputDebugWriter
+ : public NON_EXPORTED_BASE(media::AudioInputWriter) {
public:
- explicit AudioInputDebugWriter(base::File file);
+ AudioInputDebugWriter(base::File file, const media::AudioParameters& params);
~AudioInputDebugWriter() override;
// Write data from |data| to file.
- void Write(scoped_ptr<media::AudioBus> data) override;
+ void Write(std::unique_ptr<media::AudioBus> data) override;
private:
// Write data from |data| to file. Called on the FILE thread.
- void DoWrite(scoped_ptr<media::AudioBus> data);
+ void DoWrite(std::unique_ptr<media::AudioBus> data);
+
+ // Write wave header to file. Called on the FILE thread twice: on construction
+ // of AudioInputDebugWriter size of the wave data is unknown, so the header is
+ // written with zero sizes; then on destruction it is re-written with the
+ // actual size info accumulated throughout the object lifetime.
+ void WriteHeader();
// The file to write to.
base::File file_;
+ // Number of written samples.
+ uint64_t samples_;
+
+ // Input audio parameters required to build wave header.
+ media::AudioParameters params_;
+
// Intermediate buffer to be written to file. Interleaved 16 bit audio data.
- scoped_ptr<int16_t[]> interleaved_data_;
+ std::unique_ptr<int16_t[]> interleaved_data_;
int interleaved_data_size_;
base::WeakPtrFactory<AudioInputDebugWriter> weak_factory_;
diff --git a/chromium/content/browser/renderer_host/media/audio_input_debug_writer_unittest.cc b/chromium/content/browser/renderer_host/media/audio_input_debug_writer_unittest.cc
new file mode 100644
index 00000000000..ee8b5d5cdfd
--- /dev/null
+++ b/chromium/content/browser/renderer_host/media/audio_input_debug_writer_unittest.cc
@@ -0,0 +1,270 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "base/files/file_util.h"
+#include "base/sys_byteorder.h"
+#include "content/browser/renderer_host/media/audio_input_debug_writer.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "media/base/audio_bus.h"
+#include "media/base/test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+static const uint16_t kBytesPerSample = sizeof(uint16_t);
+static const uint16_t kPcmEncoding = 1;
+static const size_t kWavHeaderSize = 44;
+
+uint16_t ReadLE2(const char* buf) {
+ return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8);
+}
+
+uint32_t ReadLE4(const char* buf) {
+ return static_cast<uint8_t>(buf[0]) | (static_cast<uint8_t>(buf[1]) << 8) |
+ (static_cast<uint8_t>(buf[2]) << 16) |
+ (static_cast<uint8_t>(buf[3]) << 24);
+}
+
+} // namespace
+
+// <channel layout, sample rate, frames per buffer, number of buffer writes
+typedef std::tr1::tuple<media::ChannelLayout, int, int, int>
+ AudioInputDebugWriterTestData;
+
+class AudioInputDebugWriterTest
+ : public testing::TestWithParam<AudioInputDebugWriterTestData> {
+ public:
+ AudioInputDebugWriterTest()
+ : params_(media::AudioParameters::Format::AUDIO_PCM_LINEAR,
+ std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()),
+ kBytesPerSample * 8,
+ std::tr1::get<2>(GetParam())),
+ writes_(std::tr1::get<3>(GetParam())),
+ source_samples_(params_.frames_per_buffer() * params_.channels() *
+ writes_),
+ source_interleaved_(source_samples_ ? new int16_t[source_samples_]
+ : nullptr) {
+ InitSourceInterleaved(source_interleaved_.get(), source_samples_);
+ }
+
+ protected:
+ virtual ~AudioInputDebugWriterTest() {}
+
+ static void InitSourceInterleaved(int16_t* source_interleaved,
+ int source_samples) {
+ if (source_samples) {
+ // equal steps to cover int16_t range of values
+ int16_t step = 0xffff / source_samples;
+ int16_t val = std::numeric_limits<int16_t>::min();
+ for (int i = 0; i < source_samples; ++i, val += step)
+ source_interleaved[i] = val;
+ }
+ }
+
+ static void VerifyHeader(const char(&wav_header)[kWavHeaderSize],
+ const media::AudioParameters& params,
+ int writes,
+ int64_t file_length) {
+ uint32_t block_align = params.channels() * kBytesPerSample;
+ uint32_t data_size =
+ static_cast<uint32_t>(params.frames_per_buffer() * params.channels() *
+ writes * kBytesPerSample);
+ // Offset Length Content
+ // 0 4 "RIFF"
+ EXPECT_EQ(0, strncmp(wav_header, "RIFF", 4));
+ // 4 4 <file length - 8>
+ EXPECT_EQ(static_cast<uint64_t>(file_length - 8), ReadLE4(wav_header + 4));
+ EXPECT_EQ(static_cast<uint32_t>(data_size + kWavHeaderSize - 8),
+ ReadLE4(wav_header + 4));
+ // 8 4 "WAVE"
+ // 12 4 "fmt "
+ EXPECT_EQ(0, strncmp(wav_header + 8, "WAVEfmt ", 8));
+ // 16 4 <length of the fmt data> (=16)
+ EXPECT_EQ(16U, ReadLE4(wav_header + 16));
+ // 20 2 <WAVE file encoding tag>
+ EXPECT_EQ(kPcmEncoding, ReadLE2(wav_header + 20));
+ // 22 2 <channels>
+ EXPECT_EQ(params.channels(), ReadLE2(wav_header + 22));
+ // 24 4 <sample rate>
+ EXPECT_EQ(static_cast<uint32_t>(params.sample_rate()),
+ ReadLE4(wav_header + 24));
+ // 28 4 <bytes per second> (sample rate * block align)
+ EXPECT_EQ(static_cast<uint32_t>(params.sample_rate()) * block_align,
+ ReadLE4(wav_header + 28));
+ // 32 2 <block align> (channels * bits per sample / 8)
+ EXPECT_EQ(block_align, ReadLE2(wav_header + 32));
+ // 34 2 <bits per sample>
+ EXPECT_EQ(kBytesPerSample * 8, ReadLE2(wav_header + 34));
+ // 36 4 "data"
+ EXPECT_EQ(0, strncmp(wav_header + 36, "data", 4));
+ // 40 4 <sample data size(n)>
+ EXPECT_EQ(data_size, ReadLE4(wav_header + 40));
+ }
+
+ // |result_interleaved| is expected to be little-endian.
+ static void VerifyDataRecording(const int16_t* source_interleaved,
+ const int16_t* result_interleaved,
+ int16_t source_samples) {
+ // Allow mismatch by 1 due to rounding error in int->float->int
+ // calculations.
+ for (int i = 0; i < source_samples; ++i)
+ EXPECT_LE(std::abs(static_cast<int16_t>(
+ base::ByteSwapToLE16(source_interleaved[i])) -
+ result_interleaved[i]),
+ 1)
+ << "i = " << i << " source " << source_interleaved[i] << " result "
+ << result_interleaved[i];
+ }
+
+ void VerifyRecording(const base::FilePath& file_path) {
+ base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ EXPECT_TRUE(file.IsValid());
+
+ char wav_header[kWavHeaderSize];
+ EXPECT_EQ(file.Read(0, wav_header, kWavHeaderSize),
+ static_cast<int>(kWavHeaderSize));
+ VerifyHeader(wav_header, params_, writes_, file.GetLength());
+
+ if (source_samples_ > 0) {
+ std::unique_ptr<int16_t[]> result_interleaved(
+ new int16_t[source_samples_]);
+ memset(result_interleaved.get(), 0, source_samples_ * kBytesPerSample);
+
+ // Recording is read from file as a byte sequence, so it stored as
+ // little-endian.
+ int read = file.Read(kWavHeaderSize,
+ reinterpret_cast<char*>(result_interleaved.get()),
+ source_samples_ * kBytesPerSample);
+ EXPECT_EQ(static_cast<int>(file.GetLength() - kWavHeaderSize), read);
+
+ VerifyDataRecording(source_interleaved_.get(), result_interleaved.get(),
+ source_samples_);
+ }
+ }
+
+ void TestDoneOnFileThread(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+
+ // |writer| must be destroyed on FILE thread.
+ input_debug_writer_.reset(nullptr);
+ callback.Run();
+ }
+
+ void DoDebugRecording(base::File file) {
+ if (!file.IsValid())
+ return;
+
+ input_debug_writer_.reset(
+ new AudioInputDebugWriter(std::move(file), params_));
+ // Write tasks are posted to BrowserThread::FILE.
+ for (int i = 0; i < writes_; ++i) {
+ std::unique_ptr<media::AudioBus> bus = media::AudioBus::Create(
+ params_.channels(), params_.frames_per_buffer());
+
+ bus->FromInterleaved(
+ source_interleaved_.get() +
+ i * params_.channels() * params_.frames_per_buffer(),
+ params_.frames_per_buffer(), kBytesPerSample);
+
+ input_debug_writer_->Write(std::move(bus));
+ }
+
+ media::WaitableMessageLoopEvent event;
+
+ // Post a task to BrowserThread::FILE indicating that all the writes are
+ // done.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&AudioInputDebugWriterTest::TestDoneOnFileThread,
+ base::Unretained(this), event.GetClosure()));
+
+ // Wait for TestDoneOnFileThread() to call event's closure.
+ event.RunAndWait();
+ }
+
+ protected:
+ TestBrowserThreadBundle thread_bundle_;
+
+ // Writer under test.
+ std::unique_ptr<AudioInputDebugWriter> input_debug_writer_;
+
+ // AudioBus parameters.
+ media::AudioParameters params_;
+
+ // Number of times to write AudioBus to the file.
+ int writes_;
+
+ // Number of samples in the source data.
+ int source_samples_;
+
+ // Source data.
+ std::unique_ptr<int16_t[]> source_interleaved_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AudioInputDebugWriterTest);
+};
+
+TEST_P(AudioInputDebugWriterTest, WaveRecordingTest) {
+ base::FilePath file_path;
+ EXPECT_TRUE(base::CreateTemporaryFile(&file_path));
+
+ base::File file(file_path,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ EXPECT_TRUE(file.IsValid());
+
+ DoDebugRecording(std::move(file));
+
+ VerifyRecording(file_path);
+
+ if (::testing::Test::HasFailure()) {
+ LOG(ERROR) << "Test failed; keeping recording(s) at ["
+ << file_path.value().c_str() << "].";
+ } else {
+ EXPECT_TRUE(base::DeleteFile(file_path, false));
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AudioInputDebugWriterTest,
+ AudioInputDebugWriterTest,
+ // Using 10ms sframes per buffer everywhere.
+ testing::Values(
+ // No writes.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO,
+ 44100,
+ 44100 / 100,
+ 0),
+ // 1 write of mono.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO,
+ 44100,
+ 44100 / 100,
+ 1),
+ // 1 second of mono.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO,
+ 44100,
+ 44100 / 100,
+ 100),
+ // 1 second of mono, higher rate.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO,
+ 48000,
+ 48000 / 100,
+ 100),
+ // 1 second of stereo.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
+ 44100,
+ 44100 / 100,
+ 100),
+ // 15 seconds of stereo, higher rate.
+ std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO,
+ 48000,
+ 48000 / 100,
+ 1500)));
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc b/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
index 65148e04e90..72f8ee0a391 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
@@ -4,8 +4,9 @@
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include <memory>
+
#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
@@ -172,7 +173,7 @@ void AudioInputDeviceManager::EnumerateOnDeviceThread(
audio_manager_->GetAudioInputDeviceNames(&device_names);
}
- scoped_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray());
+ std::unique_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray());
for (media::AudioDeviceNames::iterator it = device_names.begin();
it != device_names.end(); ++it) {
// Add device information to device vector.
@@ -241,7 +242,7 @@ void AudioInputDeviceManager::OpenOnDeviceThread(
void AudioInputDeviceManager::DevicesEnumeratedOnIOThread(
MediaStreamType stream_type,
- scoped_ptr<StreamDeviceInfoArray> devices) {
+ std::unique_ptr<StreamDeviceInfoArray> devices) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Ensure that |devices| gets deleted on exit.
if (listener_)
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager.h b/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
index d3f01b35f78..0f58242f75d 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
@@ -84,8 +84,9 @@ class CONTENT_EXPORT AudioInputDeviceManager : public MediaStreamProvider {
// Callback used by EnumerateOnDeviceThread(), called with a list of
// enumerated devices on IO thread.
- void DevicesEnumeratedOnIOThread(MediaStreamType stream_type,
- scoped_ptr<StreamDeviceInfoArray> devices);
+ void DevicesEnumeratedOnIOThread(
+ MediaStreamType stream_type,
+ std::unique_ptr<StreamDeviceInfoArray> devices);
// Callback used by OpenOnDeviceThread(), called with the session_id
// referencing the opened device on IO thread.
void OpenedOnIOThread(int session_id, const StreamDeviceInfo& info);
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index 4fac69d7dda..dd387bbdf23 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -2,20 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+
#include <stddef.h>
+#include <memory>
#include <string>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "build/build_config.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/public/common/media_stream_request.h"
#include "media/audio/audio_manager_base.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -94,11 +95,11 @@ class MAYBE_AudioInputDeviceManagerTest : public testing::Test {
io_thread_.reset();
}
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<BrowserThreadImpl> io_thread_;
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<BrowserThreadImpl> io_thread_;
scoped_refptr<AudioInputDeviceManager> manager_;
- scoped_ptr<MockAudioInputDeviceManagerListener> audio_input_listener_;
- scoped_ptr<media::AudioManager> audio_manager_;
+ std::unique_ptr<MockAudioInputDeviceManagerListener> audio_input_listener_;
+ std::unique_ptr<media::AudioManager> audio_manager_;
StreamDeviceInfoArray devices_;
private:
@@ -141,7 +142,7 @@ TEST_F(MAYBE_AudioInputDeviceManagerTest, OpenMultipleDevices) {
InSequence s;
int index = 0;
- scoped_ptr<int[]> session_id(new int[devices_.size()]);
+ std::unique_ptr<int[]> session_id(new int[devices_.size()]);
// Opens the devices in a loop.
for (StreamDeviceInfoArray::const_iterator iter = devices_.begin();
@@ -238,7 +239,7 @@ TEST_F(MAYBE_AudioInputDeviceManagerTest, AccessAndCloseSession) {
InSequence s;
int index = 0;
- scoped_ptr<int[]> session_id(new int[devices_.size()]);
+ std::unique_ptr<int[]> session_id(new int[devices_.size()]);
// Loops through the devices and calls Open()/Close()/GetOpenedDeviceInfoById
// for each device.
diff --git a/chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc b/chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc
index 60f64596171..2d8a89a1481 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -16,9 +16,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
+#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
#include "content/browser/media/capture/web_contents_audio_input_stream.h"
#include "content/browser/media/media_internals.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/browser/renderer_host/media/audio_input_debug_writer.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
@@ -35,7 +36,7 @@ namespace {
const base::FilePath::CharType kDebugRecordingFileNameAddition[] =
FILE_PATH_LITERAL("source_input");
const base::FilePath::CharType kDebugRecordingFileNameExtension[] =
- FILE_PATH_LITERAL("pcm");
+ FILE_PATH_LITERAL("wav");
#endif
void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
@@ -52,7 +53,7 @@ void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
base::File CreateDebugRecordingFile(base::FilePath file_path) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::File recording_file(
- file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
+ file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
PLOG_IF(ERROR, !recording_file.IsValid())
<< "Could not open debug recording file, error="
<< recording_file.error_details();
@@ -65,7 +66,7 @@ void CloseFile(base::File file) {
}
void DeleteInputDebugWriterOnFileThread(
- scoped_ptr<AudioInputDebugWriter> writer) {
+ std::unique_ptr<AudioInputDebugWriter> writer) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
// |writer| must be closed and destroyed on FILE thread.
}
@@ -90,17 +91,22 @@ struct AudioInputRendererHost::AudioEntry {
// The synchronous writer to be used by the controller. We have the
// ownership of the writer.
- scoped_ptr<media::AudioInputController::SyncWriter> writer;
+ std::unique_ptr<AudioInputSyncWriter> writer;
// Must be deleted on the file thread. Must be posted for deletion and nulled
// before the AudioEntry is deleted.
- scoped_ptr<AudioInputDebugWriter> input_debug_writer;
+ std::unique_ptr<AudioInputDebugWriter> input_debug_writer;
// Set to true after we called Close() for the controller.
bool pending_close;
// If this entry's layout has a keyboard mic channel.
bool has_keyboard_mic;
+
+#ifdef ENABLE_WEBRTC
+ // Stream audio parameters, used to build wave header for debug recording.
+ media::AudioParameters audio_params;
+#endif // ENABLE_WEBRTC
};
AudioInputRendererHost::AudioEntry::AudioEntry()
@@ -168,35 +174,25 @@ void AudioInputRendererHost::OnDestruct() const {
void AudioInputRendererHost::OnCreated(
media::AudioInputController* controller) {
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &AudioInputRendererHost::DoCompleteCreation,
- this,
- make_scoped_refptr(controller)));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioInputRendererHost::DoCompleteCreation, this,
+ base::RetainedRef(controller)));
}
void AudioInputRendererHost::OnRecording(
media::AudioInputController* controller) {
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &AudioInputRendererHost::DoSendRecordingMessage,
- this,
- make_scoped_refptr(controller)));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioInputRendererHost::DoSendRecordingMessage, this,
+ base::RetainedRef(controller)));
}
void AudioInputRendererHost::OnError(media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) {
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &AudioInputRendererHost::DoHandleError,
- this,
- make_scoped_refptr(controller),
- error_code));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioInputRendererHost::DoHandleError, this,
+ base::RetainedRef(controller), error_code));
}
void AudioInputRendererHost::OnData(media::AudioInputController* controller,
@@ -206,12 +202,9 @@ void AudioInputRendererHost::OnData(media::AudioInputController* controller,
void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
const std::string& message) {
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioInputRendererHost::DoLog,
- this,
- make_scoped_refptr(controller),
- message));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioInputRendererHost::DoLog, this,
+ base::RetainedRef(controller), message));
}
void AudioInputRendererHost::set_renderer_pid(int32_t renderer_pid) {
@@ -252,8 +245,7 @@ void AudioInputRendererHost::DoCompleteCreation(
return;
}
- AudioInputSyncWriter* writer =
- static_cast<AudioInputSyncWriter*>(entry->writer.get());
+ AudioInputSyncWriter* writer = entry->writer.get();
base::SyncSocket::TransitDescriptor socket_transit_descriptor;
@@ -391,6 +383,7 @@ void AudioInputRendererHost::DoCreateStream(
audio_params.set_format(media::AudioParameters::AUDIO_FAKE);
// Check if we have the permission to open the device and which device to use.
+ MediaStreamType type = MEDIA_NO_SERVICE;
std::string device_name;
std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
@@ -403,14 +396,14 @@ void AudioInputRendererHost::DoCreateStream(
MaybeUnregisterKeyboardMicStream(config);
return;
}
-
+ type = info->device.type;
device_id = info->device.id;
device_name = info->device.name;
oss << ": device_name=" << device_name;
}
// Create a new AudioEntry structure.
- scoped_ptr<AudioEntry> entry(new AudioEntry());
+ std::unique_ptr<AudioEntry> entry(new AudioEntry());
const uint32_t segment_size =
(sizeof(media::AudioInputBufferParameters) +
@@ -429,7 +422,7 @@ void AudioInputRendererHost::DoCreateStream(
return;
}
- scoped_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
+ std::unique_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
entry->shared_memory.memory(), entry->shared_memory.requested_size(),
entry->shared_memory_segment_count, audio_params));
@@ -453,6 +446,9 @@ void AudioInputRendererHost::DoCreateStream(
audio_mirroring_manager_),
entry->writer.get(),
user_input_monitor_);
+ // Only count for captures from desktop media picker dialog.
+ if (entry->controller.get() && type == MEDIA_DESKTOP_AUDIO_CAPTURE)
+ IncrementDesktopCaptureCounter(TAB_AUDIO_CAPTURER_CREATED);
} else {
// We call CreateLowLatency regardless of the value of
// |audio_params.format|. Low latency can currently mean different things in
@@ -468,6 +464,13 @@ void AudioInputRendererHost::DoCreateStream(
user_input_monitor_,
config.automatic_gain_control);
oss << ", AGC=" << config.automatic_gain_control;
+
+ // Only count for captures from desktop media picker dialog and system loop
+ // back audio.
+ if (entry->controller.get() && type == MEDIA_DESKTOP_AUDIO_CAPTURE &&
+ device_id == media::AudioManagerBase::kLoopbackInputDeviceId) {
+ IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
+ }
}
if (!entry->controller.get()) {
@@ -483,6 +486,10 @@ void AudioInputRendererHost::DoCreateStream(
}
#endif
+#if defined(ENABLE_WEBRTC)
+ entry->audio_params = audio_params;
+#endif // ENABLE_WEBRTC
+
MediaStreamManager::SendMessageToNativeLog(oss.str());
DVLOG(1) << oss.str();
@@ -594,7 +601,7 @@ void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
#endif
// Delete the entry when this method goes out of scope.
- scoped_ptr<AudioEntry> entry_deleter(entry);
+ std::unique_ptr<AudioEntry> entry_deleter(entry);
// Erase the entry from the map.
audio_entries_.erase(entry->stream_id);
@@ -705,7 +712,8 @@ void AudioInputRendererHost::DoEnableDebugRecording(
base::Bind(&CloseFile, Passed(std::move(file))));
return;
}
- entry->input_debug_writer.reset(new AudioInputDebugWriter(std::move(file)));
+ entry->input_debug_writer.reset(
+ new AudioInputDebugWriter(std::move(file), entry->audio_params));
entry->controller->EnableDebugRecording(entry->input_debug_writer.get());
}
diff --git a/chromium/content/browser/renderer_host/media/audio_input_renderer_host.h b/chromium/content/browser/renderer_host/media/audio_input_renderer_host.h
index dd549965446..cd6ed9db082 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_renderer_host.h
+++ b/chromium/content/browser/renderer_host/media/audio_input_renderer_host.h
@@ -24,15 +24,15 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_RENDERER_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_RENDERER_HOST_H_
+#include <stdint.h>
+
#include <map>
+#include <memory>
#include <string>
-#include <stdint.h>
-
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "base/sequenced_task_runner_helpers.h"
@@ -259,7 +259,7 @@ class CONTENT_EXPORT AudioInputRendererHost
// Raw pointer of the UserInputMonitor.
media::UserInputMonitor* user_input_monitor_;
- scoped_ptr<media::AudioLog> audio_log_;
+ std::unique_ptr<media::AudioLog> audio_log_;
base::WeakPtrFactory<AudioInputRendererHost> weak_factory_;
diff --git a/chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc b/chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc
index 1ddc66c1e29..caa326127b6 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc
@@ -61,9 +61,9 @@ AudioInputSyncWriter::AudioInputSyncWriter(void* shared_memory,
CHECK_EQ(0U, reinterpret_cast<uintptr_t>(ptr) &
(AudioBus::kChannelAlignment - 1));
AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr);
- scoped_ptr<AudioBus> audio_bus =
+ std::unique_ptr<AudioBus> audio_bus =
AudioBus::WrapMemory(params, buffer->audio);
- audio_buses_.push_back(audio_bus.release());
+ audio_buses_.push_back(std::move(audio_bus));
ptr += shared_memory_segment_size_;
}
}
@@ -132,7 +132,8 @@ void AudioInputSyncWriter::Write(const AudioBus* data,
// writing. We verify that each buffer index is in sequence.
size_t number_of_indices_available = socket_->Peek() / sizeof(uint32_t);
if (number_of_indices_available > 0) {
- scoped_ptr<uint32_t[]> indices(new uint32_t[number_of_indices_available]);
+ std::unique_ptr<uint32_t[]> indices(
+ new uint32_t[number_of_indices_available]);
size_t bytes_received = socket_->Receive(
&indices[0],
number_of_indices_available * sizeof(indices[0]));
@@ -249,10 +250,10 @@ bool AudioInputSyncWriter::PushDataToFifo(const AudioBus* data,
overflow_params_.push_back(params);
// Push audio data to fifo.
- scoped_ptr<AudioBus> audio_bus =
+ std::unique_ptr<AudioBus> audio_bus =
AudioBus::Create(data->channels(), data->frames());
data->CopyTo(audio_bus.get());
- overflow_buses_.push_back(audio_bus.release());
+ overflow_buses_.push_back(std::move(audio_bus));
DCHECK_LE(overflow_buses_.size(), static_cast<size_t>(kMaxOverflowBusesSize));
DCHECK_EQ(overflow_params_.size(), overflow_buses_.size());
diff --git a/chromium/content/browser/renderer_host/media/audio_input_sync_writer.h b/chromium/content/browser/renderer_host/media/audio_input_sync_writer.h
index 8429e44ee73..432901633fe 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_sync_writer.h
+++ b/chromium/content/browser/renderer_host/media/audio_input_sync_writer.h
@@ -59,7 +59,7 @@ class CONTENT_EXPORT AudioInputSyncWriter
protected:
// Socket for transmitting audio data.
- scoped_ptr<base::CancelableSyncSocket> socket_;
+ std::unique_ptr<base::CancelableSyncSocket> socket_;
private:
friend class AudioInputSyncWriterTest;
@@ -107,7 +107,7 @@ class CONTENT_EXPORT AudioInputSyncWriter
// Socket to be used by the renderer. The reference is released after
// PrepareForeignSocketHandle() is called and ran successfully.
- scoped_ptr<base::CancelableSyncSocket> foreign_socket_;
+ std::unique_ptr<base::CancelableSyncSocket> foreign_socket_;
// The time of the creation of this object.
base::Time creation_time_;
diff --git a/chromium/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc b/chromium/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc
index d691b22d342..0fdf34203ce 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc
@@ -2,16 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
+
#include <stddef.h>
#include <stdint.h>
+#include <memory>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/sync_socket.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_bus.h"
@@ -181,9 +183,9 @@ class AudioInputSyncWriterTest : public testing::Test {
}
protected:
- scoped_ptr<AudioInputSyncWriterUnderTest> writer_;
+ std::unique_ptr<AudioInputSyncWriterUnderTest> writer_;
MockCancelableSyncSocket* socket_;
- scoped_ptr<AudioBus> audio_bus_;
+ std::unique_ptr<AudioBus> audio_bus_;
private:
TestBrowserThreadBundle thread_bundle_;
diff --git a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.cc b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.cc
index 54c05311e1f..24ef8f9ec2e 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.cc
+++ b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.cc
@@ -17,7 +17,7 @@ namespace {
AudioOutputDeviceEnumeration EnumerateDevicesOnDeviceThread(
media::AudioManager* audio_manager) {
- DCHECK(audio_manager->GetWorkerTaskRunner()->BelongsToCurrentThread());
+ DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
AudioOutputDeviceEnumeration snapshot;
media::AudioDeviceNames device_names;
@@ -54,6 +54,9 @@ AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration(
AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration()
: has_actual_devices(false) {}
+AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration(
+ const AudioOutputDeviceEnumeration& other) = default;
+
AudioOutputDeviceEnumeration::~AudioOutputDeviceEnumeration() {}
AudioOutputDeviceEnumerator::AudioOutputDeviceEnumerator(
@@ -114,7 +117,7 @@ void AudioOutputDeviceEnumerator::DoEnumerateDevices() {
is_enumeration_ongoing_ = true;
seq_last_enumeration_ = NewEventSequence();
base::PostTaskAndReplyWithResult(
- audio_manager_->GetWorkerTaskRunner().get(), FROM_HERE,
+ audio_manager_->GetTaskRunner().get(), FROM_HERE,
base::Bind(&EnumerateDevicesOnDeviceThread, audio_manager_),
base::Bind(&AudioOutputDeviceEnumerator::DevicesEnumerated,
weak_factory_.GetWeakPtr()));
diff --git a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.h b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.h
index bf223a9bccd..1de0ea8074f 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.h
+++ b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator.h
@@ -12,13 +12,14 @@
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_OUTPUT_DEVICE_ENUMERATOR_H_
#include <stdint.h>
+
#include <list>
+#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
@@ -50,6 +51,7 @@ struct AudioOutputDeviceEnumeration {
const std::vector<AudioOutputDeviceInfo>& devices,
bool has_actual_devices);
AudioOutputDeviceEnumeration();
+ AudioOutputDeviceEnumeration(const AudioOutputDeviceEnumeration& other);
~AudioOutputDeviceEnumeration();
std::vector<AudioOutputDeviceInfo> devices;
diff --git a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc
index ac6140cbb01..f84f87e2bd0 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc
@@ -2,18 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/audio_output_device_enumerator.h"
+
+#include <memory>
#include <string>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/thread_task_runner_handle.h"
-#include "content/browser/renderer_host/media/audio_output_device_enumerator.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "media/audio/audio_manager_base.h"
#include "media/audio/fake_audio_log_factory.h"
@@ -118,7 +119,7 @@ class AudioOutputDeviceEnumeratorTest : public ::testing::Test {
}
protected:
- scoped_ptr<MockAudioManager> audio_manager_;
+ std::unique_ptr<MockAudioManager> audio_manager_;
TestBrowserThreadBundle thread_bundle_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::RunLoop run_loop_;
diff --git a/chromium/content/browser/renderer_host/media/audio_renderer_host.cc b/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
index d469d342433..20d5215bb5a 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -17,7 +17,6 @@
#include "content/browser/bad_message.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/media/audio_stream_monitor.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/media_internals.h"
@@ -31,7 +30,6 @@
#include "content/public/browser/media_device_id.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "media/audio/audio_device_name.h"
#include "media/audio/audio_manager_base.h"
@@ -51,34 +49,6 @@ namespace {
base::LazyInstance<media::AudioStreamsTracker> g_audio_streams_tracker =
LAZY_INSTANCE_INITIALIZER;
-// TODO(aiolos): This is a temporary hack until the resource scheduler is
-// migrated to RenderFrames for the Site Isolation project. It's called in
-// response to low frequency playback state changes. http://crbug.com/472869
-int RenderFrameIdToRenderViewId(int render_process_id, int render_frame_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RenderFrameHost* const frame =
- RenderFrameHost::FromID(render_process_id, render_frame_id);
- return frame ? frame->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE;
-}
-
-void NotifyResourceDispatcherOfAudioStateChange(int render_process_id,
- bool is_playing,
- int render_view_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
- return;
-
- ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
- render_process_id, render_view_id, is_playing);
-}
-
-media::AudioParameters DummyParams() {
- return media::AudioParameters(
- media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO,
- media::AudioParameters::kAudioCDSampleRate, 16,
- media::AudioParameters::kAudioCDSampleRate / 10);
-}
-
std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData(
int stream_id,
bool authorized,
@@ -118,7 +88,7 @@ bool IsDefaultDeviceId(const std::string& device_id) {
AudioOutputDeviceInfo GetDefaultDeviceInfoOnDeviceThread(
media::AudioManager* audio_manager) {
- DCHECK(audio_manager->GetWorkerTaskRunner()->BelongsToCurrentThread());
+ DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
AudioOutputDeviceInfo default_device_info = {
media::AudioManagerBase::kDefaultDeviceId,
audio_manager->GetDefaultDeviceName(),
@@ -147,7 +117,7 @@ void MaybeFixAudioParameters(media::AudioParameters* params) {
// If hardware parameters are still invalid, use dummy parameters with
// fake audio path and let the client handle the error.
if (!params->IsValid())
- *params = DummyParams();
+ *params = media::AudioParameters::UnavailableDeviceParams();
}
} // namespace
@@ -160,8 +130,8 @@ class AudioRendererHost::AudioEntry
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
- scoped_ptr<base::SharedMemory> shared_memory,
- scoped_ptr<media::AudioOutputController::SyncReader> reader);
+ std::unique_ptr<base::SharedMemory> shared_memory,
+ std::unique_ptr<media::AudioOutputController::SyncReader> reader);
~AudioEntry() override;
int stream_id() const {
@@ -197,10 +167,10 @@ class AudioRendererHost::AudioEntry
const int render_frame_id_;
// Shared memory for transmission of the audio data. Used by |reader_|.
- const scoped_ptr<base::SharedMemory> shared_memory_;
+ const std::unique_ptr<base::SharedMemory> shared_memory_;
// The synchronous reader to be used by |controller_|.
- const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
+ const std::unique_ptr<media::AudioOutputController::SyncReader> reader_;
// The AudioOutputController that manages the audio stream.
const scoped_refptr<media::AudioOutputController> controller_;
@@ -214,8 +184,8 @@ AudioRendererHost::AudioEntry::AudioEntry(
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
- scoped_ptr<base::SharedMemory> shared_memory,
- scoped_ptr<media::AudioOutputController::SyncReader> reader)
+ std::unique_ptr<base::SharedMemory> shared_memory,
+ std::unique_ptr<media::AudioOutputController::SyncReader> reader)
: host_(host),
stream_id_(stream_id),
render_frame_id_(render_frame_id),
@@ -450,7 +420,8 @@ void AudioRendererHost::OnRequestDeviceAuthorization(
if (!IsValidDeviceId(device_id)) {
Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, DummyParams()));
+ stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams()));
return;
}
@@ -505,7 +476,7 @@ void AudioRendererHost::OnDeviceAuthorized(int stream_id,
authorizations_.erase(auth_data);
Send(new AudioMsg_NotifyDeviceAuthorized(
stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
- DummyParams()));
+ media::AudioParameters::UnavailableDeviceParams()));
return;
}
@@ -517,7 +488,7 @@ void AudioRendererHost::OnDeviceAuthorized(int stream_id,
!media_stream_manager_->audio_output_device_enumerator()
->IsCacheEnabled()) {
base::PostTaskAndReplyWithResult(
- audio_manager_->GetWorkerTaskRunner().get(), FROM_HERE,
+ audio_manager_->GetTaskRunner().get(), FROM_HERE,
base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_),
base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id,
true));
@@ -544,7 +515,8 @@ void AudioRendererHost::OnDeviceIDTranslated(
if (!device_found) {
authorizations_.erase(auth_data);
Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, DummyParams()));
+ stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams()));
return;
}
@@ -592,13 +564,13 @@ void AudioRendererHost::DoCreateStream(int stream_id,
// Create the shared memory and share with the renderer process.
uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) +
AudioBus::CalculateMemorySize(params);
- scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
+ std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
SendErrorMessage(stream_id);
return;
}
- scoped_ptr<AudioSyncReader> reader(
+ std::unique_ptr<AudioSyncReader> reader(
new AudioSyncReader(shared_memory.get(), params));
if (!reader->Init()) {
SendErrorMessage(stream_id);
@@ -610,7 +582,7 @@ void AudioRendererHost::DoCreateStream(int stream_id,
if (media_observer)
media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
- scoped_ptr<AudioEntry> entry(
+ std::unique_ptr<AudioEntry> entry(
new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id,
std::move(shared_memory), std::move(reader)));
if (mirroring_manager_) {
@@ -684,7 +656,7 @@ void AudioRendererHost::OnCloseStream(int stream_id) {
AudioEntryMap::iterator i = audio_entries_.find(stream_id);
if (i == audio_entries_.end())
return;
- scoped_ptr<AudioEntry> entry(i->second);
+ std::unique_ptr<AudioEntry> entry(i->second);
audio_entries_.erase(i);
g_audio_streams_tracker.Get().DecreaseStreamCount();
@@ -694,7 +666,7 @@ void AudioRendererHost::OnCloseStream(int stream_id) {
audio_log_->OnClosed(stream_id);
}
-void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
+void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// De-register the controller from the AudioMirroringManager now that the
@@ -738,10 +710,7 @@ void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
if (entry->playing() == is_playing)
return;
- bool should_alert_resource_scheduler;
if (is_playing) {
- should_alert_resource_scheduler =
- !RenderFrameHasActiveAudio(entry->render_frame_id());
entry->set_playing(true);
base::AtomicRefCountInc(&num_playing_streams_);
@@ -755,9 +724,6 @@ void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
}
} else {
entry->set_playing(false);
- should_alert_resource_scheduler =
- !RenderFrameHasActiveAudio(entry->render_frame_id());
-
// Inform the RenderProcessHost when there is no more audio playing.
if (!base::AtomicRefCountDec(&num_playing_streams_)) {
BrowserThread::PostTask(
@@ -766,15 +732,6 @@ void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
render_process_id_));
}
}
-
- if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&RenderFrameIdToRenderViewId, render_process_id_,
- entry->render_frame_id()),
- base::Bind(&NotifyResourceDispatcherOfAudioStateChange,
- render_process_id_, is_playing));
- }
}
bool AudioRendererHost::HasActiveAudio() {
@@ -799,10 +756,9 @@ void AudioRendererHost::CheckOutputDeviceAccess(
const OutputDeviceAccessCB& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Skip origin check in requests for the default device with an empty
- // security origin.
- bool skip_origin_check = gurl_security_origin.is_empty() && device_id.empty();
- if (!skip_origin_check &&
+ // Check security origin if nondefault device is requested.
+ // Ignore check for default device, which is always authorized.
+ if (!IsDefaultDeviceId(device_id) &&
!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
render_process_id_, gurl_security_origin)) {
content::bad_message::ReceivedBadMessage(this,
@@ -815,7 +771,7 @@ void AudioRendererHost::CheckOutputDeviceAccess(
} else {
// Check that MediaStream device permissions have been granted,
// hence the use of a MediaStreamUIProxy.
- scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
// Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
// because MediaStreamUIProxy::CheckAccess does not currently support
@@ -829,9 +785,10 @@ void AudioRendererHost::CheckOutputDeviceAccess(
}
}
-void AudioRendererHost::AccessChecked(scoped_ptr<MediaStreamUIProxy> ui_proxy,
- const OutputDeviceAccessCB& callback,
- bool have_access) {
+void AudioRendererHost::AccessChecked(
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy,
+ const OutputDeviceAccessCB& callback,
+ bool have_access) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
callback.Run(have_access);
}
@@ -856,8 +813,9 @@ void AudioRendererHost::TranslateDeviceID(
}
}
DCHECK(!device_id.empty()); // Default device must always be found
- AudioOutputDeviceInfo device_info = {std::string(), std::string(),
- DummyParams()};
+ AudioOutputDeviceInfo device_info = {
+ std::string(), std::string(),
+ media::AudioParameters::UnavailableDeviceParams()};
callback.Run(false, device_info);
}
diff --git a/chromium/content/browser/renderer_host/media/audio_renderer_host.h b/chromium/content/browser/renderer_host/media/audio_renderer_host.h
index e549df20cc9..b4e9d3f329a 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.h
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.h
@@ -40,17 +40,17 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_RENDERER_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_RENDERER_HOST_H_
+#include <stddef.h>
+
#include <map>
+#include <memory>
#include <string>
#include <utility>
-#include <stddef.h>
-
#include "base/atomic_ref_count.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "base/sequenced_task_runner_helpers.h"
#include "content/browser/renderer_host/media/audio_output_device_enumerator.h"
@@ -203,7 +203,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Delete an audio entry, notifying observers first. This is called by
// AudioOutputController after it has closed.
- void DeleteEntry(scoped_ptr<AudioEntry> entry);
+ void DeleteEntry(std::unique_ptr<AudioEntry> entry);
// Send an error message to the renderer, then close the stream.
void ReportErrorAndClose(int stream_id);
@@ -223,7 +223,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
const OutputDeviceAccessCB& callback);
// Invoke |callback| after permission to use a device has been checked.
- void AccessChecked(scoped_ptr<MediaStreamUIProxy> ui_proxy,
+ void AccessChecked(std::unique_ptr<MediaStreamUIProxy> ui_proxy,
const OutputDeviceAccessCB& callback,
bool have_access);
@@ -242,7 +242,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
media::AudioManager* const audio_manager_;
AudioMirroringManager* const mirroring_manager_;
- scoped_ptr<media::AudioLog> audio_log_;
+ std::unique_ptr<media::AudioLog> audio_log_;
// Used to access to AudioInputDeviceManager.
MediaStreamManager* media_stream_manager_;
diff --git a/chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
index 396d9239507..3e3b4f3d40c 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
@@ -2,18 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/audio_renderer_host.h"
+
#include <stdint.h>
+#include <memory>
+
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/sync_socket.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
-#include "content/browser/renderer_host/media/audio_renderer_host.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/common/media/audio_messages.h"
#include "content/public/common/content_switches.h"
@@ -157,8 +159,8 @@ class MockAudioRendererHost : public AudioRendererHost {
}
}
- scoped_ptr<base::SharedMemory> shared_memory_;
- scoped_ptr<base::SyncSocket> sync_socket_;
+ std::unique_ptr<base::SharedMemory> shared_memory_;
+ std::unique_ptr<base::SyncSocket> sync_socket_;
uint32_t shared_memory_length_;
DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost);
@@ -217,7 +219,9 @@ class AudioRendererHostTest : public testing::Test {
}
protected:
- void Create() { Create(false, kDefaultDeviceId, url::Origin()); }
+ void Create() {
+ Create(false, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)));
+ }
void Create(bool unified_stream,
const std::string& device_id,
@@ -319,9 +323,9 @@ class AudioRendererHostTest : public testing::Test {
private:
// MediaStreamManager uses a DestructionObserver, so it must outlive the
// TestBrowserThreadBundle.
- scoped_ptr<MediaStreamManager> media_stream_manager_;
+ std::unique_ptr<MediaStreamManager> media_stream_manager_;
TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<media::AudioManager> audio_manager_;
+ std::unique_ptr<media::AudioManager> audio_manager_;
MockAudioMirroringManager mirroring_manager_;
scoped_refptr<MockAudioRendererHost> host_;
@@ -389,7 +393,7 @@ TEST_F(AudioRendererHostTest, SimulateErrorAndClose) {
}
TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) {
- Create(true, kDefaultDeviceId, url::Origin());
+ Create(true, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)));
Close();
}
diff --git a/chromium/content/browser/renderer_host/media/audio_sync_reader.cc b/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
index 85b13f8453c..af94822adae 100644
--- a/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -46,6 +46,7 @@ AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
packet_size_(shared_memory_->requested_size()),
renderer_callback_count_(0),
renderer_missed_callback_count_(0),
+ trailing_renderer_missed_callback_count_(0),
#if defined(OS_MACOSX)
maximum_wait_time_(params.GetBufferDuration() / 2),
#else
@@ -66,6 +67,24 @@ AudioSyncReader::~AudioSyncReader() {
if (!renderer_callback_count_)
return;
+ DVLOG(1) << "Trailing glitch count on destruction: "
+ << trailing_renderer_missed_callback_count_;
+
+ // Subtract 'trailing' count of callbacks missed just before the destructor
+ // call. This happens if the renderer process was killed or e.g. the page
+ // refreshed while the output device was open etc.
+ // This trims off the end of both the missed and total counts so that we
+ // preserve the proportion of counts before the teardown period.
+ DCHECK_LE(trailing_renderer_missed_callback_count_,
+ renderer_missed_callback_count_);
+ DCHECK_LE(trailing_renderer_missed_callback_count_, renderer_callback_count_);
+
+ renderer_missed_callback_count_ -= trailing_renderer_missed_callback_count_;
+ renderer_callback_count_ -= trailing_renderer_missed_callback_count_;
+
+ if (!renderer_callback_count_)
+ return;
+
// Recording the percentage of deadline misses gives us a rough overview of
// how many users might be running into audio glitches.
int percentage_missed =
@@ -107,6 +126,7 @@ void AudioSyncReader::UpdatePendingBytes(uint32_t bytes,
void AudioSyncReader::Read(AudioBus* dest) {
++renderer_callback_count_;
if (!WaitUntilDataIsReady()) {
+ ++trailing_renderer_missed_callback_count_;
++renderer_missed_callback_count_;
if (renderer_missed_callback_count_ <= 100) {
LOG(WARNING) << "AudioSyncReader::Read timed out, audio glitch count="
@@ -118,6 +138,8 @@ void AudioSyncReader::Read(AudioBus* dest) {
return;
}
+ trailing_renderer_missed_callback_count_ = 0;
+
if (mute_audio_)
dest->Zero();
else
diff --git a/chromium/content/browser/renderer_host/media/audio_sync_reader.h b/chromium/content/browser/renderer_host/media/audio_sync_reader.h
index 6e07e5129b6..05c68e9d2c1 100644
--- a/chromium/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/chromium/content/browser/renderer_host/media/audio_sync_reader.h
@@ -59,14 +59,14 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
const bool mute_audio_;
// Socket for transmitting audio data.
- scoped_ptr<base::CancelableSyncSocket> socket_;
+ std::unique_ptr<base::CancelableSyncSocket> socket_;
// Socket to be used by the renderer. The reference is released after
// PrepareForeignSocketHandle() is called and ran successfully.
- scoped_ptr<base::CancelableSyncSocket> foreign_socket_;
+ std::unique_ptr<base::CancelableSyncSocket> foreign_socket_;
// Shared memory wrapper used for transferring audio data to Read() callers.
- scoped_ptr<media::AudioBus> output_bus_;
+ std::unique_ptr<media::AudioBus> output_bus_;
// Maximum amount of audio data which can be transferred in one Read() call.
const int packet_size_;
@@ -75,6 +75,7 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
// report a UMA stat during destruction.
size_t renderer_callback_count_;
size_t renderer_missed_callback_count_;
+ size_t trailing_renderer_missed_callback_count_;
// The maximum amount of time to wait for data from the renderer. Calculated
// from the parameters given at construction.
diff --git a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 9fee099443a..0c18286db4f 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -288,7 +288,7 @@ class MediaStreamDispatcherHostTest : public testing::Test {
EXPECT_CALL(*stream_ui_, OnStarted(_, _));
}
media_stream_manager_->UseFakeUIForTests(
- scoped_ptr<FakeMediaStreamUIProxy>(stream_ui_));
+ std::unique_ptr<FakeMediaStreamUIProxy>(stream_ui_));
}
void GenerateStreamAndWaitForResult(int render_frame_id,
@@ -422,11 +422,11 @@ class MediaStreamDispatcherHostTest : public testing::Test {
}
scoped_refptr<MockMediaStreamDispatcherHost> host_;
- scoped_ptr<media::AudioManager> audio_manager_;
- scoped_ptr<MediaStreamManager> media_stream_manager_;
+ std::unique_ptr<media::AudioManager> audio_manager_;
+ std::unique_ptr<MediaStreamManager> media_stream_manager_;
MockMediaStreamUIProxy* stream_ui_;
ContentBrowserClient* old_browser_client_;
- scoped_ptr<ContentClient> content_client_;
+ std::unique_ptr<ContentClient> content_client_;
content::TestBrowserThreadBundle thread_bundle_;
content::TestBrowserContext browser_context_;
media::AudioDeviceNames physical_audio_devices_;
@@ -846,7 +846,8 @@ TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
StreamControls controls(false, true);
base::Closure close_callback;
- scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
+ std::unique_ptr<MockMediaStreamUIProxy> stream_ui(
+ new MockMediaStreamUIProxy());
EXPECT_CALL(*stream_ui, OnStarted(_, _))
.WillOnce(SaveArg<0>(&close_callback));
media_stream_manager_->UseFakeUIForTests(std::move(stream_ui));
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 f602e8d26b1..6d1f005d298 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
@@ -24,6 +24,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_local.h"
#include "build/build_config.h"
@@ -37,6 +38,7 @@
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/media_request_state.h"
#include "content/public/browser/render_process_host.h"
@@ -60,18 +62,15 @@
#include "chromeos/audio/cras_audio_handler.h"
#endif
+#if defined(OS_MACOSX)
+#include "media/capture/device_monitor_mac.h"
+#endif
+
namespace content {
base::LazyInstance<base::ThreadLocalPointer<MediaStreamManager>>::Leaky
g_media_stream_manager_tls_ptr = LAZY_INSTANCE_INITIALIZER;
-// Forward declaration of DeviceMonitorMac and its only useable method.
-class DeviceMonitorMac {
- public:
- void StartMonitoring(
- const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
-};
-
namespace {
// Creates a random label used to identify requests.
std::string RandomLabel() {
@@ -99,6 +98,9 @@ void ParseStreamType(const StreamControls& controls,
MediaStreamType* video_type) {
*audio_type = MEDIA_NO_SERVICE;
*video_type = MEDIA_NO_SERVICE;
+ const bool audio_support_flag_for_desktop_share =
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableAudioSupportForDesktopShare);
if (controls.audio.requested) {
if (!controls.audio.stream_source.empty()) {
// This is tab or screen capture.
@@ -106,6 +108,9 @@ void ParseStreamType(const StreamControls& controls,
*audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
} else if (controls.audio.stream_source == kMediaStreamSourceSystem) {
*audio_type = content::MEDIA_DESKTOP_AUDIO_CAPTURE;
+ } else if (audio_support_flag_for_desktop_share &&
+ controls.audio.stream_source == kMediaStreamSourceDesktop) {
+ *audio_type = content::MEDIA_DESKTOP_AUDIO_CAPTURE;
}
} else {
// This is normal audio device capture.
@@ -278,7 +283,7 @@ class MediaStreamManager::DeviceRequest {
}
bool HasUIRequest() const { return ui_request_.get() != nullptr; }
- scoped_ptr<MediaStreamRequest> DetachUIRequest() {
+ std::unique_ptr<MediaStreamRequest> DetachUIRequest() {
return std::move(ui_request_);
}
@@ -342,13 +347,13 @@ class MediaStreamManager::DeviceRequest {
// Currently it is only used by |DEVICE_ACCESS| type.
MediaStreamManager::MediaRequestResponseCallback callback;
- scoped_ptr<MediaStreamUIProxy> ui_proxy;
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy;
std::string tab_capture_device_id;
private:
std::vector<MediaRequestState> state_;
- scoped_ptr<MediaStreamRequest> ui_request_;
+ std::unique_ptr<MediaStreamRequest> ui_request_;
MediaStreamType audio_type_;
MediaStreamType video_type_;
int target_process_id_;
@@ -948,9 +953,9 @@ void MediaStreamManager::StartMonitoringOnUIThread() {
// fixed.
tracked_objects::ScopedTracker tracking_profile2(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "458404 MediaStreamManager::GetWorkerTaskRunner"));
+ "458404 MediaStreamManager::GetTaskRunner"));
const scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- audio_manager_->GetWorkerTaskRunner();
+ audio_manager_->GetTaskRunner();
// TODO(erikchen): Remove ScopedTracker below once crbug.com/458404 is
// fixed.
tracked_objects::ScopedTracker tracking_profile3(
@@ -1101,7 +1106,7 @@ void MediaStreamManager::DeleteRequest(const std::string& label) {
for (DeviceRequests::iterator request_it = requests_.begin();
request_it != requests_.end(); ++request_it) {
if (request_it->first == label) {
- scoped_ptr<DeviceRequest> request(request_it->second);
+ std::unique_ptr<DeviceRequest> request(request_it->second);
requests_.erase(request_it);
return;
}
@@ -1109,8 +1114,34 @@ void MediaStreamManager::DeleteRequest(const std::string& label) {
NOTREACHED();
}
-void MediaStreamManager::PostRequestToUI(const std::string& label,
- DeviceRequest* request) {
+void MediaStreamManager::ReadOutputParamsAndPostRequestToUI(
+ const std::string& label,
+ DeviceRequest* request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Actual audio parameters are required only for MEDIA_TAB_AUDIO_CAPTURE.
+ // TODO(guidou): MEDIA_TAB_AUDIO_CAPTURE should not be a special case. See
+ // crbug.com/584287.
+ if (request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE) {
+ // Read output parameters on the correct thread for native audio OS calls.
+ // Using base::Unretained is safe since |audio_manager_| is deleted after
+ // its task runner, and MediaStreamManager is deleted on the UI thread,
+ // after the IO thread has been stopped.
+ base::PostTaskAndReplyWithResult(
+ audio_manager_->GetTaskRunner().get(), FROM_HERE,
+ base::Bind(&media::AudioManager::GetDefaultOutputStreamParameters,
+ base::Unretained(audio_manager_)),
+ base::Bind(&MediaStreamManager::PostRequestToUI, base::Unretained(this),
+ label, request));
+ } else {
+ PostRequestToUI(label, request, media::AudioParameters());
+ }
+}
+
+void MediaStreamManager::PostRequestToUI(
+ const std::string& label,
+ DeviceRequest* request,
+ const media::AudioParameters& output_parameters) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(request->HasUIRequest());
DVLOG(1) << "PostRequestToUI({label= " << label << "})";
@@ -1124,7 +1155,10 @@ void MediaStreamManager::PostRequestToUI(const std::string& label,
if (IsVideoMediaType(video_type))
request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
- if (use_fake_ui_) {
+ // If using the fake UI, it will just auto-select from the available devices.
+ // The fake UI doesn't work for desktop sharing requests since we can't see
+ // its devices from here; always use the real UI for such requests.
+ if (use_fake_ui_ && request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE) {
if (!fake_ui_)
fake_ui_.reset(new FakeMediaStreamUIProxy());
@@ -1152,7 +1186,7 @@ void MediaStreamManager::PostRequestToUI(const std::string& label,
request->ui_proxy->RequestAccess(
request->DetachUIRequest(),
base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
- base::Unretained(this), label));
+ base::Unretained(this), label, output_parameters));
}
void MediaStreamManager::SetupRequest(const std::string& label) {
@@ -1221,7 +1255,7 @@ void MediaStreamManager::SetupRequest(const std::string& label) {
return;
}
}
- PostRequestToUI(label, request);
+ ReadOutputParamsAndPostRequestToUI(label, request);
}
bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
@@ -1314,7 +1348,11 @@ bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
}
}
- request->CreateUIRequest("", video_device_id);
+ const std::string audio_device_id =
+ request->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE ? video_device_id
+ : "";
+
+ request->CreateUIRequest(audio_device_id, video_device_id);
return true;
}
@@ -1527,7 +1565,7 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
"457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 1"));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!device_task_runner_.get());
- device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
+ device_task_runner_ = audio_manager_->GetTaskRunner();
// TODO(dalecurtis): Remove ScopedTracker below once crbug.com/457525 is
// fixed.
@@ -1728,7 +1766,7 @@ void MediaStreamManager::DevicesEnumerated(
if (!SetupDeviceCaptureRequest(request))
FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
else
- PostRequestToUI(label, request);
+ ReadOutputParamsAndPostRequestToUI(label, request);
break;
}
}
@@ -1754,7 +1792,7 @@ void MediaStreamManager::OnResume() {
}
void MediaStreamManager::UseFakeUIForTests(
- scoped_ptr<FakeMediaStreamUIProxy> fake_ui) {
+ std::unique_ptr<FakeMediaStreamUIProxy> fake_ui) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
use_fake_ui_ = true;
fake_ui_ = std::move(fake_ui);
@@ -1775,21 +1813,14 @@ void MediaStreamManager::UnregisterNativeLogCallback(int renderer_host_id) {
}
void MediaStreamManager::AddLogMessageOnIOThread(const std::string& message) {
- // Get render process ids on the IO thread.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- for (const LabeledDeviceRequest& labeled_request : requests_) {
- DeviceRequest* const request = labeled_request.second;
- if (request->request_type == MEDIA_GENERATE_STREAM) {
- const auto& found = log_callbacks_.find(request->requesting_process_id);
- if (found != log_callbacks_.end())
- found->second.Run(message);
- }
- }
+ for (const auto& callback : log_callbacks_)
+ callback.second.Run(message);
}
void MediaStreamManager::HandleAccessRequestResponse(
const std::string& label,
+ const media::AudioParameters& output_parameters,
const MediaStreamDevices& devices,
content::MediaStreamRequestResult result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -1824,29 +1855,27 @@ void MediaStreamManager::HandleAccessRequestResponse(
if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
device_info.device.id = request->tab_capture_device_id;
+ }
- // Initialize the sample_rate and channel_layout here since for audio
- // mirroring, we don't go through EnumerateDevices where these are usually
- // initialized.
- if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
- const media::AudioParameters parameters =
- audio_manager_->GetDefaultOutputStreamParameters();
- int sample_rate = parameters.sample_rate();
- // If we weren't able to get the native sampling rate or the sample_rate
- // is outside the valid range for input devices set reasonable defaults.
- if (sample_rate <= 0 || sample_rate > 96000)
- sample_rate = 44100;
-
- device_info.device.input.sample_rate = sample_rate;
- device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
- }
+ // Initialize the sample_rate and channel_layout here since for audio
+ // mirroring, we don't go through EnumerateDevices where these are usually
+ // initialized.
+ if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE ||
+ device_info.device.type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) {
+ int sample_rate = output_parameters.sample_rate();
+ // If we weren't able to get the native sampling rate or the sample_rate
+ // is outside the valid range for input devices set reasonable defaults.
+ if (sample_rate <= 0 || sample_rate > 96000)
+ sample_rate = 44100;
+
+ device_info.device.input.sample_rate = sample_rate;
+ device_info.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
}
- if (device_info.device.type == request->audio_type()) {
+ if (device_info.device.type == request->audio_type())
found_audio = true;
- } else if (device_info.device.type == request->video_type()) {
+ else if (device_info.device.type == request->video_type())
found_video = true;
- }
// If this is request for a new MediaStream, a device is only opened once
// per render frame. This is so that the permission to use a device can be
@@ -2016,15 +2045,27 @@ void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
if (!window_id)
return;
- // Pass along for desktop capturing. Ignored for other stream types.
- if (video_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
- for (const StreamDeviceInfo& device_info : devices ) {
- if (device_info.device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
- video_capture_manager_->SetDesktopCaptureWindowId(
- device_info.session_id, window_id);
- break;
- }
- }
+ if (video_type != MEDIA_DESKTOP_VIDEO_CAPTURE)
+ return;
+
+ // Pass along for desktop screen and window capturing when
+ // DesktopCaptureDevice is used.
+ for (const StreamDeviceInfo& device_info : devices) {
+ if (device_info.device.type != MEDIA_DESKTOP_VIDEO_CAPTURE)
+ continue;
+
+ DesktopMediaID media_id = DesktopMediaID::Parse(device_info.device.id);
+ // WebContentsVideoCaptureDevice is used for tab/webcontents.
+ if (media_id.type == DesktopMediaID::TYPE_WEB_CONTENTS)
+ continue;
+#if defined(USE_AURA)
+ // DesktopCaptureDevicAura is used when aura_id is valid.
+ if (media_id.aura_id > DesktopMediaID::kNullId)
+ continue;
+#endif
+ video_capture_manager_->SetDesktopCaptureWindowId(device_info.session_id,
+ window_id);
+ break;
}
}
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager.h b/chromium/content/browser/renderer_host/media/media_stream_manager.h
index 21d4f2f4050..52c3fa71d44 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.h
@@ -28,12 +28,12 @@
#include <list>
#include <map>
+#include <memory>
#include <string>
#include <utility>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_observer.h"
#include "base/system_monitor/system_monitor.h"
@@ -72,7 +72,7 @@ class CONTENT_EXPORT MediaStreamManager
public:
// Callback to deliver the result of a media request.
typedef base::Callback<void(const MediaStreamDevices& devices,
- scoped_ptr<MediaStreamUIProxy> ui)>
+ std::unique_ptr<MediaStreamUIProxy> ui)>
MediaRequestResponseCallback;
// Adds |message| to native logs for outstanding device requests, for use by
@@ -212,7 +212,7 @@ class CONTENT_EXPORT MediaStreamManager
// Called by the tests to specify a fake UI that should be used for next
// generated stream (or when using --use-fake-ui-for-media-stream).
- void UseFakeUIForTests(scoped_ptr<FakeMediaStreamUIProxy> fake_ui);
+ void UseFakeUIForTests(std::unique_ptr<FakeMediaStreamUIProxy> fake_ui);
// Register and unregister a new callback for receiving native log entries.
// The registered callback will be invoked on the IO thread.
@@ -265,9 +265,12 @@ class CONTENT_EXPORT MediaStreamManager
void NotifyDevicesChanged(MediaStreamType stream_type,
const StreamDeviceInfoArray& devices);
- void HandleAccessRequestResponse(const std::string& label,
- const MediaStreamDevices& devices,
- content::MediaStreamRequestResult result);
+ // |output_parameters| contains real values only if the request requires it.
+ void HandleAccessRequestResponse(
+ const std::string& label,
+ const media::AudioParameters& output_parameters,
+ const MediaStreamDevices& devices,
+ content::MediaStreamRequestResult result);
void StopMediaStreamFromBrowser(const std::string& label);
void DoEnumerateDevices(const std::string& label);
@@ -319,7 +322,12 @@ class CONTENT_EXPORT MediaStreamManager
bool SetupScreenCaptureRequest(DeviceRequest* request);
// Called when a request has been setup and devices have been enumerated if
// needed.
- void PostRequestToUI(const std::string& label, DeviceRequest* request);
+ void ReadOutputParamsAndPostRequestToUI(const std::string& label,
+ DeviceRequest* request);
+ // Called when audio output parameters have been read if needed.
+ void PostRequestToUI(const std::string& label,
+ DeviceRequest* request,
+ const media::AudioParameters& output_parameters);
// Returns true if a device with |device_id| has already been requested with
// a render procecss_id and render_frame_id and type equal to the the values
// in |request|. If it has been requested, |device_info| contain information
@@ -402,7 +410,7 @@ class CONTENT_EXPORT MediaStreamManager
media::AudioManager* const audio_manager_; // not owned
scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
scoped_refptr<VideoCaptureManager> video_capture_manager_;
- scoped_ptr<AudioOutputDeviceEnumerator> audio_output_device_enumerator_;
+ std::unique_ptr<AudioOutputDeviceEnumerator> audio_output_device_enumerator_;
#if defined(OS_WIN)
base::Thread video_capture_thread_;
#endif
@@ -423,7 +431,7 @@ class CONTENT_EXPORT MediaStreamManager
DeviceRequests requests_;
bool use_fake_ui_;
- scoped_ptr<FakeMediaStreamUIProxy> fake_ui_;
+ std::unique_ptr<FakeMediaStreamUIProxy> fake_ui_;
// Maps render process hosts to log callbacks. Used on the IO thread.
std::map<int, base::Callback<void(const std::string&)>> log_callbacks_;
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index 9f7fadb0755..9c606327c53 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -66,9 +66,8 @@ ResourceContext::SaltCallback GetMockSaltCallback() {
return base::Bind(&ReturnMockSalt);
}
-// This class mocks the audio manager and overrides the
-// GetAudioInputDeviceNames() method to ensure that we can run our tests on
-// the buildbots. media::AudioManagerBase
+// This class mocks the audio manager and overrides some methods to ensure that
+// we can run our tests on the buildbots.
class MockAudioManager : public AudioManagerPlatform {
public:
MockAudioManager()
@@ -103,6 +102,17 @@ class MockAudioManager : public AudioManagerPlatform {
}
}
+ media::AudioParameters GetDefaultOutputStreamParameters() override {
+ return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128);
+ }
+
+ media::AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) override {
+ return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128);
+ }
+
void SetNumAudioOutputDevices(size_t num_devices) {
num_output_devices_ = num_devices;
}
@@ -180,7 +190,7 @@ class MediaStreamManagerTest : public ::testing::Test {
MOCK_METHOD1(Response, void(int index));
void ResponseCallback(int index,
const MediaStreamDevices& devices,
- scoped_ptr<MediaStreamUIProxy> ui_proxy) {
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy) {
Response(index);
task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure());
}
@@ -200,8 +210,8 @@ class MediaStreamManagerTest : public ::testing::Test {
security_origin, callback);
}
- scoped_ptr<MockAudioManager> audio_manager_;
- scoped_ptr<MediaStreamManager> media_stream_manager_;
+ std::unique_ptr<MockAudioManager> audio_manager_;
+ std::unique_ptr<MediaStreamManager> media_stream_manager_;
content::TestBrowserThreadBundle thread_bundle_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::RunLoop run_loop_;
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
index f21618f484e..f0f93b476ad 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
@@ -70,10 +70,10 @@ class MediaStreamDeviceUIControllerTest
std::string());
}
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<BrowserThreadImpl> ui_thread_;
- scoped_ptr<BrowserThreadImpl> io_thread_;
- scoped_ptr<MediaStreamUIController> ui_controller_;
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<BrowserThreadImpl> ui_thread_;
+ std::unique_ptr<BrowserThreadImpl> io_thread_;
+ std::unique_ptr<MediaStreamUIController> ui_controller_;
private:
DISALLOW_COPY_AND_ASSIGN(MediaStreamDeviceUIControllerTest);
@@ -97,7 +97,7 @@ TEST_F(MediaStreamDeviceUIControllerTest, GenerateAndRemoveRequest) {
}
TEST_F(MediaStreamDeviceUIControllerTest, HandleRequestUsingFakeUI) {
- ui_controller_->UseFakeUI(scoped_ptr<MediaStreamUI>());
+ ui_controller_->UseFakeUI(std::unique_ptr<MediaStreamUI>());
const std::string label = "label";
CreateDummyRequest(label, true, true);
@@ -111,7 +111,7 @@ TEST_F(MediaStreamDeviceUIControllerTest, HandleRequestUsingFakeUI) {
}
TEST_F(MediaStreamDeviceUIControllerTest, CreateRequestsAndCancelTheFirst) {
- ui_controller_->UseFakeUI(scoped_ptr<MediaStreamUI>());
+ ui_controller_->UseFakeUI(std::unique_ptr<MediaStreamUI>());
// Create the first audio request.
const std::string label_1 = "label_1";
@@ -139,7 +139,7 @@ TEST_F(MediaStreamDeviceUIControllerTest, CreateRequestsAndCancelTheFirst) {
}
TEST_F(MediaStreamDeviceUIControllerTest, CreateRequestsAndCancelTheLast) {
- ui_controller_->UseFakeUI(scoped_ptr<MediaStreamUI>());
+ ui_controller_->UseFakeUI(std::unique_ptr<MediaStreamUI>());
// Create the first audio request.
const std::string label_1 = "label_1";
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
index 6cecbec2feb..79ae89de62a 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
@@ -45,7 +45,7 @@ class MediaStreamUIProxy::Core {
RenderFrameHostDelegate* test_render_delegate);
~Core();
- void RequestAccess(scoped_ptr<MediaStreamRequest> request);
+ void RequestAccess(std::unique_ptr<MediaStreamRequest> request);
bool CheckAccess(const GURL& security_origin,
MediaStreamType type,
int process_id,
@@ -55,13 +55,13 @@ class MediaStreamUIProxy::Core {
private:
void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
content::MediaStreamRequestResult result,
- scoped_ptr<MediaStreamUI> stream_ui);
+ std::unique_ptr<MediaStreamUI> stream_ui);
void ProcessStopRequestFromUI();
RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id,
int render_frame_id);
base::WeakPtr<MediaStreamUIProxy> proxy_;
- scoped_ptr<MediaStreamUI> ui_;
+ std::unique_ptr<MediaStreamUI> ui_;
RenderFrameHostDelegate* const test_render_delegate_;
@@ -84,7 +84,7 @@ MediaStreamUIProxy::Core::~Core() {
}
void MediaStreamUIProxy::Core::RequestAccess(
- scoped_ptr<MediaStreamRequest> request) {
+ std::unique_ptr<MediaStreamRequest> request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate(
@@ -94,7 +94,7 @@ void MediaStreamUIProxy::Core::RequestAccess(
if (!render_delegate) {
ProcessAccessRequestResponse(MediaStreamDevices(),
MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
- scoped_ptr<MediaStreamUI>());
+ std::unique_ptr<MediaStreamUI>());
return;
}
SetAndCheckAncestorFlag(request.get());
@@ -129,7 +129,7 @@ void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
const MediaStreamDevices& devices,
content::MediaStreamRequestResult result,
- scoped_ptr<MediaStreamUI> stream_ui) {
+ std::unique_ptr<MediaStreamUI> stream_ui) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ui_ = std::move(stream_ui);
@@ -158,14 +158,14 @@ RenderFrameHostDelegate* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate(
}
// static
-scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
- return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
+std::unique_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
+ return std::unique_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
}
// static
-scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
+std::unique_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
RenderFrameHostDelegate* render_delegate) {
- return scoped_ptr<MediaStreamUIProxy>(
+ return std::unique_ptr<MediaStreamUIProxy>(
new MediaStreamUIProxy(render_delegate));
}
@@ -181,7 +181,7 @@ MediaStreamUIProxy::~MediaStreamUIProxy() {
}
void MediaStreamUIProxy::RequestAccess(
- scoped_ptr<MediaStreamRequest> request,
+ std::unique_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -290,7 +290,7 @@ void FakeMediaStreamUIProxy::SetCameraAccess(bool access) {
}
void FakeMediaStreamUIProxy::RequestAccess(
- scoped_ptr<MediaStreamRequest> request,
+ std::unique_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h
index 0c2eaeae196..a89d35b87e3 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h
@@ -5,9 +5,10 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_UI_PROXY_H_
+#include <memory>
+
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/media_stream_request.h"
@@ -28,8 +29,8 @@ class CONTENT_EXPORT MediaStreamUIProxy {
typedef base::Callback<void(gfx::NativeViewId window_id)> WindowIdCallback;
- static scoped_ptr<MediaStreamUIProxy> Create();
- static scoped_ptr<MediaStreamUIProxy> CreateForTests(
+ static std::unique_ptr<MediaStreamUIProxy> Create();
+ static std::unique_ptr<MediaStreamUIProxy> CreateForTests(
RenderFrameHostDelegate* render_delegate);
virtual ~MediaStreamUIProxy();
@@ -38,7 +39,7 @@ class CONTENT_EXPORT MediaStreamUIProxy {
// WebContentsDelegate::RequestMediaAccessPermission(). The specified
// |response_callback| is called when the WebContentsDelegate approves or
// denies request.
- virtual void RequestAccess(scoped_ptr<MediaStreamRequest> request,
+ virtual void RequestAccess(std::unique_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback);
// Checks if we have permission to access the microphone or camera. Note that
@@ -78,7 +79,7 @@ class CONTENT_EXPORT MediaStreamUIProxy {
void OnCheckedAccess(const base::Callback<void(bool)>& callback,
bool have_access);
- scoped_ptr<Core, content::BrowserThread::DeleteOnUIThread> core_;
+ std::unique_ptr<Core, content::BrowserThread::DeleteOnUIThread> core_;
ResponseCallback response_callback_;
base::Closure stop_callback_;
@@ -97,7 +98,7 @@ class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy {
void SetCameraAccess(bool access);
// MediaStreamUIProxy overrides.
- void RequestAccess(scoped_ptr<MediaStreamRequest> request,
+ void RequestAccess(std::unique_ptr<MediaStreamRequest> request,
const ResponseCallback& response_callback) override;
void CheckAccess(const GURL& security_origin,
MediaStreamType type,
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index eae9607c600..a3ce7707d3d 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -72,7 +72,7 @@ class MediaStreamUIProxyTest : public testing::Test {
MockRenderFrameHostDelegate delegate_;
MockResponseCallback response_callback_;
- scoped_ptr<MediaStreamUIProxy> proxy_;
+ std::unique_ptr<MediaStreamUIProxy> proxy_;
};
MATCHER_P(SameRequest, expected, "") {
@@ -88,13 +88,10 @@ MATCHER_P(SameRequest, expected, "") {
}
TEST_F(MediaStreamUIProxyTest, Deny) {
- scoped_ptr<MediaStreamRequest> request (
- new MediaStreamRequest(0, 0, 0, GURL("http://origin/"),
- false,
- MEDIA_GENERATE_STREAM, std::string(),
- std::string(),
- MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE));
+ std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
+ 0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
+ std::string(), std::string(), MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@@ -108,7 +105,7 @@ TEST_F(MediaStreamUIProxyTest, Deny) {
ASSERT_FALSE(callback.is_null());
MediaStreamDevices devices;
- callback.Run(devices, MEDIA_DEVICE_OK, scoped_ptr<MediaStreamUI>());
+ callback.Run(devices, MEDIA_DEVICE_OK, std::unique_ptr<MediaStreamUI>());
MediaStreamDevices response;
EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _))
@@ -119,13 +116,10 @@ TEST_F(MediaStreamUIProxyTest, Deny) {
}
TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
- scoped_ptr<MediaStreamRequest> request (
- new MediaStreamRequest(0, 0, 0,
- GURL("http://origin/"), false,
- MEDIA_GENERATE_STREAM, std::string(),
- std::string(),
- MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE));
+ std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
+ 0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
+ std::string(), std::string(), MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@@ -141,7 +135,7 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
MediaStreamDevices devices;
devices.push_back(
MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic"));
- scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
+ std::unique_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(0));
callback.Run(devices, MEDIA_DEVICE_OK, std::move(ui));
@@ -158,13 +152,10 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
// Verify that the proxy can be deleted before the request is processed.
TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
- scoped_ptr<MediaStreamRequest> request (
- new MediaStreamRequest(0, 0, 0,
- GURL("http://origin/"), false,
- MEDIA_GENERATE_STREAM, std::string(),
- std::string(),
- MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE));
+ std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
+ 0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
+ std::string(), std::string(), MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@@ -180,18 +171,15 @@ TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
proxy_.reset();
MediaStreamDevices devices;
- scoped_ptr<MediaStreamUI> ui;
+ std::unique_ptr<MediaStreamUI> ui;
callback.Run(devices, MEDIA_DEVICE_OK, std::move(ui));
}
TEST_F(MediaStreamUIProxyTest, StopFromUI) {
- scoped_ptr<MediaStreamRequest> request (
- new MediaStreamRequest(0, 0, 0,
- GURL("http://origin/"), false,
- MEDIA_GENERATE_STREAM, std::string(),
- std::string(),
- MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE));
+ std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
+ 0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
+ std::string(), std::string(), MEDIA_DEVICE_AUDIO_CAPTURE,
+ MEDIA_DEVICE_VIDEO_CAPTURE));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
std::move(request),
@@ -209,7 +197,7 @@ TEST_F(MediaStreamUIProxyTest, StopFromUI) {
MediaStreamDevices devices;
devices.push_back(
MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic"));
- scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
+ std::unique_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_))
.WillOnce(testing::DoAll(SaveArg<0>(&stop_callback), Return(0)));
callback.Run(devices, MEDIA_DEVICE_OK, std::move(ui));
@@ -234,13 +222,10 @@ TEST_F(MediaStreamUIProxyTest, StopFromUI) {
}
TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
- scoped_ptr<MediaStreamRequest> request (
- new MediaStreamRequest(0, 0, 0,
- GURL("http://origin/"), false,
- MEDIA_GENERATE_STREAM, std::string(),
- std::string(),
- MEDIA_NO_SERVICE,
- MEDIA_DESKTOP_VIDEO_CAPTURE));
+ std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
+ 0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
+ std::string(), std::string(), MEDIA_NO_SERVICE,
+ MEDIA_DESKTOP_VIDEO_CAPTURE));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
@@ -254,7 +239,7 @@ TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
message_loop_.RunUntilIdle();
const int kWindowId = 1;
- scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
+ std::unique_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(kWindowId));
callback.Run(MediaStreamDevices(), MEDIA_DEVICE_OK, std::move(ui));
diff --git a/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc b/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc
index 41580ebe9c7..12f6edc96d1 100644
--- a/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc
+++ b/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc
@@ -4,7 +4,7 @@
#include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
#include "base/power_monitor/power_monitor.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/common/media/peer_connection_tracker_messages.h"
#include "content/public/browser/render_process_host.h"
diff --git a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc
index a934a40cf81..df4e70b92d8 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc
@@ -4,8 +4,10 @@
#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include <memory>
+
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "build/build_config.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
@@ -16,99 +18,31 @@ namespace content {
const int VideoCaptureBufferPool::kInvalidId = -1;
-// A simple holder of a memory-backed buffer and accessors to it.
-class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle {
- public:
- SimpleBufferHandle(void* data,
- size_t mapped_size,
- base::SharedMemoryHandle handle)
- : data_(data),
- mapped_size_(mapped_size)
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
- ,
- handle_(handle)
-#endif
- {
- }
- ~SimpleBufferHandle() override {}
-
- gfx::Size dimensions() const override {
- NOTREACHED();
- return gfx::Size();
- }
- size_t mapped_size() const override { return mapped_size_; }
- void* data(int plane) override {
- DCHECK_EQ(plane, 0);
- return data_;
- }
- ClientBuffer AsClientBuffer(int plane) override {
- NOTREACHED();
- return nullptr;
- }
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
- base::FileDescriptor AsPlatformFile() override {
- return handle_;
- }
-#endif
-
- private:
- void* const data_;
- const size_t mapped_size_;
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
- const base::SharedMemoryHandle handle_;
-#endif
-};
-
-// A holder of a GpuMemoryBuffer-backed buffer. Holds weak references to
-// GpuMemoryBuffer-backed buffers and provides accessors to their data.
-class GpuMemoryBufferBufferHandle final
- : public VideoCaptureBufferPool::BufferHandle {
- public:
- GpuMemoryBufferBufferHandle(const gfx::Size& dimensions,
- std::vector<
- scoped_ptr<gfx::GpuMemoryBuffer>>* gmbs)
- : dimensions_(dimensions), gmbs_(gmbs) {
- DCHECK(gmbs);
- }
- ~GpuMemoryBufferBufferHandle() override {}
-
- gfx::Size dimensions() const override { return dimensions_; }
- size_t mapped_size() const override { return dimensions_.GetArea(); }
- void* data(int plane) override {
- DCHECK_GE(plane, 0);
- DCHECK_LT(plane, static_cast<int>(gmbs_->size()));
- DCHECK((*gmbs_)[plane]);
- return (*gmbs_)[plane]->memory(0);
- }
- ClientBuffer AsClientBuffer(int plane) override {
- DCHECK_GE(plane, 0);
- DCHECK_LT(plane, static_cast<int>(gmbs_->size()));
- return (*gmbs_)[plane]->AsClientBuffer();
- }
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
- base::FileDescriptor AsPlatformFile() override {
- NOTREACHED();
- return base::FileDescriptor();
- }
-#endif
-
- private:
- const gfx::Size dimensions_;
- std::vector<scoped_ptr<gfx::GpuMemoryBuffer>>* const gmbs_;
-};
-
// Tracker specifics for SharedMemory.
class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
public:
- SharedMemTracker();
- bool Init(media::VideoPixelFormat format,
+ SharedMemTracker() : Tracker() {}
+
+ bool Init(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
- base::Lock* lock) override;
+ base::Lock* lock) override {
+ DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
+ set_dimensions(dimensions);
+ // |dimensions| can be 0x0 for trackers that do not require memory backing.
+ set_max_pixel_count(dimensions.GetArea());
+ set_pixel_format(format);
+ set_storage_type(storage_type);
+ mapped_size_ =
+ media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type)
+ .ImageAllocationSize();
+ if (!mapped_size_)
+ return true;
+ return shared_memory_.CreateAndMapAnonymous(mapped_size_);
+ }
- scoped_ptr<BufferHandle> GetBufferHandle() override {
- return make_scoped_ptr(new SimpleBufferHandle(
- shared_memory_.memory(), mapped_size_, shared_memory_.handle()));
+ std::unique_ptr<BufferHandle> GetBufferHandle() override {
+ return base::WrapUnique(new SharedMemBufferHandle(this));
}
bool ShareToProcess(base::ProcessHandle process_handle,
base::SharedMemoryHandle* new_handle) override {
@@ -122,6 +56,37 @@ class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
}
private:
+ // A simple proxy that implements the BufferHandle interface, providing
+ // accessors to SharedMemTracker's memory and properties.
+ class SharedMemBufferHandle : public VideoCaptureBufferPool::BufferHandle {
+ public:
+ // |tracker| must outlive SimpleBufferHandle. This is ensured since a
+ // tracker is pinned until ownership of this SimpleBufferHandle is returned
+ // to VideoCaptureBufferPool.
+ explicit SharedMemBufferHandle(SharedMemTracker* tracker)
+ : tracker_(tracker) {}
+ ~SharedMemBufferHandle() override {}
+
+ gfx::Size dimensions() const override { return tracker_->dimensions(); }
+ size_t mapped_size() const override { return tracker_->mapped_size_; }
+ void* data(int plane) override {
+ DCHECK_EQ(plane, 0);
+ return tracker_->shared_memory_.memory();
+ }
+ ClientBuffer AsClientBuffer(int plane) override {
+ NOTREACHED();
+ return nullptr;
+ }
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ base::FileDescriptor AsPlatformFile() override {
+ return tracker_->shared_memory_.handle();
+ }
+#endif
+
+ private:
+ SharedMemTracker* const tracker_;
+ };
+
// The memory created to be shared with renderer processes.
base::SharedMemory shared_memory_;
size_t mapped_size_;
@@ -131,151 +96,155 @@ class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
// associated pixel dimensions.
class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
public:
- GpuMemoryBufferTracker();
- bool Init(media::VideoPixelFormat format,
+ GpuMemoryBufferTracker() : Tracker() {}
+
+ ~GpuMemoryBufferTracker() override {
+ for (const auto& gmb : gpu_memory_buffers_)
+ gmb->Unmap();
+ }
+
+ bool Init(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
- base::Lock* lock) override;
- ~GpuMemoryBufferTracker() override;
+ base::Lock* lock) override {
+ DVLOG(2) << "allocating GMB for " << dimensions.ToString();
+ // BrowserGpuMemoryBufferManager::current() may not be accessed on IO
+ // Thread.
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(BrowserGpuMemoryBufferManager::current());
+ // This class is only expected to be called with I420 buffer requests at
+ // this point.
+ DCHECK_EQ(format, media::PIXEL_FORMAT_I420);
+ set_dimensions(dimensions);
+ set_max_pixel_count(dimensions.GetArea());
+ set_pixel_format(format);
+ set_storage_type(storage_type);
+ // |dimensions| can be 0x0 for trackers that do not require memory backing.
+ if (dimensions.GetArea() == 0u)
+ return true;
- scoped_ptr<BufferHandle> GetBufferHandle() override {
+ base::AutoUnlock auto_unlock(*lock);
+ const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format());
+ for (size_t i = 0; i < num_planes; ++i) {
+ const gfx::Size& size =
+ media::VideoFrame::PlaneSize(pixel_format(), i, dimensions);
+ gpu_memory_buffers_.push_back(
+ BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
+ size, gfx::BufferFormat::R_8,
+ gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, 0 /* surface_id */));
+
+ DLOG_IF(ERROR, !gpu_memory_buffers_[i]) << "Allocating GpuMemoryBuffer";
+ if (!gpu_memory_buffers_[i] || !gpu_memory_buffers_[i]->Map())
+ return false;
+ }
+ return true;
+ }
+
+ std::unique_ptr<BufferHandle> GetBufferHandle() override {
DCHECK_EQ(gpu_memory_buffers_.size(),
media::VideoFrame::NumPlanes(pixel_format()));
- return make_scoped_ptr(
- new GpuMemoryBufferBufferHandle(dimensions_, &gpu_memory_buffers_));
+ return base::WrapUnique(new GpuMemoryBufferBufferHandle(this));
}
+
bool ShareToProcess(base::ProcessHandle process_handle,
base::SharedMemoryHandle* new_handle) override {
NOTREACHED();
return false;
}
+
bool ShareToProcess2(int plane,
base::ProcessHandle process_handle,
- gfx::GpuMemoryBufferHandle* new_handle) override;
-
- private:
- gfx::Size dimensions_;
- // Owned references to GpuMemoryBuffers.
- std::vector<scoped_ptr<gfx::GpuMemoryBuffer>> gpu_memory_buffers_;
-};
-
-VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {}
-
-bool VideoCaptureBufferPool::SharedMemTracker::Init(
- media::VideoPixelFormat format,
- media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
- base::Lock* lock) {
- DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
- set_pixel_format(format);
- set_storage_type(storage_type);
- // |dimensions| can be 0x0 for trackers that do not require memory backing.
- set_pixel_count(dimensions.GetArea());
- mapped_size_ =
- media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type)
- .ImageAllocationSize();
- if (!mapped_size_)
- return true;
- return shared_memory_.CreateAndMapAnonymous(mapped_size_);
-}
-
-VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
- : Tracker() {
-}
-
-VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
- for (const auto& gmb : gpu_memory_buffers_)
- gmb->Unmap();
-}
-
-bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
- media::VideoPixelFormat format,
- media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
- base::Lock* lock) {
- DVLOG(2) << "allocating GMB for " << dimensions.ToString();
- // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(BrowserGpuMemoryBufferManager::current());
- // This class is only expected to be called with I420 buffer requests at this
- // point.
- DCHECK_EQ(format, media::PIXEL_FORMAT_I420);
- set_pixel_format(format);
- set_storage_type(storage_type);
- set_pixel_count(dimensions.GetArea());
- // |dimensions| can be 0x0 for trackers that do not require memory backing.
- if (dimensions.GetArea() == 0u)
+ gfx::GpuMemoryBufferHandle* new_handle) override {
+ DCHECK_LE(plane, static_cast<int>(gpu_memory_buffers_.size()));
+
+ const auto& current_gmb_handle = gpu_memory_buffers_[plane]->GetHandle();
+ switch (current_gmb_handle.type) {
+ case gfx::EMPTY_BUFFER:
+ NOTREACHED();
+ return false;
+ case gfx::SHARED_MEMORY_BUFFER: {
+ DCHECK(base::SharedMemory::IsHandleValid(current_gmb_handle.handle));
+ base::SharedMemory shared_memory(
+ base::SharedMemory::DuplicateHandle(current_gmb_handle.handle),
+ false);
+ shared_memory.ShareToProcess(process_handle, &new_handle->handle);
+ DCHECK(base::SharedMemory::IsHandleValid(new_handle->handle));
+ new_handle->type = gfx::SHARED_MEMORY_BUFFER;
+ return true;
+ }
+ case gfx::IO_SURFACE_BUFFER:
+ case gfx::SURFACE_TEXTURE_BUFFER:
+ case gfx::OZONE_NATIVE_PIXMAP:
+ *new_handle = current_gmb_handle;
+ return true;
+ }
+ NOTREACHED();
return true;
- dimensions_ = dimensions;
-
- lock->Release();
- const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format());
- for (size_t i = 0; i < num_planes; ++i) {
- const gfx::Size& size =
- media::VideoFrame::PlaneSize(pixel_format(), i, dimensions);
- gpu_memory_buffers_.push_back(
- BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
- size, gfx::BufferFormat::R_8,
- gfx::BufferUsage::GPU_READ_CPU_READ_WRITE));
-
- DLOG_IF(ERROR, !gpu_memory_buffers_[i]) << "Allocating GpuMemoryBuffer";
- if (!gpu_memory_buffers_[i] || !gpu_memory_buffers_[i]->Map())
- return false;
}
- lock->Acquire();
- return true;
-}
-bool VideoCaptureBufferPool::GpuMemoryBufferTracker::ShareToProcess2(
- int plane,
- base::ProcessHandle process_handle,
- gfx::GpuMemoryBufferHandle* new_handle) {
- DCHECK_LE(plane, static_cast<int>(gpu_memory_buffers_.size()));
-
- const auto& current_gmb_handle = gpu_memory_buffers_[plane]->GetHandle();
- switch (current_gmb_handle.type) {
- case gfx::EMPTY_BUFFER:
+ private:
+ // A simple proxy that implements the BufferHandle interface, providing
+ // accessors to GpuMemoryBufferTracker's memory and properties.
+ class GpuMemoryBufferBufferHandle
+ : public VideoCaptureBufferPool::BufferHandle {
+ public:
+ // |tracker| must outlive GpuMemoryBufferBufferHandle. This is ensured since
+ // a tracker is pinned until ownership of this GpuMemoryBufferBufferHandle
+ // is returned to VideoCaptureBufferPool.
+ explicit GpuMemoryBufferBufferHandle(GpuMemoryBufferTracker* tracker)
+ : tracker_(tracker) {}
+ ~GpuMemoryBufferBufferHandle() override {}
+
+ gfx::Size dimensions() const override { return tracker_->dimensions(); }
+ size_t mapped_size() const override {
+ return tracker_->dimensions().GetArea();
+ }
+ void* data(int plane) override {
+ DCHECK_GE(plane, 0);
+ DCHECK_LT(plane, static_cast<int>(tracker_->gpu_memory_buffers_.size()));
+ DCHECK(tracker_->gpu_memory_buffers_[plane]);
+ return tracker_->gpu_memory_buffers_[plane]->memory(0);
+ }
+ ClientBuffer AsClientBuffer(int plane) override {
+ DCHECK_GE(plane, 0);
+ DCHECK_LT(plane, static_cast<int>(tracker_->gpu_memory_buffers_.size()));
+ return tracker_->gpu_memory_buffers_[plane]->AsClientBuffer();
+ }
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ base::FileDescriptor AsPlatformFile() override {
NOTREACHED();
- return false;
- case gfx::SHARED_MEMORY_BUFFER: {
- DCHECK(base::SharedMemory::IsHandleValid(current_gmb_handle.handle));
- base::SharedMemory shared_memory(
- base::SharedMemory::DuplicateHandle(current_gmb_handle.handle),
- false);
- shared_memory.ShareToProcess(process_handle, &new_handle->handle);
- DCHECK(base::SharedMemory::IsHandleValid(new_handle->handle));
- new_handle->type = gfx::SHARED_MEMORY_BUFFER;
- return true;
+ return base::FileDescriptor();
}
- case gfx::IO_SURFACE_BUFFER:
- case gfx::SURFACE_TEXTURE_BUFFER:
- case gfx::OZONE_NATIVE_PIXMAP:
- *new_handle = current_gmb_handle;
- return true;
- }
- NOTREACHED();
- return true;
-}
+#endif
+
+ private:
+ GpuMemoryBufferTracker* const tracker_;
+ };
+
+ // Owned references to GpuMemoryBuffers.
+ std::vector<std::unique_ptr<gfx::GpuMemoryBuffer>> gpu_memory_buffers_;
+};
// static
-scoped_ptr<VideoCaptureBufferPool::Tracker>
+std::unique_ptr<VideoCaptureBufferPool::Tracker>
VideoCaptureBufferPool::Tracker::CreateTracker(
media::VideoPixelStorage storage) {
switch (storage) {
case media::PIXEL_STORAGE_GPUMEMORYBUFFER:
- return make_scoped_ptr(new GpuMemoryBufferTracker());
+ return base::WrapUnique(new GpuMemoryBufferTracker());
case media::PIXEL_STORAGE_CPU:
- return make_scoped_ptr(new SharedMemTracker());
+ return base::WrapUnique(new SharedMemTracker());
}
NOTREACHED();
- return scoped_ptr<VideoCaptureBufferPool::Tracker>();
+ return std::unique_ptr<VideoCaptureBufferPool::Tracker>();
}
VideoCaptureBufferPool::Tracker::~Tracker() {}
VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
: count_(count),
- next_buffer_id_(0) {
+ next_buffer_id_(0),
+ last_relinquished_buffer_id_(kInvalidId) {
DCHECK_GT(count, 0);
}
@@ -318,27 +287,26 @@ bool VideoCaptureBufferPool::ShareToProcess2(
return false;
}
-scoped_ptr<VideoCaptureBufferPool::BufferHandle>
+std::unique_ptr<VideoCaptureBufferPool::BufferHandle>
VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
base::AutoLock lock(lock_);
Tracker* tracker = GetTracker(buffer_id);
if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
- return scoped_ptr<BufferHandle>();
+ return std::unique_ptr<BufferHandle>();
}
DCHECK(tracker->held_by_producer());
return tracker->GetBufferHandle();
}
-int VideoCaptureBufferPool::ReserveForProducer(
- media::VideoPixelFormat format,
- media::VideoPixelStorage storage,
- const gfx::Size& dimensions,
- int* buffer_id_to_drop) {
+int VideoCaptureBufferPool::ReserveForProducer(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage,
+ int* buffer_id_to_drop) {
base::AutoLock lock(lock_);
- return ReserveForProducerInternal(format, storage, dimensions,
+ return ReserveForProducerInternal(dimensions, format, storage,
buffer_id_to_drop);
}
@@ -351,6 +319,7 @@ void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
}
DCHECK(tracker->held_by_producer());
tracker->set_held_by_producer(false);
+ last_relinquished_buffer_id_ = buffer_id;
}
void VideoCaptureBufferPool::HoldForConsumers(
@@ -385,6 +354,36 @@ void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
num_clients);
}
+int VideoCaptureBufferPool::ResurrectLastForProducer(
+ const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) {
+ base::AutoLock lock(lock_);
+
+ // Return early if the last relinquished buffer has been re-used already.
+ if (last_relinquished_buffer_id_ == kInvalidId)
+ return kInvalidId;
+
+ // If there are no consumers reading from this buffer, then it's safe to
+ // provide this buffer back to the producer (because the producer may
+ // potentially modify the content). Check that the expected dimensions,
+ // format, and storage match.
+ TrackerMap::iterator it = trackers_.find(last_relinquished_buffer_id_);
+ DCHECK(it != trackers_.end());
+ DCHECK(!it->second->held_by_producer());
+ if (it->second->consumer_hold_count() == 0 &&
+ it->second->dimensions() == dimensions &&
+ it->second->pixel_format() == format &&
+ it->second->storage_type() == storage) {
+ it->second->set_held_by_producer(true);
+ const int resurrected_buffer_id = last_relinquished_buffer_id_;
+ last_relinquished_buffer_id_ = kInvalidId;
+ return resurrected_buffer_id;
+ }
+
+ return kInvalidId;
+}
+
double VideoCaptureBufferPool::GetBufferPoolUtilization() const {
base::AutoLock lock(lock_);
int num_buffers_held = 0;
@@ -397,9 +396,9 @@ double VideoCaptureBufferPool::GetBufferPoolUtilization() const {
}
int VideoCaptureBufferPool::ReserveForProducerInternal(
+ const gfx::Size& dimensions,
media::VideoPixelFormat pixel_format,
media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
int* buffer_id_to_drop) {
lock_.AssertAcquired();
@@ -408,32 +407,50 @@ int VideoCaptureBufferPool::ReserveForProducerInternal(
// largest one that's not big enough, in case we have to reallocate a tracker.
*buffer_id_to_drop = kInvalidId;
size_t largest_size_in_pixels = 0;
+ TrackerMap::iterator tracker_of_last_resort = trackers_.end();
TrackerMap::iterator tracker_to_drop = trackers_.end();
for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
++it) {
Tracker* const tracker = it->second;
if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
- if (tracker->pixel_count() >= size_in_pixels &&
+ if (tracker->max_pixel_count() >= size_in_pixels &&
(tracker->pixel_format() == pixel_format) &&
(tracker->storage_type() == storage_type)) {
+ if (it->first == last_relinquished_buffer_id_) {
+ // This buffer would do just fine, but avoid returning it because the
+ // client may want to resurrect it. It will be returned perforce if
+ // the pool has reached it's maximum limit (see code below).
+ tracker_of_last_resort = it;
+ continue;
+ }
// Existing tracker is big enough and has correct format. Reuse it.
+ tracker->set_dimensions(dimensions);
tracker->set_held_by_producer(true);
return it->first;
}
- if (tracker->pixel_count() > largest_size_in_pixels) {
- largest_size_in_pixels = tracker->pixel_count();
+ if (tracker->max_pixel_count() > largest_size_in_pixels) {
+ largest_size_in_pixels = tracker->max_pixel_count();
tracker_to_drop = it;
}
}
}
// Preferably grow the pool by creating a new tracker. If we're at maximum
- // size, then reallocate by deleting an existing one instead.
+ // size, then try using |tracker_of_last_resort| or reallocate by deleting an
+ // existing one instead.
if (trackers_.size() == static_cast<size_t>(count_)) {
+ if (tracker_of_last_resort != trackers_.end()) {
+ last_relinquished_buffer_id_ = kInvalidId;
+ tracker_of_last_resort->second->set_dimensions(dimensions);
+ tracker_of_last_resort->second->set_held_by_producer(true);
+ return tracker_of_last_resort->first;
+ }
if (tracker_to_drop == trackers_.end()) {
// We're out of space, and can't find an unused tracker to reallocate.
return kInvalidId;
}
+ if (tracker_to_drop->first == last_relinquished_buffer_id_)
+ last_relinquished_buffer_id_ = kInvalidId;
*buffer_id_to_drop = tracker_to_drop->first;
delete tracker_to_drop->second;
trackers_.erase(tracker_to_drop);
@@ -442,10 +459,10 @@ int VideoCaptureBufferPool::ReserveForProducerInternal(
// Create the new tracker.
const int buffer_id = next_buffer_id_++;
- scoped_ptr<Tracker> tracker = Tracker::CreateTracker(storage_type);
+ std::unique_ptr<Tracker> tracker = Tracker::CreateTracker(storage_type);
// TODO(emircan): We pass the lock here to solve GMB allocation issue, see
// crbug.com/545238.
- if (!tracker->Init(pixel_format, storage_type, dimensions, &lock_)) {
+ if (!tracker->Init(dimensions, pixel_format, storage_type, &lock_)) {
DLOG(ERROR) << "Error initializing Tracker";
return kInvalidId;
}
diff --git a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
index c69a842a79b..ba92d4d4f86 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool.h
@@ -58,7 +58,7 @@ class CONTENT_EXPORT VideoCaptureBufferPool
virtual size_t mapped_size() const = 0;
virtual void* data(int plane) = 0;
virtual ClientBuffer AsClientBuffer(int plane) = 0;
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
virtual base::FileDescriptor AsPlatformFile() = 0;
#endif
};
@@ -76,7 +76,7 @@ class CONTENT_EXPORT VideoCaptureBufferPool
gfx::GpuMemoryBufferHandle* new_handle);
// Try and obtain a BufferHandle for |buffer_id|.
- scoped_ptr<BufferHandle> GetBufferHandle(int buffer_id);
+ std::unique_ptr<BufferHandle> GetBufferHandle(int buffer_id);
// Reserve or allocate a buffer to support a packed frame of |dimensions| of
// pixel |format| and return its id. This will fail (returning kInvalidId) if
@@ -91,9 +91,9 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// On occasion, this call will decide to free an old buffer to make room for a
// new allocation at a larger size. If so, the ID of the destroyed buffer is
// returned via |buffer_id_to_drop|.
- int ReserveForProducer(media::VideoPixelFormat format,
+ int ReserveForProducer(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
media::VideoPixelStorage storage,
- const gfx::Size& dimensions,
int* buffer_id_to_drop);
// Indicate that a buffer held for the producer should be returned back to the
@@ -111,6 +111,18 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// done, a buffer is returned to the pool for reuse.
void RelinquishConsumerHold(int buffer_id, int num_clients);
+ // Attempt to reserve the same buffer that was relinquished in the last call
+ // to RelinquishProducerReservation(). If the buffer is not still being
+ // consumed, and has not yet been re-used since being consumed, and the
+ // specified |dimensions|, |format|, and |storage| agree with its last
+ // reservation, this will succeed. Otherwise, |kInvalidId| will be returned.
+ //
+ // A producer may assume the content of the buffer has been preserved and may
+ // also make modifications.
+ int ResurrectLastForProducer(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage);
+
// Returns a snapshot of the current number of buffers in-use divided by the
// maximum |count_|.
double GetBufferPoolUtilization() const;
@@ -122,18 +134,23 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// Tracker carries indication of pixel format and storage type.
class Tracker {
public:
- static scoped_ptr<Tracker> CreateTracker(media::VideoPixelStorage storage);
+ static std::unique_ptr<Tracker> CreateTracker(
+ media::VideoPixelStorage storage);
Tracker()
- : pixel_count_(0), held_by_producer_(false), consumer_hold_count_(0) {}
- virtual bool Init(media::VideoPixelFormat format,
+ : max_pixel_count_(0),
+ held_by_producer_(false),
+ consumer_hold_count_(0) {}
+ virtual bool Init(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
media::VideoPixelStorage storage_type,
- const gfx::Size& dimensions,
base::Lock* lock) = 0;
virtual ~Tracker();
- size_t pixel_count() const { return pixel_count_; }
- void set_pixel_count(size_t count) { pixel_count_ = count; }
+ const gfx::Size& dimensions() const { return dimensions_; }
+ void set_dimensions(const gfx::Size& dim) { dimensions_ = dim; }
+ size_t max_pixel_count() const { return max_pixel_count_; }
+ void set_max_pixel_count(size_t count) { max_pixel_count_ = count; }
media::VideoPixelFormat pixel_format() const {
return pixel_format_;
}
@@ -151,7 +168,7 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// Returns a handle to the underlying storage, be that a block of Shared
// Memory, or a GpuMemoryBuffer.
- virtual scoped_ptr<BufferHandle> GetBufferHandle() = 0;
+ virtual std::unique_ptr<BufferHandle> GetBufferHandle() = 0;
virtual bool ShareToProcess(base::ProcessHandle process_handle,
base::SharedMemoryHandle* new_handle) = 0;
@@ -160,11 +177,17 @@ class CONTENT_EXPORT VideoCaptureBufferPool
gfx::GpuMemoryBufferHandle* new_handle) = 0;
private:
- size_t pixel_count_;
+ // |dimensions_| may change as a Tracker is re-used, but |max_pixel_count_|,
+ // |pixel_format_|, and |storage_type_| are set once for the lifetime of a
+ // Tracker.
+ gfx::Size dimensions_;
+ size_t max_pixel_count_;
media::VideoPixelFormat pixel_format_;
media::VideoPixelStorage storage_type_;
+
// Indicates whether this Tracker is currently referenced by the producer.
bool held_by_producer_;
+
// Number of consumer processes which hold this Tracker.
int consumer_hold_count_;
};
@@ -172,9 +195,9 @@ class CONTENT_EXPORT VideoCaptureBufferPool
friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
virtual ~VideoCaptureBufferPool();
- int ReserveForProducerInternal(media::VideoPixelFormat format,
+ int ReserveForProducerInternal(const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
media::VideoPixelStorage storage,
- const gfx::Size& dimensions,
int* tracker_id_to_drop);
Tracker* GetTracker(int buffer_id);
@@ -188,6 +211,10 @@ class CONTENT_EXPORT VideoCaptureBufferPool
// The ID of the next buffer.
int next_buffer_id_;
+ // The ID of the buffer last relinquished by the producer (a candidate for
+ // resurrection).
+ int last_relinquished_buffer_id_;
+
// The buffers, indexed by the first parameter, a buffer id.
using TrackerMap = std::map<int, Tracker*>;
TrackerMap trackers_;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
index 21c61326024..cb867b5900f 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
@@ -9,12 +9,15 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
+
+#include <memory>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "build/build_config.h"
#include "cc/test/test_context_provider.h"
@@ -102,11 +105,12 @@ class VideoCaptureBufferPoolTest
public:
StubBrowserGpuMemoryBufferManager() : BrowserGpuMemoryBufferManager(1, 1) {}
- scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
- gfx::BufferUsage usage) override {
- return make_scoped_ptr(new MockGpuMemoryBuffer(size));
+ gfx::BufferUsage usage,
+ int32_t surface_id) override {
+ return base::WrapUnique(new MockGpuMemoryBuffer(size));
}
};
class MockBufferQueue : public BufferQueue {
@@ -130,7 +134,7 @@ class VideoCaptureBufferPoolTest
class Buffer {
public:
Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
- scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
+ std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle,
int id)
: id_(id), pool_(pool), buffer_handle_(std::move(buffer_handle)) {}
~Buffer() { pool_->RelinquishProducerReservation(id()); }
@@ -141,7 +145,7 @@ class VideoCaptureBufferPoolTest
private:
const int id_;
const scoped_refptr<VideoCaptureBufferPool> pool_;
- const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
+ const std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
};
VideoCaptureBufferPoolTest()
@@ -165,8 +169,9 @@ class VideoCaptureBufferPoolTest
expected_dropped_id_ = expected_dropped_id;
}
- scoped_ptr<Buffer> ReserveBuffer(const gfx::Size& dimensions,
- PixelFormatAndStorage format_and_storage) {
+ std::unique_ptr<Buffer> ReserveBuffer(
+ const gfx::Size& dimensions,
+ PixelFormatAndStorage format_and_storage) {
// To verify that ReserveBuffer always sets |buffer_id_to_drop|,
// initialize it to something different than the expected value.
int buffer_id_to_drop = ~expected_dropped_id_;
@@ -175,26 +180,38 @@ class VideoCaptureBufferPoolTest
<< media::VideoPixelFormatToString(format_and_storage.pixel_format)
<< " " << dimensions.ToString();
const int buffer_id = pool_->ReserveForProducer(
- format_and_storage.pixel_format, format_and_storage.pixel_storage,
- dimensions, &buffer_id_to_drop);
+ dimensions, format_and_storage.pixel_format,
+ format_and_storage.pixel_storage, &buffer_id_to_drop);
if (buffer_id == VideoCaptureBufferPool::kInvalidId)
- return scoped_ptr<Buffer>();
+ return std::unique_ptr<Buffer>();
EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
- scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
+ std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle =
pool_->GetBufferHandle(buffer_id);
- return scoped_ptr<Buffer>(
+ return std::unique_ptr<Buffer>(
new Buffer(pool_, std::move(buffer_handle), buffer_id));
}
+ std::unique_ptr<Buffer> ResurrectLastBuffer(
+ const gfx::Size& dimensions,
+ PixelFormatAndStorage format_and_storage) {
+ const int buffer_id = pool_->ResurrectLastForProducer(
+ dimensions, format_and_storage.pixel_format,
+ format_and_storage.pixel_storage);
+ if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+ return std::unique_ptr<Buffer>();
+ return std::unique_ptr<Buffer>(
+ new Buffer(pool_, pool_->GetBufferHandle(buffer_id), buffer_id));
+ }
+
base::MessageLoop loop_;
int expected_dropped_id_;
scoped_refptr<VideoCaptureBufferPool> pool_;
private:
#if !defined(OS_ANDROID)
- scoped_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
- scoped_ptr<MockBufferQueue> output_surface_;
+ std::unique_ptr<StubBrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ std::unique_ptr<MockBufferQueue> output_surface_;
#endif
DISALLOW_COPY_AND_ASSIGN(VideoCaptureBufferPoolTest);
@@ -215,13 +232,13 @@ TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
// reserved.
ASSERT_EQ(0.0, pool_->GetBufferPoolUtilization());
- scoped_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
+ std::unique_ptr<Buffer> buffer1 = ReserveBuffer(size_lo, GetParam());
ASSERT_NE(nullptr, buffer1.get());
ASSERT_EQ(1.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
- scoped_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
+ std::unique_ptr<Buffer> buffer2 = ReserveBuffer(size_lo, GetParam());
ASSERT_NE(nullptr, buffer2.get());
ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
- scoped_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
+ std::unique_ptr<Buffer> buffer3 = ReserveBuffer(size_lo, GetParam());
ASSERT_NE(nullptr, buffer3.get());
ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
@@ -251,7 +268,7 @@ TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
// Release 1st buffer and retry; this should succeed.
buffer1.reset();
ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
- scoped_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
+ std::unique_ptr<Buffer> buffer4 = ReserveBuffer(size_lo, GetParam());
ASSERT_NE(nullptr, buffer4.get());
ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
@@ -371,6 +388,138 @@ TEST_P(VideoCaptureBufferPoolTest, BufferPool) {
buffer4.reset();
}
+// Tests that a previously-released buffer can be immediately resurrected under
+// normal conditions.
+TEST_P(VideoCaptureBufferPoolTest, ResurrectsLastBuffer) {
+ ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+
+ // At the start, there should be nothing to resurrect.
+ std::unique_ptr<Buffer> resurrected =
+ ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_EQ(nullptr, resurrected.get());
+
+ // Reserve a 10x10 buffer and fill it with 0xab values.
+ std::unique_ptr<Buffer> original =
+ ReserveBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, original.get());
+ const size_t original_mapped_size = original->mapped_size();
+ memset(original->data(), 0xab, original_mapped_size);
+
+ // Try to resurrect a buffer BEFORE releasing |original|. This should fail.
+ resurrected = ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_EQ(nullptr, resurrected.get());
+
+ // Release |original| and then try to resurrect it. Confirm the content of
+ // the resurrected buffer is a fill of 0xab values.
+ original.reset();
+ resurrected = ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, resurrected.get());
+ ASSERT_EQ(original_mapped_size, resurrected->mapped_size());
+ uint8_t* resurrected_memory = reinterpret_cast<uint8_t*>(resurrected->data());
+ for (size_t i = 0; i < original_mapped_size; ++i)
+ EXPECT_EQ(0xab, resurrected_memory[i]) << "Mismatch at byte offset: " << i;
+
+ // Now, fill the resurrected buffer with 0xbc values and release it.
+ memset(resurrected_memory, 0xbc, original_mapped_size);
+ resurrected.reset();
+
+ // Finally, resurrect the buffer again, and confirm it contains a fill of 0xbc
+ // values.
+ resurrected = ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, resurrected.get());
+ ASSERT_EQ(original_mapped_size, resurrected->mapped_size());
+ resurrected_memory = reinterpret_cast<uint8_t*>(resurrected->data());
+ for (size_t i = 0; i < original_mapped_size; ++i)
+ EXPECT_EQ(0xbc, resurrected_memory[i]) << "Mismatch at byte offset: " << i;
+}
+
+// Tests that a buffer cannot be resurrected if its properties do not match.
+TEST_P(VideoCaptureBufferPoolTest, DoesNotResurrectIfPropertiesNotMatched) {
+ ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+
+ // Reserve a 10x10 buffer, fill it with 0xcd values, and release it.
+ std::unique_ptr<Buffer> original =
+ ReserveBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, original.get());
+ const size_t original_mapped_size = original->mapped_size();
+ memset(original->data(), 0xcd, original_mapped_size);
+ original.reset();
+
+ // Expect that the buffer cannot be resurrected if the dimensions do not
+ // match.
+ std::unique_ptr<Buffer> resurrected =
+ ResurrectLastBuffer(gfx::Size(8, 8), GetParam());
+ ASSERT_EQ(nullptr, resurrected.get());
+
+ // Expect that the buffer cannot be resurrected if the pixel format does not
+ // match.
+ PixelFormatAndStorage altered_format_or_storage = GetParam();
+ altered_format_or_storage.pixel_format =
+ (altered_format_or_storage.pixel_format == media::PIXEL_FORMAT_I420
+ ? media::PIXEL_FORMAT_ARGB
+ : media::PIXEL_FORMAT_I420);
+ resurrected =
+ ResurrectLastBuffer(gfx::Size(10, 10), altered_format_or_storage);
+ ASSERT_EQ(nullptr, resurrected.get());
+
+ // Expect that the buffer cannot be resurrected if the pixel storage does not
+ // match.
+ altered_format_or_storage = GetParam();
+ altered_format_or_storage.pixel_storage =
+ (altered_format_or_storage.pixel_storage == media::PIXEL_STORAGE_CPU)
+ ? media::PIXEL_STORAGE_GPUMEMORYBUFFER
+ : media::PIXEL_STORAGE_CPU;
+ resurrected =
+ ResurrectLastBuffer(gfx::Size(10, 10), altered_format_or_storage);
+ ASSERT_EQ(nullptr, resurrected.get());
+
+ // Finally, check that the buffer CAN be resurrected if all properties match.
+ resurrected = ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, resurrected.get());
+ ASSERT_EQ(original_mapped_size, resurrected->mapped_size());
+ uint8_t* resurrected_memory = reinterpret_cast<uint8_t*>(resurrected->data());
+ for (size_t i = 0; i < original_mapped_size; ++i)
+ EXPECT_EQ(0xcd, resurrected_memory[i]) << "Mismatch at byte offset: " << i;
+}
+
+// Tests that the buffers are managed by the pool such that the last-released
+// buffer is kept around as long as possible (for successful resurrection).
+TEST_P(VideoCaptureBufferPoolTest, AvoidsClobberingForResurrectingLastBuffer) {
+ ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+
+ // Reserve a 10x10 buffer, fill it with 0xde values, and release it.
+ std::unique_ptr<Buffer> original =
+ ReserveBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, original.get());
+ const size_t original_mapped_size = original->mapped_size();
+ memset(original->data(), 0xde, original_mapped_size);
+ original.reset();
+
+ // Reserve all but one of the pool's buffers.
+ std::vector<std::unique_ptr<Buffer>> held_buffers;
+ for (int i = 0; i < kTestBufferPoolSize - 1; ++i) {
+ held_buffers.push_back(ReserveBuffer(gfx::Size(10, 10), GetParam()));
+ ASSERT_NE(nullptr, held_buffers.back().get());
+ }
+
+ // Now, attempt to resurrect the original buffer. This should succeed.
+ std::unique_ptr<Buffer> resurrected =
+ ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_NE(nullptr, resurrected.get());
+ ASSERT_EQ(original_mapped_size, resurrected->mapped_size());
+ uint8_t* resurrected_memory = reinterpret_cast<uint8_t*>(resurrected->data());
+ for (size_t i = 0; i < original_mapped_size; ++i)
+ EXPECT_EQ(0xde, resurrected_memory[i]) << "Mismatch at byte offset: " << i;
+ resurrected.reset();
+
+ // Reserve the final buffer in the pool, and then confirm resurrection does
+ // not succeed.
+ held_buffers.push_back(ReserveBuffer(gfx::Size(10, 10), GetParam()));
+ ASSERT_NE(nullptr, held_buffers.back().get());
+ resurrected = ResurrectLastBuffer(gfx::Size(10, 10), GetParam());
+ ASSERT_EQ(nullptr, resurrected.get());
+}
+
INSTANTIATE_TEST_CASE_P(,
VideoCaptureBufferPoolTest,
testing::ValuesIn(kCapturePixelFormatAndStorages));
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller.cc b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
index 6cde5f0d671..bad1a51a0ca 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
@@ -12,15 +12,16 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
#include "build/build_config.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
#include "content/browser/renderer_host/media/video_capture_device_client.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "media/base/video_frame.h"
@@ -141,10 +142,10 @@ VideoCaptureController::GetWeakPtrForIOThread() {
return weak_ptr_factory_.GetWeakPtr();
}
-scoped_ptr<media::VideoCaptureDevice::Client>
+std::unique_ptr<media::VideoCaptureDevice::Client>
VideoCaptureController::NewDeviceClient() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return make_scoped_ptr(new VideoCaptureDeviceClient(
+ return base::WrapUnique(new VideoCaptureDeviceClient(
this->GetWeakPtrForIOThread(), buffer_pool_));
}
@@ -260,14 +261,22 @@ int VideoCaptureController::GetClientCount() const {
return controller_clients_.size();
}
-int VideoCaptureController::GetActiveClientCount() const {
+bool VideoCaptureController::HasActiveClient() const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- int active_client_count = 0;
for (ControllerClient* client : controller_clients_) {
if (!client->paused)
- ++active_client_count;
+ return true;
}
- return active_client_count;
+ return false;
+}
+
+bool VideoCaptureController::HasPausedClient() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (ControllerClient* client : controller_clients_) {
+ if (client->paused)
+ return true;
+ }
+ return false;
}
void VideoCaptureController::StopSession(int session_id) {
@@ -344,7 +353,7 @@ VideoCaptureController::~VideoCaptureController() {
}
void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
const scoped_refptr<VideoFrame>& frame,
const base::TimeTicks& timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -357,7 +366,8 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE,
video_capture_format_.frame_rate);
}
- scoped_ptr<base::DictionaryValue> metadata(new base::DictionaryValue());
+ std::unique_ptr<base::DictionaryValue> metadata(
+ new base::DictionaryValue());
frame->metadata()->MergeInternalValuesInto(metadata.get());
// Only I420 pixel format is currently supported.
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller.h b/chromium/content/browser/renderer_host/media/video_capture_controller.h
index 66611445963..8baca918c99 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.h
@@ -41,11 +41,11 @@
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_H_
#include <list>
+#include <memory>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
@@ -71,7 +71,7 @@ class CONTENT_EXPORT VideoCaptureController {
// Return a new VideoCaptureDeviceClient to forward capture events to this
// instance.
- scoped_ptr<media::VideoCaptureDevice::Client> NewDeviceClient();
+ std::unique_ptr<media::VideoCaptureDevice::Client> NewDeviceClient();
// Start video capturing and try to use the resolution specified in |params|.
// Buffers will be shared to the client as necessary. The client will continue
@@ -99,8 +99,11 @@ class CONTENT_EXPORT VideoCaptureController {
int GetClientCount() const;
- // Return the number of clients that aren't paused.
- int GetActiveClientCount() const;
+ // Return true if there is client that isn't paused.
+ bool HasActiveClient() const;
+
+ // Return true if there is client paused.
+ bool HasPausedClient() const;
// API called directly by VideoCaptureManager in case the device is
// prematurely closed.
@@ -124,7 +127,7 @@ class CONTENT_EXPORT VideoCaptureController {
// Worker functions on IO thread. Called by the VideoCaptureDeviceClient.
virtual void DoIncomingCapturedVideoFrameOnIOThread(
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp);
virtual void DoErrorOnIOThread();
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
index e7d8d219012..3285de9c065 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
@@ -5,7 +5,8 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_CONTROLLER_EVENT_HANDLER_H_
-#include "base/memory/scoped_ptr.h"
+#include <memory>
+
#include "base/memory/shared_memory.h"
#include "content/common/content_export.h"
#include "ui/gfx/geometry/size.h"
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 99e563f50a1..0e28d307e9a 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -8,6 +8,8 @@
#include <stdint.h>
#include <string.h>
+
+#include <memory>
#include <string>
#include <utility>
@@ -16,7 +18,6 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
@@ -133,10 +134,10 @@ class VideoCaptureControllerTest : public testing::Test {
}
TestBrowserThreadBundle bundle_;
- scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_;
- scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_;
- scoped_ptr<VideoCaptureController> controller_;
- scoped_ptr<media::VideoCaptureDevice::Client> device_;
+ std::unique_ptr<MockVideoCaptureControllerEventHandler> client_a_;
+ std::unique_ptr<MockVideoCaptureControllerEventHandler> client_b_;
+ std::unique_ptr<VideoCaptureController> controller_;
+ std::unique_ptr<media::VideoCaptureDevice::Client> device_;
private:
DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
@@ -290,9 +291,8 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// side effect this will cause the first buffer to be shared with clients.
uint8_t buffer_no = 1;
ASSERT_EQ(0.0, device_->GetBufferPoolUtilization());
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
- device_->ReserveOutputBuffer(capture_resolution,
- media::PIXEL_FORMAT_I420,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU));
ASSERT_TRUE(buffer.get());
ASSERT_EQ(1.0 / kPoolSize, device_->GetBufferPoolUtilization());
@@ -331,6 +331,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
Mock::VerifyAndClearExpectations(client_b_.get());
+
// Expect VideoCaptureController set the metadata in |video_frame| to hold a
// resource utilization of 0.5 (the largest of all reported values).
double resource_utilization_in_metadata = -1.0;
@@ -342,9 +343,8 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Second buffer which ought to use the same shared memory buffer. In this
// case pretend that the Buffer pointer is held by the device for a long
// delay. This shouldn't affect anything.
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer2 =
- device_->ReserveOutputBuffer(capture_resolution,
- media::PIXEL_FORMAT_I420,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer2 =
+ device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
ASSERT_TRUE(buffer2.get());
memset(buffer2->data(), buffer_no++, buffer2->mapped_size());
@@ -359,15 +359,27 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
base::TimeTicks());
// The buffer should be delivered to the clients in any order.
- EXPECT_CALL(*client_a_,
- DoI420BufferReady(client_a_route_1, capture_resolution))
- .Times(1);
- EXPECT_CALL(*client_b_,
- DoI420BufferReady(client_b_route_1, capture_resolution))
- .Times(1);
- EXPECT_CALL(*client_a_,
- DoI420BufferReady(client_a_route_2, capture_resolution))
- .Times(1);
+ {
+ InSequence s;
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
+ EXPECT_CALL(*client_a_,
+ DoI420BufferReady(client_a_route_1, capture_resolution))
+ .Times(1);
+ }
+ {
+ InSequence s;
+ EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
+ EXPECT_CALL(*client_b_,
+ DoI420BufferReady(client_b_route_1, capture_resolution))
+ .Times(1);
+ }
+ {
+ InSequence s;
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
+ EXPECT_CALL(*client_a_,
+ DoI420BufferReady(client_a_route_2, capture_resolution))
+ .Times(1);
+ }
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
Mock::VerifyAndClearExpectations(client_b_.get());
@@ -389,7 +401,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
for (int i = 0; i < kPoolSize; i++) {
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
device_->ReserveOutputBuffer(capture_resolution,
media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
@@ -407,23 +419,24 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU).get());
- // The new client needs to be told of 3 buffers; the old clients only 2.
+ // The new client needs to be notified of the creation of |kPoolSize| buffers;
+ // the old clients only |kPoolSize - 2|.
EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
EXPECT_CALL(*client_b_,
DoI420BufferReady(client_b_route_2, capture_resolution))
.Times(kPoolSize);
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
- .Times(kPoolSize - 1);
+ .Times(kPoolSize - 2);
EXPECT_CALL(*client_a_,
DoI420BufferReady(client_a_route_1, capture_resolution))
.Times(kPoolSize);
EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
- .Times(kPoolSize - 1);
+ .Times(kPoolSize - 2);
EXPECT_CALL(*client_a_,
DoI420BufferReady(client_a_route_2, capture_resolution))
.Times(kPoolSize);
EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
- .Times(kPoolSize - 1);
+ .Times(kPoolSize - 2);
EXPECT_CALL(*client_b_,
DoI420BufferReady(client_b_route_1, capture_resolution))
.Times(kPoolSize);
@@ -438,9 +451,8 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
controller_->StopSession(300);
// Queue up another buffer.
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer3 =
- device_->ReserveOutputBuffer(capture_resolution,
- media::PIXEL_FORMAT_I420,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer3 =
+ device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
ASSERT_TRUE(buffer3.get());
memset(buffer3->data(), buffer_no++, buffer3->mapped_size());
@@ -450,9 +462,8 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
device_->OnIncomingCapturedVideoFrame(std::move(buffer3), video_frame,
base::TimeTicks());
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer4 =
- device_->ReserveOutputBuffer(capture_resolution,
- media::PIXEL_FORMAT_I420,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer4 =
+ device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
{
// Kill A2 via session close (posts a task to disconnect, but A2 must not
@@ -506,9 +517,8 @@ TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_b_.get());
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
- device_->ReserveOutputBuffer(capture_resolution,
- media::PIXEL_FORMAT_I420,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU));
ASSERT_TRUE(buffer.get());
scoped_refptr<media::VideoFrame> video_frame =
@@ -544,7 +554,7 @@ TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
Mock::VerifyAndClearExpectations(client_a_.get());
const gfx::Size dims(320, 240);
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
device_->ReserveOutputBuffer(dims, media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU));
ASSERT_TRUE(buffer.get());
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_client.cc b/chromium/content/browser/renderer_host/media/video_capture_device_client.cc
index b4d142e99ff..cf6ad3a9814 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_device_client.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_client.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -47,7 +48,7 @@ class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
ClientBuffer AsClientBuffer(int plane) override {
return buffer_handle_->AsClientBuffer(plane);
}
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
base::FileDescriptor AsPlatformFile() override {
return buffer_handle_->AsPlatformFile();
}
@@ -58,7 +59,7 @@ class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
const int id_;
const scoped_refptr<VideoCaptureBufferPool> pool_;
- const scoped_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
+ const std::unique_ptr<VideoCaptureBufferPool::BufferHandle> buffer_handle_;
};
VideoCaptureDeviceClient::VideoCaptureDeviceClient(
@@ -133,7 +134,7 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData(
use_gpu_memory_buffers_ ? media::PIXEL_STORAGE_GPUMEMORYBUFFER
: media::PIXEL_STORAGE_CPU;
uint8_t *y_plane_data, *u_plane_data, *v_plane_data;
- scoped_ptr<Buffer> buffer(
+ std::unique_ptr<Buffer> buffer(
ReserveI420OutputBuffer(dimensions, output_pixel_storage, &y_plane_data,
&u_plane_data, &v_plane_data));
if (!buffer.get()) {
@@ -188,10 +189,10 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData(
NOTREACHED() << "RGB24 is only available in Linux and Windows platforms";
#endif
#if defined(OS_WIN)
- // TODO(wjia): Currently, for RGB24 on WIN, capture device always
- // passes in positive src_width and src_height. Remove this hardcoded
- // value when nagative src_height is supported. The negative src_height
- // indicates that vertical flipping is needed.
+ // TODO(wjia): Currently, for RGB24 on WIN, capture device always passes
+ // in positive src_width and src_height. Remove this hardcoded value when
+ // negative src_height is supported. The negative src_height indicates
+ // that vertical flipping is needed.
flip = true;
#endif
break;
@@ -256,57 +257,7 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData(
OnIncomingCapturedBuffer(std::move(buffer), output_format, timestamp);
}
-void VideoCaptureDeviceClient::OnIncomingCapturedYuvData(
- const uint8_t* y_data,
- const uint8_t* u_data,
- const uint8_t* v_data,
- size_t y_stride,
- size_t u_stride,
- size_t v_stride,
- const VideoCaptureFormat& frame_format,
- int clockwise_rotation,
- const base::TimeTicks& timestamp) {
- TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedYuvData");
- DCHECK_EQ(media::PIXEL_FORMAT_I420, frame_format.pixel_format);
- DCHECK_EQ(media::PIXEL_STORAGE_CPU, frame_format.pixel_storage);
- DCHECK_EQ(0, clockwise_rotation) << "Rotation not supported";
-
- uint8_t *y_plane_data, *u_plane_data, *v_plane_data;
- scoped_ptr<Buffer> buffer(ReserveI420OutputBuffer(
- frame_format.frame_size, frame_format.pixel_storage, &y_plane_data,
- &u_plane_data, &v_plane_data));
- if (!buffer.get())
- return;
-
- const size_t dst_y_stride =
- VideoFrame::RowBytes(VideoFrame::kYPlane, media::PIXEL_FORMAT_I420,
- frame_format.frame_size.width());
- const size_t dst_u_stride =
- VideoFrame::RowBytes(VideoFrame::kUPlane, media::PIXEL_FORMAT_I420,
- frame_format.frame_size.width());
- const size_t dst_v_stride =
- VideoFrame::RowBytes(VideoFrame::kVPlane, media::PIXEL_FORMAT_I420,
- frame_format.frame_size.width());
- DCHECK_GE(y_stride, dst_y_stride);
- DCHECK_GE(u_stride, dst_u_stride);
- DCHECK_GE(v_stride, dst_v_stride);
-
- if (libyuv::I420Copy(y_data, y_stride,
- u_data, u_stride,
- v_data, v_stride,
- y_plane_data, dst_y_stride,
- u_plane_data, dst_u_stride,
- v_plane_data, dst_v_stride,
- frame_format.frame_size.width(),
- frame_format.frame_size.height())) {
- DLOG(WARNING) << "Failed to copy buffer";
- return;
- }
-
- OnIncomingCapturedBuffer(std::move(buffer), frame_format, timestamp);
-};
-
-scoped_ptr<media::VideoCaptureDevice::Client::Buffer>
+std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
VideoCaptureDeviceClient::ReserveOutputBuffer(
const gfx::Size& frame_size,
media::VideoPixelFormat pixel_format,
@@ -320,25 +271,21 @@ VideoCaptureDeviceClient::ReserveOutputBuffer(
// it's a ShMem GMB or a DmaBuf GMB.
int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;
const int buffer_id = buffer_pool_->ReserveForProducer(
- pixel_format, pixel_storage, frame_size, &buffer_id_to_drop);
- if (buffer_id == VideoCaptureBufferPool::kInvalidId)
- return NULL;
-
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
- new AutoReleaseBuffer(buffer_pool_, buffer_id));
-
+ frame_size, pixel_format, pixel_storage, &buffer_id_to_drop);
if (buffer_id_to_drop != VideoCaptureBufferPool::kInvalidId) {
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&VideoCaptureController::DoBufferDestroyedOnIOThread,
controller_, buffer_id_to_drop));
}
-
- return output_buffer;
+ if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+ return nullptr;
+ return base::WrapUnique<Buffer>(
+ new AutoReleaseBuffer(buffer_pool_, buffer_id));
}
void VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp) {
// Currently, only I420 pixel format is supported.
@@ -376,7 +323,7 @@ void VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
}
void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const scoped_refptr<VideoFrame>& frame,
const base::TimeTicks& timestamp) {
BrowserThread::PostTask(
@@ -390,6 +337,19 @@ void VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
timestamp));
}
+std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
+VideoCaptureDeviceClient::ResurrectLastOutputBuffer(
+ const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) {
+ const int buffer_id =
+ buffer_pool_->ResurrectLastForProducer(dimensions, format, storage);
+ if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+ return nullptr;
+ return base::WrapUnique<Buffer>(
+ new AutoReleaseBuffer(buffer_pool_, buffer_id));
+}
+
void VideoCaptureDeviceClient::OnError(
const tracked_objects::Location& from_here,
const std::string& reason) {
@@ -417,7 +377,7 @@ double VideoCaptureDeviceClient::GetBufferPoolUtilization() const {
return buffer_pool_->GetBufferPoolUtilization();
}
-scoped_ptr<media::VideoCaptureDevice::Client::Buffer>
+std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
VideoCaptureDeviceClient::ReserveI420OutputBuffer(
const gfx::Size& dimensions,
media::VideoPixelStorage storage,
@@ -430,10 +390,10 @@ VideoCaptureDeviceClient::ReserveI420OutputBuffer(
DCHECK(dimensions.width());
const media::VideoPixelFormat format = media::PIXEL_FORMAT_I420;
- scoped_ptr<Buffer> buffer(ReserveOutputBuffer(
- dimensions, media::PIXEL_FORMAT_I420, storage));
+ std::unique_ptr<Buffer> buffer(
+ ReserveOutputBuffer(dimensions, media::PIXEL_FORMAT_I420, storage));
if (!buffer)
- return scoped_ptr<Buffer>();
+ return std::unique_ptr<Buffer>();
switch (storage) {
case media::PIXEL_STORAGE_CPU:
@@ -459,7 +419,7 @@ VideoCaptureDeviceClient::ReserveI420OutputBuffer(
return buffer;
}
NOTREACHED();
- return scoped_ptr<Buffer>();
+ return std::unique_ptr<Buffer>();
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_client.h b/chromium/content/browser/renderer_host/media/video_capture_device_client.h
index 8215f5642a2..46a8d106da1 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_device_client.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_client.h
@@ -8,9 +8,10 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "media/capture/video/video_capture_device.h"
@@ -49,26 +50,21 @@ class CONTENT_EXPORT VideoCaptureDeviceClient
const media::VideoCaptureFormat& frame_format,
int rotation,
const base::TimeTicks& timestamp) override;
- void OnIncomingCapturedYuvData(const uint8_t* y_data,
- const uint8_t* u_data,
- const uint8_t* v_data,
- size_t y_stride,
- size_t u_stride,
- size_t v_stride,
- const media::VideoCaptureFormat& frame_format,
- int clockwise_rotation,
- const base::TimeTicks& timestamp) override;
- scoped_ptr<Buffer> ReserveOutputBuffer(
+ std::unique_ptr<Buffer> ReserveOutputBuffer(
const gfx::Size& dimensions,
media::VideoPixelFormat format,
media::VideoPixelStorage storage) override;
- void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
+ void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp) override;
void OnIncomingCapturedVideoFrame(
- scoped_ptr<Buffer> buffer,
+ std::unique_ptr<Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp) override;
+ std::unique_ptr<Buffer> ResurrectLastOutputBuffer(
+ const gfx::Size& dimensions,
+ media::VideoPixelFormat format,
+ media::VideoPixelStorage storage) override;
void OnError(const tracked_objects::Location& from_here,
const std::string& reason) override;
void OnLog(const std::string& message) override;
@@ -87,17 +83,18 @@ class CONTENT_EXPORT VideoCaptureDeviceClient
// GpuMemoryBuffers in R_8 format representing I420 planes are reserved. The
// output buffers stay reserved and mapped for use until the Buffer objects
// are destroyed or returned.
- scoped_ptr<Buffer> ReserveI420OutputBuffer(const gfx::Size& dimensions,
- media::VideoPixelStorage storage,
- uint8_t** y_plane_data,
- uint8_t** u_plane_data,
- uint8_t** v_plane_data);
+ std::unique_ptr<Buffer> ReserveI420OutputBuffer(
+ const gfx::Size& dimensions,
+ media::VideoPixelStorage storage,
+ uint8_t** y_plane_data,
+ uint8_t** u_plane_data,
+ uint8_t** v_plane_data);
// The controller to which we post events.
const base::WeakPtr<VideoCaptureController> controller_;
// Hardware JPEG decoder.
- scoped_ptr<VideoCaptureGpuJpegDecoder> external_jpeg_decoder_;
+ std::unique_ptr<VideoCaptureGpuJpegDecoder> external_jpeg_decoder_;
// Whether |external_jpeg_decoder_| has been initialized.
bool external_jpeg_decoder_initialized_;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_client_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
index 56c0a120345..d96b9d941a8 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
@@ -2,18 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/video_capture_device_client.h"
+
#include <stddef.h>
+#include <memory>
+
#include "base/bind.h"
+#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
#include "content/browser/renderer_host/media/video_capture_controller.h"
-#include "content/browser/renderer_host/media/video_capture_device_client.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "media/base/limits.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -41,7 +44,7 @@ class MockVideoCaptureController : public VideoCaptureController {
MOCK_METHOD1(DoBufferDestroyedOnIOThread, void(int buffer_id_to_drop));
void DoIncomingCapturedVideoFrameOnIOThread(
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
const scoped_refptr<media::VideoFrame>& frame,
const base::TimeTicks& timestamp) override {
MockDoIncomingCapturedVideoFrameOnIOThread(frame->coded_size());
@@ -60,8 +63,8 @@ class VideoCaptureDeviceClientTest : public ::testing::Test {
protected:
const content::TestBrowserThreadBundle thread_bundle_;
- const scoped_ptr<MockVideoCaptureController> controller_;
- const scoped_ptr<media::VideoCaptureDevice::Client> device_client_;
+ const std::unique_ptr<MockVideoCaptureController> controller_;
+ const std::unique_ptr<media::VideoCaptureDevice::Client> device_client_;
private:
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest);
@@ -79,6 +82,7 @@ TEST_F(VideoCaptureDeviceClientTest, Minimal) {
media::PIXEL_FORMAT_I420,
media::PIXEL_STORAGE_CPU);
DCHECK(device_client_.get());
+ EXPECT_CALL(*controller_, DoLogOnIOThread(_)).Times(1);
EXPECT_CALL(*controller_, MockDoIncomingCapturedVideoFrameOnIOThread(_))
.Times(1);
device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
@@ -100,6 +104,7 @@ TEST_F(VideoCaptureDeviceClientTest, FailsSilentlyGivenInvalidFrameFormat) {
media::VideoPixelStorage::PIXEL_STORAGE_CPU);
DCHECK(device_client_.get());
// Expect the the call to fail silently inside the VideoCaptureDeviceClient.
+ EXPECT_CALL(*controller_, DoLogOnIOThread(_)).Times(1);
EXPECT_CALL(*controller_, MockDoIncomingCapturedVideoFrameOnIOThread(_))
.Times(0);
device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
@@ -119,6 +124,7 @@ TEST_F(VideoCaptureDeviceClientTest, DropsFrameIfNoBuffer) {
media::PIXEL_STORAGE_CPU);
// We expect the second frame to be silently dropped, so these should
// only be called once despite the two frames.
+ EXPECT_CALL(*controller_, DoLogOnIOThread(_)).Times(1);
EXPECT_CALL(*controller_, MockDoIncomingCapturedVideoFrameOnIOThread(_))
.Times(1);
// Pass two frames. The second will be dropped.
@@ -132,39 +138,42 @@ TEST_F(VideoCaptureDeviceClientTest, DropsFrameIfNoBuffer) {
Mock::VerifyAndClearExpectations(controller_.get());
}
-// Tests that buffer-based capture API accepts all memory-backed pixel formats.
-TEST_F(VideoCaptureDeviceClientTest, DataCaptureInEachVideoFormatInSequence) {
+// Tests that buffer-based capture API accepts some memory-backed pixel formats.
+TEST_F(VideoCaptureDeviceClientTest, DataCaptureGoodPixelFormats) {
// The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
// be used since it does not accept all pixel formats. The memory backed
// buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
// buffer.
const size_t kScratchpadSizeInBytes = 400;
unsigned char data[kScratchpadSizeInBytes] = {};
- const gfx::Size capture_resolution(10, 10);
- ASSERT_GE(kScratchpadSizeInBytes, capture_resolution.GetArea() * 4u)
+ const gfx::Size kCaptureResolution(10, 10);
+ ASSERT_GE(kScratchpadSizeInBytes, kCaptureResolution.GetArea() * 4u)
<< "Scratchpad is too small to hold the largest pixel format (ARGB).";
- for (int format = 0; format < media::PIXEL_FORMAT_MAX;
- ++format) {
- // Conversion from some formats are unsupported.
- if (format == media::PIXEL_FORMAT_UNKNOWN ||
- format == media::PIXEL_FORMAT_YV16 ||
- format == media::PIXEL_FORMAT_YV12A ||
- format == media::PIXEL_FORMAT_YV24 ||
- format == media::PIXEL_FORMAT_ARGB ||
- format == media::PIXEL_FORMAT_XRGB ||
- format == media::PIXEL_FORMAT_MJPEG ||
- format == media::PIXEL_FORMAT_MT21) {
- continue;
- }
-#if !defined(OS_LINUX) && !defined(OS_WIN)
- if (format == media::PIXEL_FORMAT_RGB24){
- continue;
- }
+ media::VideoCaptureParams params;
+ params.requested_format = media::VideoCaptureFormat(
+ kCaptureResolution, 30.0f, media::PIXEL_FORMAT_UNKNOWN);
+
+ // Only use the VideoPixelFormats that we know supported. Do not add
+ // PIXEL_FORMAT_MJPEG since it would need a real JPEG header.
+ const media::VideoPixelFormat kSupportedFormats[] = {
+ media::PIXEL_FORMAT_I420,
+ media::PIXEL_FORMAT_YV12,
+ media::PIXEL_FORMAT_NV12,
+ media::PIXEL_FORMAT_NV21,
+ media::PIXEL_FORMAT_YUY2,
+ media::PIXEL_FORMAT_UYVY,
+#if defined(OS_WIN) || defined(OS_LINUX)
+ media::PIXEL_FORMAT_RGB24,
#endif
- media::VideoCaptureParams params;
- params.requested_format = media::VideoCaptureFormat(
- capture_resolution, 30.0f, media::VideoPixelFormat(format));
+ media::PIXEL_FORMAT_RGB32,
+ media::PIXEL_FORMAT_ARGB
+ };
+
+ for (media::VideoPixelFormat format : kSupportedFormats) {
+ params.requested_format.pixel_format = format;
+
+ EXPECT_CALL(*controller_, DoLogOnIOThread(_)).Times(1);
EXPECT_CALL(*controller_, MockDoIncomingCapturedVideoFrameOnIOThread(_))
.Times(1);
device_client_->OnIncomingCapturedData(
@@ -198,6 +207,8 @@ TEST_F(VideoCaptureDeviceClientTest, CheckRotationsAndCrops) {
const size_t kScratchpadSizeInBytes = 400;
unsigned char data[kScratchpadSizeInBytes] = {};
+ EXPECT_CALL(*controller_, DoLogOnIOThread(_)).Times(1);
+
media::VideoCaptureParams params;
for (const auto& size_and_rotation : kSizeAndRotations) {
ASSERT_GE(kScratchpadSizeInBytes,
diff --git a/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc b/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
index c48181acdb5..043587f39ef 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
@@ -16,10 +16,10 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
-#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "media/base/video_frame.h"
+#include "media/gpu/ipc/client/gpu_jpeg_decode_accelerator_host.h"
namespace content {
@@ -80,7 +80,7 @@ void VideoCaptureGpuJpegDecoder::DecodeCapturedData(
size_t in_buffer_size,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp,
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
DCHECK(CalledOnValidThread());
DCHECK(decoder_);
@@ -120,7 +120,7 @@ void VideoCaptureGpuJpegDecoder::DecodeCapturedData(
// Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
const gfx::Size dimensions = frame_format.frame_size;
base::SharedMemoryHandle out_handle = out_buffer->AsPlatformFile();
scoped_refptr<media::VideoFrame> out_frame =
@@ -209,7 +209,7 @@ void VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread(
base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- scoped_refptr<GpuChannelHost> gpu_channel_host(
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
BrowserGpuChannelHostFactory::instance()->GetGpuChannel());
task_runner->PostTask(
FROM_HERE, base::Bind(&VideoCaptureGpuJpegDecoder::FinishInitialization,
@@ -217,14 +217,28 @@ void VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread(
}
void VideoCaptureGpuJpegDecoder::FinishInitialization(
- scoped_refptr<GpuChannelHost> gpu_channel_host) {
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) {
+ TRACE_EVENT0("gpu", "VideoCaptureGpuJpegDecoder::FinishInitialization");
DCHECK(CalledOnValidThread());
base::AutoLock lock(lock_);
if (!gpu_channel_host) {
LOG(ERROR) << "Failed to establish GPU channel for JPEG decoder";
} else if (gpu_channel_host->gpu_info().jpeg_decode_accelerator_supported) {
gpu_channel_host_ = std::move(gpu_channel_host);
- decoder_ = gpu_channel_host_->CreateJpegDecoder(this);
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+ BrowserGpuChannelHostFactory::instance()->GetIOThreadTaskRunner();
+
+ int32_t route_id = gpu_channel_host_->GenerateRouteID();
+ std::unique_ptr<media::GpuJpegDecodeAcceleratorHost> decoder(
+ new media::GpuJpegDecodeAcceleratorHost(gpu_channel_host_.get(),
+ route_id, io_task_runner));
+ if (decoder->Initialize(this)) {
+ gpu_channel_host_->AddRouteWithTaskRunner(
+ route_id, decoder->GetReceiver(), io_task_runner);
+ decoder_ = std::move(decoder);
+ } else {
+ DLOG(ERROR) << "Failed to initialize JPEG decoder";
+ }
}
decoder_status_ = decoder_ ? INIT_PASSED : FAILED;
RecordInitDecodeUMA_Locked();
diff --git a/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h b/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
index 554cb104614..1650357ac94 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
@@ -8,12 +8,12 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
@@ -21,12 +21,15 @@
#include "media/capture/video/video_capture_device.h"
#include "media/video/jpeg_decode_accelerator.h"
+namespace gpu {
+class GpuChannelHost;
+}
+
namespace media {
class VideoFrame;
}
namespace content {
-class GpuChannelHost;
// Adapter to GpuJpegDecodeAccelerator for VideoCaptureDevice::Client. It takes
// care of GpuJpegDecodeAccelerator creation, shared memory, and threading
@@ -50,9 +53,10 @@ class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
};
typedef base::Callback<void(
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer>,
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>,
const scoped_refptr<media::VideoFrame>&,
- const base::TimeTicks&)> DecodeDoneCB;
+ const base::TimeTicks&)>
+ DecodeDoneCB;
// |decode_done_cb| is called on the IO thread when decode succeed. This can
// be on any thread. |decode_done_cb| is never called after
@@ -72,7 +76,7 @@ class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
size_t in_buffer_size,
const media::VideoCaptureFormat& frame_format,
const base::TimeTicks& timestamp,
- scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer);
+ std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer);
// JpegDecodeAccelerator::Client implementation.
// These will be called on IO thread.
@@ -90,7 +94,8 @@ class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this);
- void FinishInitialization(scoped_refptr<GpuChannelHost> gpu_channel_host);
+ void FinishInitialization(
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host);
// Returns true if the decoding of last frame is not finished yet.
bool IsDecoding_Locked() const;
@@ -98,10 +103,10 @@ class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
// Records |decoder_status_| to histogram.
void RecordInitDecodeUMA_Locked();
- scoped_refptr<GpuChannelHost> gpu_channel_host_;
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host_;
// The underlying JPEG decode accelerator.
- scoped_ptr<media::JpegDecodeAccelerator> decoder_;
+ std::unique_ptr<media::JpegDecodeAccelerator> decoder_;
// The callback to run when decode succeeds.
const DecodeDoneCB decode_done_cb_;
@@ -120,7 +125,7 @@ class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
// Shared memory to store JPEG stream buffer. The input BitstreamBuffer is
// backed by this.
- scoped_ptr<base::SharedMemory> in_shared_memory_;
+ std::unique_ptr<base::SharedMemory> in_shared_memory_;
STATUS decoder_status_;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host.cc b/chromium/content/browser/renderer_host/media/video_capture_host.cc
index ed3fea64858..46db2279ee5 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.cc
@@ -4,9 +4,10 @@
#include "content/browser/renderer_host/media/video_capture_host.h"
+#include <memory>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/memory/scoped_ptr.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
@@ -147,6 +148,8 @@ bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, OnResumeCapture)
+ IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_RequestRefreshFrame,
+ OnRequestRefreshFrame)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady,
OnRendererFinishedWithBuffer)
@@ -262,6 +265,22 @@ void VideoCaptureHost::OnResumeCapture(
}
}
+void VideoCaptureHost::OnRequestRefreshFrame(int device_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "VideoCaptureHost::OnRequestRefreshFrame, device_id "
+ << device_id;
+
+ VideoCaptureControllerID controller_id(device_id);
+ EntryMap::iterator it = entries_.find(controller_id);
+ if (it == entries_.end())
+ return;
+
+ if (VideoCaptureController* controller = it->second.get()) {
+ media_stream_manager_->video_capture_manager()
+ ->RequestRefreshFrameForClient(controller);
+ }
+}
+
void VideoCaptureHost::OnRendererFinishedWithBuffer(
int device_id,
int buffer_id,
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host.h b/chromium/content/browser/renderer_host/media/video_capture_host.h
index c35153f106b..800f562e16f 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.h
@@ -127,6 +127,10 @@ class CONTENT_EXPORT VideoCaptureHost
media::VideoCaptureSessionId session_id,
const media::VideoCaptureParams& params);
+ // IPC message: Requests that the video capture send a frame "soon" (e.g., to
+ // resolve picture loss or quality issues).
+ void OnRequestRefreshFrame(int device_id);
+
// IPC message: Called when a renderer is finished using a buffer. Notifies
// the controller.
void OnRendererFinishedWithBuffer(int device_id,
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc
index b1d991a95fe..933c58ddc75 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/renderer_host/media/video_capture_host.h"
+
#include <stdint.h>
#include <map>
+#include <memory>
#include <string>
#include "base/bind.h"
@@ -13,7 +16,6 @@
#include "base/files/scoped_file.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
@@ -24,7 +26,6 @@
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/media_stream_requester.h"
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
-#include "content/browser/renderer_host/media/video_capture_host.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/common/media/video_capture_messages.h"
#include "content/public/common/content_switches.h"
@@ -280,7 +281,7 @@ class VideoCaptureHostTest : public testing::Test {
#endif
media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
media_stream_manager_->UseFakeUIForTests(
- scoped_ptr<FakeMediaStreamUIProxy>());
+ std::unique_ptr<FakeMediaStreamUIProxy>());
// Create a Host and connect it to a simulated IPC channel.
host_ = new MockVideoCaptureHost(media_stream_manager_.get());
@@ -483,8 +484,8 @@ class VideoCaptureHostTest : public testing::Test {
private:
StrictMock<MockMediaStreamRequester> stream_requester_;
- scoped_ptr<media::AudioManager> audio_manager_;
- scoped_ptr<MediaStreamManager> media_stream_manager_;
+ std::unique_ptr<media::AudioManager> audio_manager_;
+ std::unique_ptr<MediaStreamManager> media_stream_manager_;
content::TestBrowserThreadBundle thread_bundle_;
content::TestBrowserContext browser_context_;
content::TestContentBrowserClient browser_client_;
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 dcee567489c..cf31a65f6d9 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
@@ -21,6 +21,7 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "build/build_config.h"
+#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
#include "content/browser/media/capture/web_contents_video_capture_device.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/renderer_host/media/video_capture_controller.h"
@@ -52,14 +53,22 @@ namespace {
// by the ConsolidateCaptureFormats() method.
bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
const media::VideoCaptureFormat& format2) {
- if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
+ DCHECK(format1.frame_size.GetCheckedArea().IsValid());
+ DCHECK(format2.frame_size.GetCheckedArea().IsValid());
+ if (format1.frame_size.GetCheckedArea().ValueOrDefault(0) ==
+ format2.frame_size.GetCheckedArea().ValueOrDefault(0)) {
return format1.frame_rate > format2.frame_rate;
- return format1.frame_size.GetArea() < format2.frame_size.GetArea();
+ }
+ return format1.frame_size.GetCheckedArea().ValueOrDefault(0) <
+ format2.frame_size.GetCheckedArea().ValueOrDefault(0);
}
bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
const media::VideoCaptureFormat& format2) {
- return format1.frame_size.GetArea() == format2.frame_size.GetArea();
+ DCHECK(format1.frame_size.GetCheckedArea().IsValid());
+ DCHECK(format2.frame_size.GetCheckedArea().IsValid());
+ return format1.frame_size.GetCheckedArea().ValueOrDefault(0) ==
+ format2.frame_size.GetCheckedArea().ValueOrDefault(0);
}
// This function receives a list of capture formats, removes duplicated
@@ -110,6 +119,8 @@ void LogVideoCaptureEvent(VideoCaptureEvent event) {
// Counter used for identifying a DeviceRequest to start a capture device.
static int g_device_start_id = 0;
+const media::VideoCaptureSessionId kFakeSessionId = -1;
+
} // namespace
namespace content {
@@ -117,10 +128,12 @@ namespace content {
VideoCaptureManager::DeviceEntry::DeviceEntry(
MediaStreamType stream_type,
const std::string& id,
- scoped_ptr<VideoCaptureController> controller)
+ std::unique_ptr<VideoCaptureController> controller,
+ const media::VideoCaptureParams& params)
: serial_id(g_device_start_id++),
stream_type(stream_type),
id(id),
+ parameters(params),
video_capture_controller_(std::move(controller)) {}
VideoCaptureManager::DeviceEntry::~DeviceEntry() {
@@ -132,12 +145,12 @@ VideoCaptureManager::DeviceEntry::~DeviceEntry() {
}
void VideoCaptureManager::DeviceEntry::SetVideoCaptureDevice(
- scoped_ptr<media::VideoCaptureDevice> device) {
+ std::unique_ptr<media::VideoCaptureDevice> device) {
DCHECK(thread_checker_.CalledOnValidThread());
video_capture_device_.swap(device);
}
-scoped_ptr<media::VideoCaptureDevice>
+std::unique_ptr<media::VideoCaptureDevice>
VideoCaptureManager::DeviceEntry::ReleaseVideoCaptureDevice() {
DCHECK(thread_checker_.CalledOnValidThread());
return std::move(video_capture_device_);
@@ -166,7 +179,7 @@ VideoCaptureManager::CaptureDeviceStartRequest::CaptureDeviceStartRequest(
}
VideoCaptureManager::VideoCaptureManager(
- scoped_ptr<media::VideoCaptureDeviceFactory> factory)
+ std::unique_ptr<media::VideoCaptureDeviceFactory> factory)
: listener_(NULL),
new_capture_session_id_(1),
video_capture_device_factory_(std::move(factory)) {}
@@ -184,6 +197,11 @@ void VideoCaptureManager::Register(
DCHECK(!device_task_runner_.get());
listener_ = listener;
device_task_runner_ = device_task_runner;
+#if defined(OS_ANDROID)
+ app_status_listener_.reset(new base::android::ApplicationStatusListener(
+ base::Bind(&VideoCaptureManager::OnApplicationStateChange,
+ base::Unretained(this))));
+#endif
}
void VideoCaptureManager::Unregister() {
@@ -208,17 +226,13 @@ void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
// Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
// for another callback to OnDevicesInfoEnumerated() to be run in the current
// loop, i.e. IO loop. Pass a timer for UMA histogram collection.
- base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>
- devices_enumerated_callback =
- base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread,
- this,
- media::BindToCurrentLoop(base::Bind(
- &VideoCaptureManager::OnDevicesInfoEnumerated,
- this,
- stream_type,
- base::Owned(new base::ElapsedTimer()))),
- stream_type,
- devices_info_cache_);
+ base::Callback<void(std::unique_ptr<media::VideoCaptureDevice::Names>)>
+ devices_enumerated_callback = base::Bind(
+ &VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread, this,
+ media::BindToCurrentLoop(
+ base::Bind(&VideoCaptureManager::OnDevicesInfoEnumerated, this,
+ stream_type, base::Owned(new base::ElapsedTimer()))),
+ stream_type, devices_info_cache_);
// OK to use base::Unretained() since we own the VCDFactory and |this| is
// bound in |devices_enumerated_callback|.
device_task_runner_->PostTask(FROM_HERE,
@@ -353,7 +367,7 @@ void VideoCaptureManager::HandleQueuedStartRequest() {
DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = "
<< entry->id << " start id = " << entry->serial_id;
- base::Callback<scoped_ptr<media::VideoCaptureDevice>(void)>
+ base::Callback<std::unique_ptr<media::VideoCaptureDevice>(void)>
start_capture_function;
switch (entry->stream_type) {
@@ -419,7 +433,7 @@ void VideoCaptureManager::HandleQueuedStartRequest() {
void VideoCaptureManager::OnDeviceStarted(
int serial_id,
- scoped_ptr<media::VideoCaptureDevice> device) {
+ std::unique_ptr<media::VideoCaptureDevice> device) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(serial_id == device_start_queue_.begin()->serial_id());
DVLOG(3) << "OnDeviceStarted";
@@ -450,6 +464,7 @@ void VideoCaptureManager::OnDeviceStarted(
if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
const media::VideoCaptureSessionId session_id =
device_start_queue_.front().session_id();
+ DCHECK(session_id != kFakeSessionId);
MaybePostDesktopCaptureWindowId(session_id);
}
}
@@ -458,15 +473,15 @@ void VideoCaptureManager::OnDeviceStarted(
HandleQueuedStartRequest();
}
-scoped_ptr<media::VideoCaptureDevice>
+std::unique_ptr<media::VideoCaptureDevice>
VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread(
const media::VideoCaptureDevice::Name& name,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
+ std::unique_ptr<media::VideoCaptureDevice::Client> device_client) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(IsOnDeviceThread());
- scoped_ptr<media::VideoCaptureDevice> video_capture_device;
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
video_capture_device = video_capture_device_factory_->Create(name);
if (!video_capture_device) {
@@ -478,15 +493,15 @@ VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread(
return video_capture_device;
}
-scoped_ptr<media::VideoCaptureDevice>
+std::unique_ptr<media::VideoCaptureDevice>
VideoCaptureManager::DoStartTabCaptureOnDeviceThread(
const std::string& id,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
+ std::unique_ptr<media::VideoCaptureDevice::Client> device_client) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(IsOnDeviceThread());
- scoped_ptr<media::VideoCaptureDevice> video_capture_device;
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
video_capture_device.reset(WebContentsVideoCaptureDevice::Create(id));
if (!video_capture_device) {
@@ -498,18 +513,26 @@ VideoCaptureManager::DoStartTabCaptureOnDeviceThread(
return video_capture_device;
}
-scoped_ptr<media::VideoCaptureDevice>
+std::unique_ptr<media::VideoCaptureDevice>
VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread(
const std::string& id,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
+ std::unique_ptr<media::VideoCaptureDevice::Client> device_client) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(IsOnDeviceThread());
- scoped_ptr<media::VideoCaptureDevice> video_capture_device;
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
#if defined(ENABLE_SCREEN_CAPTURE)
DesktopMediaID desktop_id = DesktopMediaID::Parse(id);
- if (!desktop_id.is_null()) {
+ if (desktop_id.is_null()) {
+ device_client->OnError(FROM_HERE, "Desktop media ID is null");
+ return nullptr;
+ }
+
+ if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
+ video_capture_device.reset(WebContentsVideoCaptureDevice::Create(id));
+ IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED);
+ } else {
#if defined(USE_AURA)
video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id);
#endif
@@ -539,7 +562,7 @@ void VideoCaptureManager::StartCaptureForClient(
<< ", request: "
<< media::VideoCaptureFormat::ToString(params.requested_format);
- DeviceEntry* entry = GetOrCreateDeviceEntry(session_id);
+ DeviceEntry* entry = GetOrCreateDeviceEntry(session_id, params);
if (!entry) {
done_cb.Run(base::WeakPtr<VideoCaptureController>());
return;
@@ -550,7 +573,8 @@ void VideoCaptureManager::StartCaptureForClient(
LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE);
// First client starts the device.
- if (entry->video_capture_controller()->GetActiveClientCount() == 0) {
+ if (!entry->video_capture_controller()->HasActiveClient() &&
+ !entry->video_capture_controller()->HasPausedClient()) {
DVLOG(1) << "VideoCaptureManager starting device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
QueueStartDevice(session_id, entry, params);
@@ -625,9 +649,6 @@ void VideoCaptureManager::PauseCaptureForClient(
return;
controller->PauseClient(client_id, client_handler);
- // Release the capture device if there are no more clients.
- if (!controller->GetActiveClientCount())
- DoStopDevice(entry);
}
void VideoCaptureManager::ResumeCaptureForClient(
@@ -650,15 +671,25 @@ void VideoCaptureManager::ResumeCaptureForClient(
if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
return;
- // We can't resume a capturing client, which will crash with Camera2 API.
- // Refer to crbug/514740 for more details.
- if (!controller->ResumeClient(client_id, client_handler))
- return;
- if (controller->GetActiveClientCount() != 1)
- return;
+ controller->ResumeClient(client_id, client_handler);
+}
+
+void VideoCaptureManager::RequestRefreshFrameForClient(
+ VideoCaptureController* controller) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // This is first active client, allocate the camera.
- QueueStartDevice(session_id, entry, params);
+ if (DeviceEntry* entry = GetDeviceEntryForController(controller)) {
+ if (media::VideoCaptureDevice* device = entry->video_capture_device()) {
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame,
+ // Unretained is safe to use here because |device| would be
+ // null if it was scheduled for shutdown and destruction,
+ // and because this task is guaranteed to run before the
+ // task that destroys the |device|.
+ base::Unretained(device)));
+ }
+ }
}
bool VideoCaptureManager::GetDeviceSupportedFormats(
@@ -756,7 +787,7 @@ void VideoCaptureManager::MaybePostDesktopCaptureWindowId(
}
void VideoCaptureManager::DoStopDeviceOnDeviceThread(
- scoped_ptr<media::VideoCaptureDevice> device) {
+ std::unique_ptr<media::VideoCaptureDevice> device) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
DCHECK(IsOnDeviceThread());
device->StopAndDeAllocate();
@@ -821,7 +852,7 @@ void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
on_devices_enumerated_callback,
MediaStreamType stream_type,
const media::VideoCaptureDeviceInfos& old_device_info_cache,
- scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
+ std::unique_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
DCHECK(IsOnDeviceThread());
// Construct |new_devices_info_cache| with the cached devices that are still
// present in the system, and remove their names from |names_snapshot|, so we
@@ -881,11 +912,9 @@ VideoCaptureManager::GetDeviceEntryForController(
void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Removal of the last active client stops the device. It is important to only
- // check active clients and not all clients, because otherwise this class gets
- // into a bad state and might crash next time VideoCaptureManager::Open() is
- // called.
- if (entry->video_capture_controller()->GetActiveClientCount() == 0) {
+ // Removal of the last client stops the device.
+ if (!entry->video_capture_controller()->HasActiveClient() &&
+ !entry->video_capture_controller()->HasPausedClient()) {
DVLOG(1) << "VideoCaptureManager stopping device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
@@ -902,7 +931,8 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
}
VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
- media::VideoCaptureSessionId capture_session_id) {
+ media::VideoCaptureSessionId capture_session_id,
+ const media::VideoCaptureParams& params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
SessionMap::iterator session_it = sessions_.find(capture_session_id);
@@ -922,10 +952,11 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
const int max_buffers = device_info.type == MEDIA_TAB_VIDEO_CAPTURE ?
kMaxNumberOfBuffersForTabCapture : kMaxNumberOfBuffers;
- scoped_ptr<VideoCaptureController> video_capture_controller(
+ std::unique_ptr<VideoCaptureController> video_capture_controller(
new VideoCaptureController(max_buffers));
- DeviceEntry* new_device = new DeviceEntry(
- device_info.type, device_info.id, std::move(video_capture_controller));
+ DeviceEntry* new_device =
+ new DeviceEntry(device_info.type, device_info.id,
+ std::move(video_capture_controller), params);
devices_.push_back(new_device);
return new_device;
}
@@ -978,4 +1009,49 @@ void VideoCaptureManager::InitializeCaptureDeviceApiOnUIThread(
}
#endif
+#if defined(OS_ANDROID)
+void VideoCaptureManager::OnApplicationStateChange(
+ base::android::ApplicationState state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
+ ResumeDevices();
+ } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) {
+ ReleaseDevices();
+ }
+}
+
+void VideoCaptureManager::ReleaseDevices() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ for (auto& entry : devices_) {
+ // Do not stop Content Video Capture devices, e.g. Tab or Screen capture.
+ if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
+ continue;
+
+ DoStopDevice(entry);
+ }
+}
+
+void VideoCaptureManager::ResumeDevices() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ for (auto& entry : devices_) {
+ // Do not resume Content Video Capture devices, e.g. Tab or Screen capture.
+ // Do not try to restart already running devices. A device will be running
+ // if the Application state changes from
+ // APPLICATION_STATE_HAS_RUNNING_ACTIVITIES
+ // ->APPLICATION_STATE_HAS_PAUSED_ACTIVITIES
+ // ->APPLICATION_STATE_HAS_RUNNING_ACTIVITIES
+ if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE ||
+ entry->video_capture_device())
+ continue;
+
+ // Session ID is only valid for Screen capture. So we can fake it to resume
+ // video capture devices here.
+ QueueStartDevice(kFakeSessionId, entry, entry->parameters);
+ }
+}
+#endif // defined(OS_ANDROID)
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager.h b/chromium/content/browser/renderer_host/media/video_capture_manager.h
index 6a5fc9c36f8..6e3e9561feb 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.h
@@ -35,6 +35,10 @@
#include "media/capture/video/video_capture_device_factory.h"
#include "media/capture/video/video_capture_device_info.h"
+#if defined(OS_ANDROID)
+#include "base/android/application_status_listener.h"
+#endif
+
namespace content {
class VideoCaptureController;
class VideoCaptureControllerEventHandler;
@@ -47,7 +51,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
void(const base::WeakPtr<VideoCaptureController>&)> DoneCB;
explicit VideoCaptureManager(
- scoped_ptr<media::VideoCaptureDeviceFactory> factory);
+ std::unique_ptr<media::VideoCaptureDeviceFactory> factory);
void Unregister();
@@ -112,6 +116,10 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
VideoCaptureControllerID client_id,
VideoCaptureControllerEventHandler* client_handler);
+ // Called by VideoCaptureHost to request a refresh frame from the video
+ // capture device.
+ void RequestRefreshFrameForClient(VideoCaptureController* controller);
+
// Retrieves all capture supported formats for a particular device. Returns
// false if the |capture_session_id| is not found. The supported formats are
// cached during device(s) enumeration, and depending on the underlying
@@ -174,7 +182,8 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// Finds a DeviceEntry entry for the indicated session, creating a fresh one
// if necessary. Returns NULL if the session id is invalid.
DeviceEntry* GetOrCreateDeviceEntry(
- media::VideoCaptureSessionId capture_session_id);
+ media::VideoCaptureSessionId capture_session_id,
+ const media::VideoCaptureParams& params);
// Finds the DeviceEntry that owns a particular controller pointer.
DeviceEntry* GetDeviceEntryForController(
@@ -190,7 +199,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
on_devices_enumerated_callback,
MediaStreamType stream_type,
const media::VideoCaptureDeviceInfos& old_device_info_cache,
- scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot);
+ std::unique_ptr<media::VideoCaptureDevice::Names> names_snapshot);
// Starting a capture device can take 1-2 seconds.
// To avoid multiple unnecessary start/stop commands to the OS, each start
@@ -202,7 +211,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
DeviceEntry* entry,
const media::VideoCaptureParams& params);
void OnDeviceStarted(int serial_id,
- scoped_ptr<media::VideoCaptureDevice> device);
+ std::unique_ptr<media::VideoCaptureDevice> device);
void DoStopDevice(DeviceEntry* entry);
void HandleQueuedStartRequest();
@@ -210,24 +219,26 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// VideoCaptureDevice is returned to the IO-thread and stored in
// a DeviceEntry in |devices_|. Ownership of |client| passes to
// the device.
- scoped_ptr<media::VideoCaptureDevice> DoStartDeviceCaptureOnDeviceThread(
+ std::unique_ptr<media::VideoCaptureDevice> DoStartDeviceCaptureOnDeviceThread(
const media::VideoCaptureDevice::Name& name,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> client);
+ std::unique_ptr<media::VideoCaptureDevice::Client> client);
- scoped_ptr<media::VideoCaptureDevice> DoStartTabCaptureOnDeviceThread(
+ std::unique_ptr<media::VideoCaptureDevice> DoStartTabCaptureOnDeviceThread(
const std::string& device_id,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> client);
+ std::unique_ptr<media::VideoCaptureDevice::Client> client);
- scoped_ptr<media::VideoCaptureDevice> DoStartDesktopCaptureOnDeviceThread(
+ std::unique_ptr<media::VideoCaptureDevice>
+ DoStartDesktopCaptureOnDeviceThread(
const std::string& device_id,
const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> client);
+ std::unique_ptr<media::VideoCaptureDevice::Client> client);
// Stops and destroys the VideoCaptureDevice held in
// |device|.
- void DoStopDeviceOnDeviceThread(scoped_ptr<media::VideoCaptureDevice> device);
+ void DoStopDeviceOnDeviceThread(
+ std::unique_ptr<media::VideoCaptureDevice> device);
media::VideoCaptureDeviceInfo* FindDeviceInfoById(
const std::string& id,
@@ -252,12 +263,26 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// Once initialization is done, and_then will be run on the IO thread.
void InitializeCaptureDeviceApiOnUIThread(const base::Closure& and_then);
- // Due to initialization issues with AVFoundation and QTKit on Mac, we need
+ // Due to initialization issues with AVFoundation on Mac, we need
// to make sure we initialize the APIs on the UI thread before we can reliably
// use them. This variable is only checked and set on the IO thread.
bool capture_device_api_initialized_ = false;
#endif
+#if defined(OS_ANDROID)
+ // On Android, we used to stop the video device when the host tab is hidden.
+ // This caused problems on some devices when the device was stopped and
+ // restarted quickly. See http://crbug/582295. Now instead, the device is
+ // only stopped when Chrome goes to background. When a tab is hidden, it will
+ // not receive video frames but the device is not stopped.
+ void OnApplicationStateChange(base::android::ApplicationState state);
+ void ReleaseDevices();
+ void ResumeDevices();
+
+ std::unique_ptr<base::android::ApplicationStatusListener>
+ app_status_listener_;
+#endif
+
// The message loop of media stream device thread, where VCD's live.
scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
@@ -283,25 +308,28 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
public:
DeviceEntry(MediaStreamType stream_type,
const std::string& id,
- scoped_ptr<VideoCaptureController> controller);
+ std::unique_ptr<VideoCaptureController> controller,
+ const media::VideoCaptureParams& params);
~DeviceEntry();
const int serial_id;
const MediaStreamType stream_type;
const std::string id;
+ const media::VideoCaptureParams parameters;
VideoCaptureController* video_capture_controller();
media::VideoCaptureDevice* video_capture_device();
- void SetVideoCaptureDevice(scoped_ptr<media::VideoCaptureDevice> device);
- scoped_ptr<media::VideoCaptureDevice> ReleaseVideoCaptureDevice();
+ void SetVideoCaptureDevice(
+ std::unique_ptr<media::VideoCaptureDevice> device);
+ std::unique_ptr<media::VideoCaptureDevice> ReleaseVideoCaptureDevice();
private:
// The controller.
- scoped_ptr<VideoCaptureController> video_capture_controller_;
+ std::unique_ptr<VideoCaptureController> video_capture_controller_;
// The capture device.
- scoped_ptr<media::VideoCaptureDevice> video_capture_device_;
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device_;
base::ThreadChecker thread_checker_;
};
@@ -340,7 +368,8 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// Device creation factory injected on construction from MediaStreamManager or
// from the test harness.
- scoped_ptr<media::VideoCaptureDeviceFactory> video_capture_device_factory_;
+ std::unique_ptr<media::VideoCaptureDeviceFactory>
+ video_capture_device_factory_;
// Local cache of the enumerated video capture devices' names and capture
// supported formats. A snapshot of the current devices and their capabilities
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 954544c6b62..222dc5d0744 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -4,19 +4,20 @@
// Unit test for VideoCaptureManager.
+#include "content/browser/renderer_host/media/video_capture_manager.h"
+
#include <stdint.h>
+#include <memory>
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
-#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/common/media/media_stream_options.h"
#include "media/capture/video/fake_video_capture_device_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -81,8 +82,9 @@ class VideoCaptureManagerTest : public testing::Test {
message_loop_.get()));
io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
message_loop_.get()));
- vcm_ = new VideoCaptureManager(scoped_ptr<media::VideoCaptureDeviceFactory>(
- new media::FakeVideoCaptureDeviceFactory()));
+ vcm_ = new VideoCaptureManager(
+ std::unique_ptr<media::VideoCaptureDeviceFactory>(
+ new media::FakeVideoCaptureDeviceFactory()));
video_capture_device_factory_ =
static_cast<media::FakeVideoCaptureDeviceFactory*>(
vcm_->video_capture_device_factory());
@@ -161,11 +163,11 @@ class VideoCaptureManagerTest : public testing::Test {
int next_client_id_;
std::map<VideoCaptureControllerID, VideoCaptureController*> controllers_;
scoped_refptr<VideoCaptureManager> vcm_;
- scoped_ptr<MockMediaStreamProviderListener> listener_;
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<BrowserThreadImpl> ui_thread_;
- scoped_ptr<BrowserThreadImpl> io_thread_;
- scoped_ptr<MockFrameObserver> frame_observer_;
+ std::unique_ptr<MockMediaStreamProviderListener> listener_;
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<BrowserThreadImpl> ui_thread_;
+ std::unique_ptr<BrowserThreadImpl> io_thread_;
+ std::unique_ptr<MockFrameObserver> frame_observer_;
media::FakeVideoCaptureDeviceFactory* video_capture_device_factory_;
private:
diff --git a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.cc b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.cc
index dc1e590cb70..c98d34a8f7e 100644
--- a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.cc
+++ b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
#include "content/common/media/webrtc_identity_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "net/base/net_errors.h"
diff --git a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
index 1a38a45f0fb..5314d577b68 100644
--- a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
@@ -5,7 +5,7 @@
#include <deque>
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
#include "content/browser/renderer_host/media/webrtc_identity_service_host.h"
#include "content/common/media/webrtc_identity_messages.h"
#include "content/public/test/mock_resource_context.h"
@@ -19,7 +19,9 @@ namespace content {
namespace {
-const char FAKE_URL[] = "http://fake.com";
+const char FAKE_URL[] = "http://www.fake.com";
+const char FAKE_SITE[] = "http://fake.com";
+const char OTHER_SITE[] = "https://other.com";
const char FAKE_FIRST_PARTY_URL[] = "http://fake.firstparty.com";
const char FAKE_IDENTITY_NAME[] = "fake identity";
const char FAKE_COMMON_NAME[] = "fake common name";
@@ -178,7 +180,7 @@ class WebRTCIdentityServiceHostTest : public ::testing::Test {
protected:
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_ptr<MockResourceContext> mock_resource_context_;
+ std::unique_ptr<MockResourceContext> mock_resource_context_;
scoped_refptr<MockWebRTCIdentityStore> store_;
scoped_refptr<WebRTCIdentityServiceHostForTest> host_;
};
@@ -231,12 +233,22 @@ TEST_F(WebRTCIdentityServiceHostTest, TestOnRequestFailed) {
TEST_F(WebRTCIdentityServiceHostTest, TestOriginAccessDenied) {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
- policy->Remove(FAKE_RENDERER_ID);
+ policy->LockToOrigin(FAKE_RENDERER_ID, GURL(OTHER_SITE));
SendRequestToHost();
VerifyRequestFailedMessage(net::ERR_ACCESS_DENIED);
}
+TEST_F(WebRTCIdentityServiceHostTest, TestOriginAccessAllowed) {
+ ChildProcessSecurityPolicyImpl* policy =
+ ChildProcessSecurityPolicyImpl::GetInstance();
+ policy->LockToOrigin(FAKE_RENDERER_ID, GURL(FAKE_SITE));
+
+ SendRequestToHost();
+ store_->RunCompletionCallback(net::OK, FAKE_CERTIFICATE, FAKE_PRIVATE_KEY);
+ VerifyIdentityReadyMessage(FAKE_CERTIFICATE, FAKE_PRIVATE_KEY);
+}
+
// Verifies that we do not crash if we try to cancel a completed request.
TEST_F(WebRTCIdentityServiceHostTest, TestCancelAfterRequestCompleted) {
SendRequestToHost();
diff --git a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.cc b/chromium/content/browser/renderer_host/memory_benchmark_message_filter.cc
deleted file mode 100644
index 9125a8c0873..00000000000
--- a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/memory_benchmark_message_filter.h"
-
-#include "build/build_config.h"
-#include "content/common/memory_benchmark_messages.h"
-
-#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
-
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-
-namespace content {
-
-MemoryBenchmarkMessageFilter::MemoryBenchmarkMessageFilter()
- : BrowserMessageFilter(MemoryBenchmarkMsgStart) {
-}
-
-bool MemoryBenchmarkMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MemoryBenchmarkMessageFilter, message)
- IPC_MESSAGE_HANDLER(MemoryBenchmarkHostMsg_HeapProfilerDump,
- OnHeapProfilerDump)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-MemoryBenchmarkMessageFilter::~MemoryBenchmarkMessageFilter() {
-}
-
-void MemoryBenchmarkMessageFilter::OnHeapProfilerDump(
- const std::string& reason) {
- ::HeapProfilerDump(reason.c_str());
-}
-
-} // namespace content
-
-#endif // defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
diff --git a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h b/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h
deleted file mode 100644
index 0bafa73b49e..00000000000
--- a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEMORY_BENCHMARK_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEMORY_BENCHMARK_MESSAGE_FILTER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class MemoryBenchmarkMessageFilter : public BrowserMessageFilter {
- public:
- MemoryBenchmarkMessageFilter();
-
- bool OnMessageReceived(const IPC::Message& message) override;
-
- private:
- ~MemoryBenchmarkMessageFilter() override;
-
- void OnHeapProfilerDump(const std::string& reason);
-
- DISALLOW_COPY_AND_ASSIGN(MemoryBenchmarkMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_MEMORY_BENCHMARK_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/renderer_host/native_web_keyboard_event_android.cc b/chromium/content/browser/renderer_host/native_web_keyboard_event_android.cc
index fb32d70ae08..696bb0de920 100644
--- a/chromium/content/browser/renderer_host/native_web_keyboard_event_android.cc
+++ b/chromium/content/browser/renderer_host/native_web_keyboard_event_android.cc
@@ -29,25 +29,46 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent()
skip_in_browser(false) {
}
-NativeWebKeyboardEvent::NativeWebKeyboardEvent(
- blink::WebInputEvent::Type type,
- int modifiers, double time_secs, int keycode, int scancode,
- int unicode_character, bool is_system_key)
- : WebKeyboardEvent(WebKeyboardEventBuilder::Build(
- type, modifiers, time_secs, keycode, scancode, unicode_character,
- is_system_key)) {
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type,
+ int modifiers,
+ double time_secs,
+ int keycode,
+ int scancode,
+ int unicode_character,
+ bool is_system_key)
+ : WebKeyboardEvent(WebKeyboardEventBuilder::Build(nullptr,
+ nullptr,
+ type,
+ modifiers,
+ time_secs,
+ keycode,
+ scancode,
+ unicode_character,
+ is_system_key)) {
os_event = NULL;
skip_in_browser = false;
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(
- jobject android_key_event, blink::WebInputEvent::Type type,
- int modifiers, double time_secs, int keycode, int scancode,
- int unicode_character, bool is_system_key)
- : WebKeyboardEvent(WebKeyboardEventBuilder::Build(
- type, modifiers, time_secs, keycode, scancode, unicode_character,
- is_system_key)) {
- os_event = NewGlobalRefForKeyEvent(android_key_event);
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& android_key_event,
+ blink::WebInputEvent::Type type,
+ int modifiers,
+ double time_secs,
+ int keycode,
+ int scancode,
+ int unicode_character,
+ bool is_system_key)
+ : WebKeyboardEvent(WebKeyboardEventBuilder::Build(env,
+ android_key_event,
+ type,
+ modifiers,
+ time_secs,
+ keycode,
+ scancode,
+ unicode_character,
+ is_system_key)) {
+ os_event = NewGlobalRefForKeyEvent(android_key_event.obj());
skip_in_browser = false;
}
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.cc b/chromium/content/browser/renderer_host/overscroll_controller.cc
index b622dc85338..34c631a56dd 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.cc
+++ b/chromium/content/browser/renderer_host/overscroll_controller.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
+#include "content/common/input/input_event_utils.h"
#include "content/public/browser/overscroll_configuration.h"
#include "content/public/common/content_switches.h"
@@ -19,6 +20,13 @@ bool IsScrollEndEffectEnabled() {
switches::kScrollEndEffect) == "1";
}
+bool IsGestureEventFromTouchpad(const blink::WebInputEvent& event) {
+ DCHECK(blink::WebInputEvent::isGestureEventType(event.type));
+ const blink::WebGestureEvent& gesture =
+ static_cast<const blink::WebGestureEvent&>(event);
+ return gesture.sourceDevice == blink::WebGestureDeviceTouchpad;
+}
+
} // namespace
namespace content {
@@ -28,18 +36,64 @@ OverscrollController::OverscrollController()
scroll_state_(STATE_UNKNOWN),
overscroll_delta_x_(0.f),
overscroll_delta_y_(0.f),
- delegate_(NULL) {
-}
+ delegate_(NULL),
+ use_gesture_wheel_scrolling_(UseGestureBasedWheelScrolling()) {}
OverscrollController::~OverscrollController() {
}
+bool OverscrollController::ShouldProcessEvent(
+ const blink::WebInputEvent& event) {
+ if (use_gesture_wheel_scrolling_) {
+ switch (event.type) {
+ case blink::WebInputEvent::MouseWheel:
+ return false;
+ case blink::WebInputEvent::GestureScrollBegin:
+ case blink::WebInputEvent::GestureScrollUpdate:
+ case blink::WebInputEvent::GestureScrollEnd: {
+ const blink::WebGestureEvent& gesture =
+ static_cast<const blink::WebGestureEvent&>(event);
+ if (gesture.sourceDevice == blink::WebGestureDeviceTouchpad)
+ return true;
+ blink::WebGestureEvent::ScrollUnits scrollUnits;
+ switch (event.type) {
+ case blink::WebInputEvent::GestureScrollBegin:
+ scrollUnits = gesture.data.scrollBegin.deltaHintUnits;
+ break;
+ case blink::WebInputEvent::GestureScrollUpdate:
+ scrollUnits = gesture.data.scrollUpdate.deltaUnits;
+ break;
+ case blink::WebInputEvent::GestureScrollEnd:
+ scrollUnits = gesture.data.scrollEnd.deltaUnits;
+ break;
+ default:
+ scrollUnits = blink::WebGestureEvent::Pixels;
+ break;
+ }
+
+ return scrollUnits == blink::WebGestureEvent::PrecisePixels;
+ }
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
+ if (!ShouldProcessEvent(event))
+ return false;
+
bool reset_scroll_state = false;
if (scroll_state_ != STATE_UNKNOWN ||
overscroll_delta_x_ || overscroll_delta_y_) {
switch (event.type) {
case blink::WebInputEvent::GestureScrollEnd:
+ // Avoid resetting the state on GestureScrollEnd generated
+ // from the touchpad since it is sent based on a timeout.
+ reset_scroll_state = !IsGestureEventFromTouchpad(event);
+ break;
+
case blink::WebInputEvent::GestureFlingStart:
reset_scroll_state = true;
break;
@@ -95,6 +149,9 @@ bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) {
void OverscrollController::ReceivedEventACK(const blink::WebInputEvent& event,
bool processed) {
+ if (!ShouldProcessEvent(event))
+ return;
+
if (processed) {
// If a scroll event is consumed by the page, i.e. some content on the page
// has been scrolled, then there is not going to be an overscroll gesture,
@@ -142,6 +199,13 @@ bool OverscrollController::DispatchEventCompletesAction (
event.type != blink::WebInputEvent::GestureFlingStart)
return false;
+ // Avoid completing the action on GestureScrollEnd generated
+ // from the touchpad since it is sent based on a timeout not
+ // when the user has stopped interacting.
+ if (event.type == blink::WebInputEvent::GestureScrollEnd &&
+ IsGestureEventFromTouchpad(event))
+ return false;
+
if (!delegate_)
return false;
@@ -199,6 +263,12 @@ bool OverscrollController::DispatchEventResetsState(
return !wheel.hasPreciseScrollingDeltas;
}
+ // Avoid resetting overscroll on GestureScrollBegin/End generated
+ // from the touchpad since it is sent based on a timeout.
+ case blink::WebInputEvent::GestureScrollBegin:
+ case blink::WebInputEvent::GestureScrollEnd:
+ return !IsGestureEventFromTouchpad(event);
+
case blink::WebInputEvent::GestureScrollUpdate:
case blink::WebInputEvent::GestureFlingCancel:
return false;
@@ -221,16 +291,15 @@ bool OverscrollController::ProcessEventForOverscroll(
break;
event_processed =
ProcessOverscroll(wheel.deltaX * wheel.accelerationRatioX,
- wheel.deltaY * wheel.accelerationRatioY,
- wheel.type);
+ wheel.deltaY * wheel.accelerationRatioY, true);
break;
}
case blink::WebInputEvent::GestureScrollUpdate: {
const blink::WebGestureEvent& gesture =
static_cast<const blink::WebGestureEvent&>(event);
- event_processed = ProcessOverscroll(gesture.data.scrollUpdate.deltaX,
- gesture.data.scrollUpdate.deltaY,
- gesture.type);
+ event_processed = ProcessOverscroll(
+ gesture.data.scrollUpdate.deltaX, gesture.data.scrollUpdate.deltaY,
+ gesture.sourceDevice == blink::WebGestureDeviceTouchpad);
break;
}
case blink::WebInputEvent::GestureFlingStart: {
@@ -270,15 +339,14 @@ bool OverscrollController::ProcessEventForOverscroll(
bool OverscrollController::ProcessOverscroll(float delta_x,
float delta_y,
- blink::WebInputEvent::Type type) {
+ bool is_touchpad) {
if (scroll_state_ != STATE_CONTENT_SCROLLING)
overscroll_delta_x_ += delta_x;
overscroll_delta_y_ += delta_y;
float horiz_threshold = GetOverscrollConfig(
- WebInputEvent::isGestureEventType(type) ?
- OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN :
- OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD);
+ is_touchpad ? OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD
+ : OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN);
float vert_threshold = GetOverscrollConfig(
OVERSCROLL_CONFIG_VERT_THRESHOLD_START);
if (fabs(overscroll_delta_x_) <= horiz_threshold &&
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.h b/chromium/content/browser/renderer_host/overscroll_controller.h
index 92fa093bf13..90f310f19fb 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.h
+++ b/chromium/content/browser/renderer_host/overscroll_controller.h
@@ -92,9 +92,7 @@ class OverscrollController {
// and the over scroll amount (i.e. |overscroll_mode_|, |overscroll_delta_x_|
// and |overscroll_delta_y_|). Returns true if overscroll was handled by the
// delegate.
- bool ProcessOverscroll(float delta_x,
- float delta_y,
- blink::WebInputEvent::Type event_type);
+ bool ProcessOverscroll(float delta_x, float delta_y, bool is_touchpad);
// Completes the desired action from the current gesture.
void CompleteAction();
@@ -103,6 +101,9 @@ class OverscrollController {
// appropriate).
void SetOverscrollMode(OverscrollMode new_mode);
+ // Whether this event should be processed or not handled by the controller.
+ bool ShouldProcessEvent(const blink::WebInputEvent& event);
+
// The current state of overscroll gesture.
OverscrollMode overscroll_mode_;
@@ -121,6 +122,7 @@ class OverscrollController {
// The delegate that receives the overscroll updates. The delegate is not
// owned by this controller.
OverscrollControllerDelegate* delegate_;
+ bool use_gesture_wheel_scrolling_;
DISALLOW_COPY_AND_ASSIGN(OverscrollController);
};
diff --git a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
index 784a808edfa..b1bc3c3c4f2 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -14,7 +14,6 @@
#include "content/public/browser/resource_context.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
-#include "net/base/ip_address_number.h"
#include "net/base/net_errors.h"
#include "net/base/network_interfaces.h"
#include "net/base/sys_addrinfo.h"
@@ -346,14 +345,13 @@ void P2PSocketDispatcherHost::DoGetNetworkList() {
void P2PSocketDispatcherHost::SendNetworkList(
const net::NetworkInterfaceList& list,
- const net::IPAddressNumber& default_ipv4_local_address,
- const net::IPAddressNumber& default_ipv6_local_address) {
+ const net::IPAddress& default_ipv4_local_address,
+ const net::IPAddress& default_ipv6_local_address) {
Send(new P2PMsg_NetworkListChanged(list, default_ipv4_local_address,
default_ipv6_local_address));
}
-net::IPAddressNumber P2PSocketDispatcherHost::GetDefaultLocalAddress(
- int family) {
+net::IPAddress P2PSocketDispatcherHost::GetDefaultLocalAddress(int family) {
DCHECK(family == AF_INET || family == AF_INET6);
// Creation and connection of a UDP socket might be janky.
@@ -364,23 +362,20 @@ net::IPAddressNumber P2PSocketDispatcherHost::GetDefaultLocalAddress(
net::DatagramSocket::DEFAULT_BIND, net::RandIntCallback(), NULL,
net::NetLog::Source()));
- net::IPAddressNumber ip_address_number;
+ net::IPAddress ip_address;
if (family == AF_INET) {
- ip_address_number.assign(kPublicIPv4Host,
- kPublicIPv4Host + net::kIPv4AddressSize);
+ ip_address = net::IPAddress(kPublicIPv4Host);
} else {
- ip_address_number.assign(kPublicIPv6Host,
- kPublicIPv6Host + net::kIPv6AddressSize);
+ ip_address = net::IPAddress(kPublicIPv6Host);
}
- if (socket->Connect(net::IPEndPoint(ip_address_number, kPublicPort)) !=
- net::OK) {
- return net::IPAddressNumber();
+ if (socket->Connect(net::IPEndPoint(ip_address, kPublicPort)) != net::OK) {
+ return net::IPAddress();
}
net::IPEndPoint local_address;
if (socket->GetLocalAddress(&local_address) != net::OK)
- return net::IPAddressNumber();
+ return net::IPAddress();
return local_address.address();
}
diff --git a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
index d783e1fbfed..5b4ef05c2c0 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
@@ -18,6 +18,7 @@
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
+#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/network_change_notifier.h"
@@ -93,13 +94,13 @@ class P2PSocketDispatcherHost
void DoGetNetworkList();
void SendNetworkList(const net::NetworkInterfaceList& list,
- const net::IPAddressNumber& default_ipv4_local_address,
- const net::IPAddressNumber& default_ipv6_local_address);
+ const net::IPAddress& default_ipv4_local_address,
+ const net::IPAddress& default_ipv6_local_address);
// This connects a UDP socket to a public IP address and gets local
// address. Since it binds to the "any" address (0.0.0.0 or ::) internally, it
// retrieves the default local address.
- net::IPAddressNumber GetDefaultLocalAddress(int family);
+ net::IPAddress GetDefaultLocalAddress(int family);
void OnAddressResolved(DnsRequest* request,
const net::IPAddressList& addresses);
@@ -116,8 +117,8 @@ class P2PSocketDispatcherHost
std::set<DnsRequest*> dns_requests_;
P2PMessageThrottler throttler_;
- net::IPAddressNumber default_ipv4_local_address_;
- net::IPAddressNumber default_ipv6_local_address_;
+ net::IPAddress default_ipv4_local_address_;
+ net::IPAddress default_ipv6_local_address_;
bool dump_incoming_rtp_packet_;
bool dump_outgoing_rtp_packet_;
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.cc b/chromium/content/browser/renderer_host/p2p/socket_host.cc
index ef6b58820c1..fa593fcf936 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.cc
@@ -11,34 +11,14 @@
#include "content/browser/renderer_host/p2p/socket_host_udp.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "crypto/hmac.h"
-#include "third_party/webrtc/base/asyncpacketsocket.h"
-#include "third_party/webrtc/base/byteorder.h"
-#include "third_party/webrtc/base/messagedigest.h"
-#include "third_party/webrtc/p2p/base/stun.h"
+#include "third_party/webrtc/media/base/rtputils.h"
+#include "third_party/webrtc/media/base/turnutils.h"
namespace {
const uint32_t kStunMagicCookie = 0x2112A442;
-const size_t kMinRtpHeaderLength = 12;
const size_t kMinRtcpHeaderLength = 8;
-const size_t kRtpExtensionHeaderLength = 4;
const size_t kDtlsRecordHeaderLength = 13;
-const size_t kTurnChannelHeaderLength = 4;
-const size_t kAbsSendTimeExtensionLength = 3;
-const size_t kOneByteHeaderLength = 1;
-const size_t kMaxRtpPacketLength = 2048;
-
-// Fake auth tag written by the render process if external authentication is
-// enabled. HMAC in packet will be compared against this value before updating
-// packet with actual HMAC value.
-static const unsigned char kFakeAuthTag[10] = {
- 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd
-};
-
-bool IsTurnChannelData(const char* data, size_t length) {
- return length >= kTurnChannelHeaderLength && ((*data & 0xC0) == 0x40);
-}
bool IsDtlsPacket(const char* data, size_t length) {
const uint8_t* u = reinterpret_cast<const uint8_t*>(data);
@@ -54,406 +34,10 @@ bool IsRtcpPacket(const char* data, size_t length) {
return (type >= 64 && type < 96);
}
-bool IsTurnSendIndicationPacket(const char* data, size_t length) {
- if (length < content::P2PSocketHost::kStunHeaderSize) {
- return false;
- }
-
- uint16_t type = rtc::GetBE16(data);
- return (type == cricket::TURN_SEND_INDICATION);
-}
-
-bool IsRtpPacket(const char* data, size_t length) {
- return (length >= kMinRtpHeaderLength) && ((*data & 0xC0) == 0x80);
-}
-
-// Verifies rtp header and message length.
-bool ValidateRtpHeader(const char* rtp, size_t length, size_t* header_length) {
- if (header_length) {
- *header_length = 0;
- }
-
- if (length < kMinRtpHeaderLength) {
- return false;
- }
-
- size_t cc_count = rtp[0] & 0x0F;
- size_t header_length_without_extension = kMinRtpHeaderLength + 4 * cc_count;
- if (header_length_without_extension > length) {
- return false;
- }
-
- // If extension bit is not set, we are done with header processing, as input
- // length is verified above.
- if (!(rtp[0] & 0x10)) {
- if (header_length)
- *header_length = header_length_without_extension;
-
- return true;
- }
-
- rtp += header_length_without_extension;
-
- if (header_length_without_extension + kRtpExtensionHeaderLength > length) {
- return false;
- }
-
- // Getting extension profile length.
- // Length is in 32 bit words.
- uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2);
- size_t extension_length = extension_length_in_32bits * 4;
-
- size_t rtp_header_length = extension_length +
- header_length_without_extension +
- kRtpExtensionHeaderLength;
-
- // Verify input length against total header size.
- if (rtp_header_length > length) {
- return false;
- }
-
- if (header_length) {
- *header_length = rtp_header_length;
- }
- return true;
-}
-
-void UpdateAbsSendTimeExtensionValue(char* extension_data,
- size_t length,
- uint32_t abs_send_time) {
- // Absolute send time in RTP streams.
- //
- // The absolute send time is signaled to the receiver in-band using the
- // general mechanism for RTP header extensions [RFC5285]. The payload
- // of this extension (the transmitted value) is a 24-bit unsigned integer
- // containing the sender's current time in seconds as a fixed point number
- // with 18 bits fractional part.
- //
- // The form of the absolute send time extension block:
- //
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | ID | len=2 | absolute send time |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- if (length != kAbsSendTimeExtensionLength) {
- NOTREACHED();
- return;
- }
-
- // Now() has resolution ~1-15ms
- uint32_t now_second = abs_send_time;
- if (!now_second) {
- uint64_t now_us =
- (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds();
- // Convert second to 24-bit unsigned with 18 bit fractional part
- now_second =
- ((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF;
- }
- // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle.
- extension_data[0] = static_cast<uint8_t>(now_second >> 16);
- extension_data[1] = static_cast<uint8_t>(now_second >> 8);
- extension_data[2] = static_cast<uint8_t>(now_second);
-}
-
-// Assumes |length| is actual packet length + tag length. Updates HMAC at end of
-// the RTP packet.
-void UpdateRtpAuthTag(char* rtp,
- size_t length,
- const rtc::PacketOptions& options) {
- // If there is no key, return.
- if (options.packet_time_params.srtp_auth_key.empty()) {
- return;
- }
-
- size_t tag_length = options.packet_time_params.srtp_auth_tag_len;
-
- // ROC (rollover counter) is at the beginning of the auth tag.
- const size_t kRocLength = 4;
- if (tag_length < kRocLength || tag_length > length) {
- NOTREACHED();
- return;
- }
-
- crypto::HMAC hmac(crypto::HMAC::SHA1);
- if (!hmac.Init(reinterpret_cast<const unsigned char*>(
- &options.packet_time_params.srtp_auth_key[0]),
- options.packet_time_params.srtp_auth_key.size())) {
- NOTREACHED();
- return;
- }
-
- if (tag_length > hmac.DigestLength()) {
- NOTREACHED();
- return;
- }
-
- char* auth_tag = rtp + (length - tag_length);
-
- // We should have a fake HMAC value @ auth_tag.
- DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length));
-
- // Copy ROC after end of rtp packet.
- memcpy(auth_tag, &options.packet_time_params.srtp_packet_index, kRocLength);
- // Authentication of a RTP packet will have RTP packet + ROC size.
- int auth_required_length = length - tag_length + kRocLength;
-
- unsigned char output[64];
- if (!hmac.Sign(base::StringPiece(rtp, auth_required_length),
- output, sizeof(output))) {
- NOTREACHED();
- return;
- }
- // Copy HMAC from output to packet. This is required as auth tag length
- // may not be equal to the actual HMAC length.
- memcpy(auth_tag, output, tag_length);
-}
-
} // namespace
namespace content {
-namespace packet_processing_helpers {
-
-bool ApplyPacketOptions(char* data,
- size_t length,
- const rtc::PacketOptions& options,
- uint32_t abs_send_time) {
- DCHECK(data != NULL);
- DCHECK(length > 0);
- // if there is no valid |rtp_sendtime_extension_id| and |srtp_auth_key| in
- // PacketOptions, nothing to be updated in this packet.
- if (options.packet_time_params.rtp_sendtime_extension_id == -1 &&
- options.packet_time_params.srtp_auth_key.empty()) {
- return true;
- }
-
- DCHECK(!IsDtlsPacket(data, length));
- DCHECK(!IsRtcpPacket(data, length));
-
- // If there is a srtp auth key present then packet must be a RTP packet.
- // RTP packet may have been wrapped in a TURN Channel Data or
- // TURN send indication.
- size_t rtp_start_pos;
- size_t rtp_length;
- if (!GetRtpPacketStartPositionAndLength(
- data, length, &rtp_start_pos, &rtp_length)) {
- // This method should never return false.
- NOTREACHED();
- return false;
- }
-
- // Skip to rtp packet.
- char* start = data + rtp_start_pos;
- // If packet option has non default value (-1) for sendtime extension id,
- // then we should parse the rtp packet to update the timestamp. Otherwise
- // just calculate HMAC and update packet with it.
- if (options.packet_time_params.rtp_sendtime_extension_id != -1) {
- UpdateRtpAbsSendTimeExtension(
- start,
- rtp_length,
- options.packet_time_params.rtp_sendtime_extension_id,
- abs_send_time);
- }
-
- UpdateRtpAuthTag(start, rtp_length, options);
- return true;
-}
-
-bool GetRtpPacketStartPositionAndLength(const char* packet,
- size_t length,
- size_t* rtp_start_pos,
- size_t* rtp_packet_length) {
- if (length < kMinRtpHeaderLength || length > kMaxRtpPacketLength) {
- return false;
- }
-
- size_t rtp_begin;
- size_t rtp_length = 0;
- if (IsTurnChannelData(packet, length)) {
- // Turn Channel Message header format.
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Channel Number | Length |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // / Application Data /
- // / /
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- rtp_begin = kTurnChannelHeaderLength;
- rtp_length = rtc::GetBE16(&packet[2]);
- if (length < rtp_length + kTurnChannelHeaderLength) {
- return false;
- }
- } else if (IsTurnSendIndicationPacket(packet, length)) {
- // Validate STUN message length.
- const size_t stun_message_length = rtc::GetBE16(&packet[2]);
- if (stun_message_length + P2PSocketHost::kStunHeaderSize != length) {
- return false;
- }
-
- // First skip mandatory stun header which is of 20 bytes.
- rtp_begin = P2PSocketHost::kStunHeaderSize;
- // Loop through STUN attributes until we find STUN DATA attribute.
- bool data_attr_present = false;
- while (rtp_begin < length) {
- // Keep reading STUN attributes until we hit DATA attribute.
- // Attribute will be a TLV structure.
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Type | Length |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Value (variable) ....
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // The value in the length field MUST contain the length of the Value
- // part of the attribute, prior to padding, measured in bytes. Since
- // STUN aligns attributes on 32-bit boundaries, attributes whose content
- // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of
- // padding so that its value contains a multiple of 4 bytes. The
- // padding bits are ignored, and may be any value.
- uint16_t attr_type, attr_length;
- const int kAttrHeaderLength = sizeof(attr_type) + sizeof(attr_length);
-
- if (length < rtp_begin + kAttrHeaderLength) {
- return false;
- }
-
- // Getting attribute type and length.
- attr_type = rtc::GetBE16(&packet[rtp_begin]);
- attr_length = rtc::GetBE16(
- &packet[rtp_begin + sizeof(attr_type)]);
-
- rtp_begin += kAttrHeaderLength; // Skip STUN_DATA_ATTR header.
-
- // Checking for bogus attribute length.
- if (length < rtp_begin + attr_length) {
- return false;
- }
-
- if (attr_type != cricket::STUN_ATTR_DATA) {
- rtp_begin += attr_length;
- if ((attr_length % 4) != 0) {
- rtp_begin += (4 - (attr_length % 4));
- }
- continue;
- }
-
- data_attr_present = true;
- rtp_length = attr_length;
-
- // We found STUN_DATA_ATTR. We can skip parsing rest of the packet.
- break;
- }
-
- if (!data_attr_present) {
- // There is no data attribute present in the message. We can't do anything
- // with the message.
- return false;
- }
-
- } else {
- // This is a raw RTP packet.
- rtp_begin = 0;
- rtp_length = length;
- }
-
- // Making sure we have a valid RTP packet at the end.
- if (IsRtpPacket(packet + rtp_begin, rtp_length) &&
- ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) {
- *rtp_start_pos = rtp_begin;
- *rtp_packet_length = rtp_length;
- return true;
- }
- return false;
-}
-
-// ValidateRtpHeader must be called before this method to make sure, we have
-// a sane rtp packet.
-bool UpdateRtpAbsSendTimeExtension(char* rtp,
- size_t length,
- int extension_id,
- uint32_t abs_send_time) {
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |V=2|P|X| CC |M| PT | sequence number |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | timestamp |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | synchronization source (SSRC) identifier |
- // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- // | contributing source (CSRC) identifiers |
- // | .... |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- // Return if extension bit is not set.
- if (!(rtp[0] & 0x10)) {
- return true;
- }
-
- size_t cc_count = rtp[0] & 0x0F;
- size_t header_length_without_extension = kMinRtpHeaderLength + 4 * cc_count;
-
- rtp += header_length_without_extension;
-
- // Getting extension profile ID and length.
- uint16_t profile_id = rtc::GetBE16(rtp);
- // Length is in 32 bit words.
- uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2);
- size_t extension_length = extension_length_in_32bits * 4;
-
- rtp += kRtpExtensionHeaderLength; // Moving past extension header.
-
- bool found = false;
- // WebRTC is using one byte header extension.
- // TODO(mallinath) - Handle two byte header extension.
- if (profile_id == 0xBEDE) { // OneByte extension header
- // 0
- // 0 1 2 3 4 5 6 7
- // +-+-+-+-+-+-+-+-+
- // | ID |length |
- // +-+-+-+-+-+-+-+-+
-
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | 0xBE | 0xDE | length=3 |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | ID | L=0 | data | ID | L=1 | data...
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // ...data | 0 (pad) | 0 (pad) | ID | L=3 |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | data |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- const char* extension_start = rtp;
- const char* extension_end = extension_start + extension_length;
-
- while (rtp < extension_end) {
- const int id = (*rtp & 0xF0) >> 4;
- const size_t length = (*rtp & 0x0F) + 1;
- if (rtp + kOneByteHeaderLength + length > extension_end) {
- return false;
- }
- // The 4-bit length is the number minus one of data bytes of this header
- // extension element following the one-byte header.
- if (id == extension_id) {
- UpdateAbsSendTimeExtensionValue(
- rtp + kOneByteHeaderLength, length, abs_send_time);
- found = true;
- break;
- }
- rtp += kOneByteHeaderLength + length;
- // Counting padding bytes.
- while ((rtp < extension_end) && (*rtp == 0)) {
- ++rtp;
- }
- }
- }
- return found;
-}
-
-} // packet_processing_helpers
-
P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
int socket_id,
ProtocolType protocol_type)
@@ -622,17 +206,19 @@ void P2PSocketHost::DumpRtpPacket(const char* packet,
size_t rtp_packet_pos = 0;
size_t rtp_packet_length = length;
- if (!packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- packet, length, &rtp_packet_pos, &rtp_packet_length)) {
+ if (!cricket::UnwrapTurnPacket(reinterpret_cast<const uint8_t*>(packet),
+ length, &rtp_packet_pos, &rtp_packet_length)) {
return;
}
packet += rtp_packet_pos;
size_t header_length = 0;
- bool valid = ValidateRtpHeader(packet, rtp_packet_length, &header_length);
+ bool valid =
+ cricket::ValidateRtpHeader(reinterpret_cast<const uint8_t*>(packet),
+ rtp_packet_length, &header_length);
if (!valid) {
- DCHECK(false);
+ NOTREACHED();
return;
}
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.h b/chromium/content/browser/renderer_host/p2p/socket_host.h
index 37ffddbf8cb..0b14f0f4885 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.h
@@ -31,33 +31,6 @@ struct PacketOptions;
namespace content {
class P2PMessageThrottler;
-namespace packet_processing_helpers {
-
-// This method can handle only RTP packet, otherwise this method must not be
-// called. It will try to do, 1. update absolute send time extension header
-// if present with current time and 2. update HMAC in RTP packet.
-// If abs_send_time is 0, ApplyPacketOption will get current time from system.
-CONTENT_EXPORT bool ApplyPacketOptions(char* data,
- size_t length,
- const rtc::PacketOptions& options,
- uint32_t abs_send_time);
-
-// Helper method which finds RTP ofset and length if the packet is encapsulated
-// in a TURN Channel Message or TURN Send Indication message.
-CONTENT_EXPORT bool GetRtpPacketStartPositionAndLength(
- const char* data,
- size_t length,
- size_t* rtp_start_pos,
- size_t* rtp_packet_length);
-
-// Helper method which updates absoulute send time extension if present.
-CONTENT_EXPORT bool UpdateRtpAbsSendTimeExtension(char* rtp,
- size_t length,
- int extension_id,
- uint32_t abs_send_time);
-
-} // packet_processing_helpers
-
// Base class for P2P sockets.
class CONTENT_EXPORT P2PSocketHost {
public:
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
index cd93a129370..10398dc614f 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -16,14 +16,13 @@
#include "jingle/glue/proxy_resolving_client_socket.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_client_socket.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
-#include "third_party/webrtc/base/asyncpacketsocket.h"
+#include "third_party/webrtc/media/base/rtputils.h"
namespace {
@@ -528,10 +527,10 @@ void P2PSocketHostTcp::DoSend(const net::IPEndPoint& to,
*reinterpret_cast<uint16_t*>(buffer->data()) = base::HostToNet16(data.size());
memcpy(buffer->data() + kPacketHeaderSize, &data[0], data.size());
- packet_processing_helpers::ApplyPacketOptions(
- buffer->data() + kPacketHeaderSize,
- buffer->BytesRemaining() - kPacketHeaderSize,
- options, 0);
+ cricket::ApplyPacketOptions(
+ reinterpret_cast<uint8_t*>(buffer->data()) + kPacketHeaderSize,
+ buffer->BytesRemaining() - kPacketHeaderSize, options.packet_time_params,
+ (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds());
WriteOrQueue(buffer);
}
@@ -601,8 +600,10 @@ void P2PSocketHostStunTcp::DoSend(const net::IPEndPoint& to,
new net::DrainableIOBuffer(new net::IOBuffer(size), size);
memcpy(buffer->data(), &data[0], data.size());
- packet_processing_helpers::ApplyPacketOptions(
- buffer->data(), data.size(), options, 0);
+ cricket::ApplyPacketOptions(
+ reinterpret_cast<uint8_t*>(buffer->data()), data.size(),
+ options.packet_time_params,
+ (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds());
if (pad_bytes) {
char padding[4] = {0};
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
index dc49bfdca9f..3d55c29bceb 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
@@ -11,7 +11,6 @@
#include "content/common/p2p_messages.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
#include "net/socket/stream_socket.h"
namespace {
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
index dce2bd60ddb..81ca20db22e 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
@@ -11,6 +11,7 @@
#include "base/thread_task_runner_handle.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
const int kStunHeaderSize = 20;
const uint16_t kStunBindingRequest = 0x0001;
@@ -159,10 +160,6 @@ bool FakeSocket::WasEverUsed() const {
return true;
}
-bool FakeSocket::UsingTCPFastOpen() const {
- return false;
-}
-
bool FakeSocket::WasNpnNegotiated() const {
return false;
}
@@ -217,7 +214,7 @@ void CreateStunError(std::vector<char>* packet) {
}
net::IPEndPoint ParseAddress(const std::string& ip_str, uint16_t port) {
- net::IPAddressNumber ip;
- EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_str, &ip));
+ net::IPAddress ip;
+ EXPECT_TRUE(ip.AssignFromIPLiteral(ip_str));
return net::IPEndPoint(ip, port);
}
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
index 77a8319b263..f1a60cc72a6 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
@@ -61,7 +61,6 @@ class FakeSocket : public net::StreamSocket {
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
- bool UsingTCPFastOpen() const override;
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc b/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
index 0dbfcec4265..451353603e4 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -18,8 +18,7 @@
#include "ipc/ipc_sender.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
-#include "third_party/webrtc/base/asyncpacketsocket.h"
+#include "third_party/webrtc/media/base/rtputils.h"
namespace {
@@ -85,6 +84,9 @@ P2PSocketHostUdp::PendingPacket::PendingPacket(
memcpy(data->data(), &content[0], size);
}
+P2PSocketHostUdp::PendingPacket::PendingPacket(const PendingPacket& other) =
+ default;
+
P2PSocketHostUdp::PendingPacket::~PendingPacket() {
}
@@ -294,9 +296,10 @@ void P2PSocketHostUdp::DoSend(const PendingPacket& packet) {
}
base::TimeTicks send_time = base::TimeTicks::Now();
-
- packet_processing_helpers::ApplyPacketOptions(
- packet.data->data(), packet.size, packet.packet_options, 0);
+ cricket::ApplyPacketOptions(reinterpret_cast<uint8_t*>(packet.data->data()),
+ packet.size,
+ packet.packet_options.packet_time_params,
+ (send_time - base::TimeTicks()).InMicroseconds());
auto callback_binding =
base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id,
packet.packet_options.packet_id, send_time);
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h b/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
index 93fb6335458..57f1db397af 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -58,6 +58,7 @@ class CONTENT_EXPORT P2PSocketHostUdp : public P2PSocketHost {
const std::vector<char>& content,
const rtc::PacketOptions& options,
uint64_t id);
+ PendingPacket(const PendingPacket& other);
~PendingPacket();
net::IPEndPoint to;
scoped_refptr<net::IOBuffer> data;
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
index 7bf0944514b..aecd85a7c60 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
@@ -121,12 +121,12 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
void AllowBroadcast() override { NOTIMPLEMENTED(); }
- int JoinGroup(const net::IPAddressNumber& group_address) const override {
+ int JoinGroup(const net::IPAddress& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- int LeaveGroup(const net::IPAddressNumber& group_address) const override {
+ int LeaveGroup(const net::IPAddress& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc
deleted file mode 100644
index c92e9d75630..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/renderer_host/p2p/socket_host_test_utils.h"
-#include "net/base/ip_endpoint.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-static unsigned char kFakeTag[4] = { 0xba, 0xdd, 0xba, 0xdd };
-static unsigned char kTestKey[] = "12345678901234567890";
-static unsigned char kTestAstValue[3] = { 0xaa, 0xbb, 0xcc };
-
-// Rtp message with invalid length.
-static unsigned char kRtpMsgWithInvalidLength[] = {
- 0x94, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xAA, 0xBB, 0xCC, 0XDD, // SSRC
- 0xDD, 0xCC, 0xBB, 0xAA // Only 1 CSRC, but CC count is 4.
-};
-
-// Rtp message with single byte header extension, invalid extension length.
-static unsigned char kRtpMsgWithInvalidExtnLength[] = {
- 0x90, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xBE, 0xDE, 0x0A, 0x00 // Extn length - 0x0A00
-};
-
-// Valid rtp Message with 2 byte header extension.
-static unsigned char kRtpMsgWith2ByteExtnHeader[] = {
- 0x90, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xAA, 0xBB, 0xCC, 0XDD, // SSRC
- 0x10, 0x00, 0x00, 0x01, // 2 Byte header extension
- 0x01, 0x00, 0x00, 0x00
-};
-
-// Stun Indication message with Zero length
-static unsigned char kTurnSendIndicationMsgWithNoAttributes[] = {
- 0x00, 0x16, 0x00, 0x00, // Zero length
- 0x21, 0x12, 0xA4, 0x42, // magic cookie
- '0', '1', '2', '3', // transaction id
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
-};
-
-// Stun Send Indication message with invalid length in stun header.
-static unsigned char kTurnSendIndicationMsgWithInvalidLength[] = {
- 0x00, 0x16, 0xFF, 0x00, // length of 0xFF00
- 0x21, 0x12, 0xA4, 0x42, // magic cookie
- '0', '1', '2', '3', // transaction id
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
-};
-
-// Stun Send Indication message with no DATA attribute in message.
-static unsigned char kTurnSendIndicatinMsgWithNoDataAttribute[] = {
- 0x00, 0x16, 0x00, 0x08, // length of
- 0x21, 0x12, 0xA4, 0x42, // magic cookie
- '0', '1', '2', '3', // transaction id
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
- 0x00, 0x20, 0x00, 0x04, // Mapped address.
- 0x00, 0x00, 0x00, 0x00
-};
-
-// A valid STUN indication message with a valid RTP header in data attribute
-// payload field and no extension bit set.
-static unsigned char kTurnSendIndicationMsgWithoutRtpExtension[] = {
- 0x00, 0x16, 0x00, 0x18, // length of
- 0x21, 0x12, 0xA4, 0x42, // magic cookie
- '0', '1', '2', '3', // transaction id
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
- 0x00, 0x20, 0x00, 0x04, // Mapped address.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x13, 0x00, 0x0C, // Data attribute.
- 0x80, 0x00, 0x00, 0x00, // RTP packet.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-};
-
-// A valid STUN indication message with a valid RTP header and a extension
-// header.
-static unsigned char kTurnSendIndicationMsgWithAbsSendTimeExtension[] = {
- 0x00, 0x16, 0x00, 0x24, // length of
- 0x21, 0x12, 0xA4, 0x42, // magic cookie
- '0', '1', '2', '3', // transaction id
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
- 0x00, 0x20, 0x00, 0x04, // Mapped address.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x13, 0x00, 0x18, // Data attribute.
- 0x90, 0x00, 0x00, 0x00, // RTP packet.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xBE, 0xDE, 0x00, 0x02,
- 0x22, 0xaa, 0xbb, 0xcc,
- 0x32, 0xaa, 0xbb, 0xcc,
-};
-
-// A valid TURN channel header, but not RTP packet.
-static unsigned char kTurnChannelMsgNoRtpPacket[] = {
- 0x40, 0x00, 0x00, 0x04,
- 0xaa, 0xbb, 0xcc, 0xdd,
-};
-
-// Turn ChannelMessage with zero length of payload.
-static unsigned char kTurnChannelMsgWithZeroLength[] = {
- 0x40, 0x00, 0x00, 0x00
-};
-
-// Turn ChannelMessage, wrapping a RTP packet without extension.
-static unsigned char kTurnChannelMsgWithRtpPacket[] = {
- 0x40, 0x00, 0x00, 0x0C,
- 0x80, 0x00, 0x00, 0x00, // RTP packet.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-};
-
-// Turn ChannelMessage, wrapping a RTP packet with AbsSendTime Extension.
-static unsigned char kTurnChannelMsgWithAbsSendTimeExtension[] = {
- 0x40, 0x00, 0x00, 0x14,
- 0x90, 0x00, 0x00, 0x00, // RTP packet.
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xBE, 0xDE, 0x00, 0x01,
- 0x32, 0xaa, 0xbb, 0xcc,
-};
-
-// RTP packet with single byte extension header of length 4 bytes.
-// Extension id = 3 and length = 3
-static unsigned char kRtpMsgWithAbsSendTimeExtension[] = {
- 0x90, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xBE, 0xDE, 0x00, 0x02,
- 0x22, 0x00, 0x02, 0x1c,
- 0x32, 0xaa, 0xbb, 0xcc,
-};
-
-// Index of AbsSendTimeExtn data in message |kRtpMsgWithAbsSendTimeExtension|.
-static const int kAstIndexInRtpMsg = 21;
-
-namespace content {
-
-// This test verifies parsing of all invalid raw packets.
-TEST(P2PSocketHostTest, TestInvalidRawRtpMessages) {
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kRtpMsgWithInvalidLength),
- sizeof(kRtpMsgWithInvalidLength),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kRtpMsgWithInvalidExtnLength),
- sizeof(kRtpMsgWithInvalidExtnLength),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-}
-
-// Verify invalid TURN send indication messages. Messages are proper STUN
-// messages with incorrect values in attributes.
-TEST(P2PSocketHostTest, TestInvalidTurnSendIndicationMessages) {
- // Initializing out params to very large value.
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithNoAttributes),
- sizeof(kTurnSendIndicationMsgWithNoAttributes),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithInvalidLength),
- sizeof(kTurnSendIndicationMsgWithInvalidLength),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnSendIndicatinMsgWithNoDataAttribute),
- sizeof(kTurnSendIndicatinMsgWithNoDataAttribute),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-}
-
-// This test verifies incorrectly formed TURN channel messages.
-TEST(P2PSocketHostTest, TestInvalidTurnChannelMessages) {
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnChannelMsgNoRtpPacket),
- sizeof(kTurnChannelMsgNoRtpPacket),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-
- EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnChannelMsgWithZeroLength),
- sizeof(kTurnChannelMsgWithZeroLength),
- &start_pos, &rtp_length));
- EXPECT_EQ(SIZE_MAX, start_pos);
- EXPECT_EQ(SIZE_MAX, rtp_length);
-}
-
-// This test verifies parsing of a valid RTP packet which has 2byte header
-// extension instead of a 1 byte header extension.
-TEST(P2PSocketHostTest, TestValid2ByteExtnHdrRtpMessage) {
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kRtpMsgWith2ByteExtnHeader),
- sizeof(kRtpMsgWith2ByteExtnHeader),
- &start_pos, &rtp_length));
- EXPECT_EQ(20U, rtp_length);
- EXPECT_EQ(0U, start_pos);
-}
-
-// This test verifies parsing of a valid RTP packet which has 1 byte header
-// AbsSendTime extension in it.
-TEST(P2PSocketHostTest, TestValidRtpPacketWithAbsSendTimeExtension) {
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kRtpMsgWithAbsSendTimeExtension),
- sizeof(kRtpMsgWithAbsSendTimeExtension),
- &start_pos, &rtp_length));
- EXPECT_EQ(24U, rtp_length);
- EXPECT_EQ(0U, start_pos);
-}
-
-// This test verifies parsing of a valid TURN Send Indication messages.
-TEST(P2PSocketHostTest, TestValidTurnSendIndicationMessages) {
- size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithoutRtpExtension),
- sizeof(kTurnSendIndicationMsgWithoutRtpExtension),
- &start_pos, &rtp_length));
- EXPECT_EQ(12U, rtp_length);
- EXPECT_EQ(32U, start_pos);
-
- start_pos = SIZE_MAX, rtp_length = SIZE_MAX;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithAbsSendTimeExtension),
- sizeof(kTurnSendIndicationMsgWithAbsSendTimeExtension),
- &start_pos, &rtp_length));
- EXPECT_EQ(24U, rtp_length);
- EXPECT_EQ(32U, start_pos);
-}
-
-// This test verifies parsing of valid TURN Channel Messages.
-TEST(P2PSocketHostTest, TestValidTurnChannelMessages) {
- size_t start_pos = 0, rtp_length = 0;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnChannelMsgWithRtpPacket),
- sizeof(kTurnChannelMsgWithRtpPacket), &start_pos, &rtp_length));
- EXPECT_EQ(12U, rtp_length);
- EXPECT_EQ(4U, start_pos);
-
- start_pos = 0, rtp_length = 0;
- EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
- reinterpret_cast<char*>(kTurnChannelMsgWithAbsSendTimeExtension),
- sizeof(kTurnChannelMsgWithAbsSendTimeExtension),
- &start_pos, &rtp_length));
- EXPECT_EQ(20U, rtp_length);
- EXPECT_EQ(4U, start_pos);
-}
-
-// Verify handling of a 2 byte extension header RTP messsage. Currently we don't
-// handle this kind of message.
-TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionIn2ByteHeaderExtn) {
- EXPECT_FALSE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
- reinterpret_cast<char*>(kRtpMsgWith2ByteExtnHeader),
- sizeof(kRtpMsgWith2ByteExtnHeader),
- 3,
- 0));
-}
-
-// Verify finding an extension ID in the TURN send indication message.
-TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionInTurnSendIndication) {
- EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithoutRtpExtension),
- sizeof(kTurnSendIndicationMsgWithoutRtpExtension),
- 3,
- 0));
-
- EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
- reinterpret_cast<char*>(kTurnSendIndicationMsgWithAbsSendTimeExtension),
- sizeof(kTurnSendIndicationMsgWithAbsSendTimeExtension),
- 3,
- 0));
-}
-
-// Test without any packet options variables set. This method should return
-// without HMAC value in the packet.
-TEST(P2PSocketHostTest, TestApplyPacketOptionsWithDefaultValues) {
- unsigned char fake_tag[4] = { 0xba, 0xdd, 0xba, 0xdd };
- rtc::PacketOptions options;
- std::vector<char> rtp_packet;
- rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length
- memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension,
- sizeof(kRtpMsgWithAbsSendTimeExtension));
- memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], fake_tag, 4);
- EXPECT_TRUE(
- packet_processing_helpers::ApplyPacketOptions(
- &rtp_packet[0], rtp_packet.size(), options, 0));
- // Making sure we have't updated the HMAC.
- EXPECT_EQ(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
- fake_tag, 4));
-
- // Verify AbsouluteSendTime extension field is not modified.
- EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg],
- kTestAstValue, sizeof(kTestAstValue)));
-}
-
-// Veirfy HMAC is updated when packet option parameters are set.
-TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParams) {
- rtc::PacketOptions options;
- options.packet_time_params.srtp_auth_key.resize(20);
- options.packet_time_params.srtp_auth_key.assign(
- kTestKey, kTestKey + sizeof(kTestKey));
- options.packet_time_params.srtp_auth_tag_len = 4;
-
- std::vector<char> rtp_packet;
- rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length
- memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension,
- sizeof(kRtpMsgWithAbsSendTimeExtension));
- memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], kFakeTag, 4);
- EXPECT_TRUE(packet_processing_helpers::ApplyPacketOptions(
- &rtp_packet[0], rtp_packet.size(), options, 0));
- // HMAC should be different from fake_tag.
- EXPECT_NE(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
- kFakeTag, sizeof(kFakeTag)));
-
- // Verify AbsouluteSendTime extension field is not modified.
- EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg],
- kTestAstValue, sizeof(kTestAstValue)));
-}
-
-// Verify finding an extension ID in a raw rtp message.
-TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionInRtpPacket) {
- EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
- reinterpret_cast<char*>(kRtpMsgWithAbsSendTimeExtension),
- sizeof(kRtpMsgWithAbsSendTimeExtension),
- 3,
- 0));
-}
-
-// Verify we update both AbsSendTime extension header and HMAC.
-TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParamsAndAbsSendTime) {
- rtc::PacketOptions options;
- options.packet_time_params.srtp_auth_key.resize(20);
- options.packet_time_params.srtp_auth_key.assign(
- kTestKey, kTestKey + sizeof(kTestKey));
- options.packet_time_params.srtp_auth_tag_len = 4;
- options.packet_time_params.rtp_sendtime_extension_id = 3;
- // 3 is also present in the test message.
-
- std::vector<char> rtp_packet;
- rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length
- memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension,
- sizeof(kRtpMsgWithAbsSendTimeExtension));
- memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], kFakeTag, 4);
- EXPECT_TRUE(packet_processing_helpers::ApplyPacketOptions(
- &rtp_packet[0], rtp_packet.size(), options, 0xccbbaa));
- // HMAC should be different from fake_tag.
- EXPECT_NE(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)],
- kFakeTag, sizeof(kFakeTag)));
-
- // ApplyPackets should have the new timestamp passed as input.
- unsigned char timestamp_array[3] = { 0xcc, 0xbb, 0xaa };
- EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg],
- timestamp_array, sizeof(timestamp_array)));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
index eaa9c51b71f..852a7d2e24f 100644
--- a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
+++ b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
@@ -211,7 +211,7 @@ bool BrowserPpapiHostImpl::HostMessageFilter::OnMessageReceived(
IPC_MESSAGE_HANDLER(PpapiHostMsg_LogInterfaceUsage,
OnHostMsgLogInterfaceUsage)
IPC_MESSAGE_UNHANDLED(handled = ppapi_host_->OnMessageReceived(msg))
- IPC_END_MESSAGE_MAP();
+ IPC_END_MESSAGE_MAP()
return handled;
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index faead267821..eea865bd9df 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -147,6 +147,9 @@ PepperFileIOHost::UIThreadStuff::UIThreadStuff() {
resolved_render_process_id = base::kNullProcessId;
}
+PepperFileIOHost::UIThreadStuff::UIThreadStuff(const UIThreadStuff& other) =
+ default;
+
PepperFileIOHost::UIThreadStuff::~UIThreadStuff() {}
int32_t PepperFileIOHost::OnHostMsgOpen(
@@ -195,7 +198,6 @@ int32_t PepperFileIOHost::OnHostMsgOpen(
case storage::kFileSystemTypeDeviceMedia:
case storage::kFileSystemTypePicasa:
case storage::kFileSystemTypeItunes:
- case storage::kFileSystemTypeIphoto:
break;
default:
return PP_ERROR_NOACCESS;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h
index 90de1da7b43..6899c2faa86 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h
@@ -49,6 +49,7 @@ class PepperFileIOHost : public ppapi::host::ResourceHost,
struct UIThreadStuff {
UIThreadStuff();
+ UIThreadStuff(const UIThreadStuff& other);
~UIThreadStuff();
base::ProcessId resolved_render_process_id;
scoped_refptr<storage::FileSystemContext> file_system_context;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
index 3059dd7780e..6f030773518 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
@@ -136,7 +136,7 @@ int32_t PepperFlashFileMessageFilter::OnOpenFile(
}
IPC::PlatformFileForTransit transit_file =
- IPC::TakeFileHandleForProcess(std::move(file), plugin_process_.Handle());
+ IPC::TakePlatformFileForTransit(std::move(file));
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
@@ -258,7 +258,7 @@ int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile(
return ppapi::FileErrorToPepperError(file.error_details());
IPC::PlatformFileForTransit transit_file =
- IPC::TakeFileHandleForProcess(std::move(file), plugin_process_.Handle());
+ IPC::TakePlatformFileForTransit(std::move(file));
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
index c841981c21b..60cba96ac3d 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
@@ -70,7 +70,7 @@ void CreateNetAddressListFromAddressList(
PP_NetAddress_Private address;
for (size_t i = 0; i < list.size(); ++i) {
if (!ppapi::NetAddressPrivateImpl::IPEndPointToNetAddress(
- list[i].address(), list[i].port(), &address)) {
+ list[i].address().bytes(), list[i].port(), &address)) {
net_address_list->clear();
return;
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc b/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc
index 1f9d27bafa0..467597fb39d 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc
@@ -98,6 +98,7 @@ int32_t PepperInternalFileRefBackend::MakeDirectory(
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
+ PpapiPluginMsg_FileRef_MakeDirectoryReply reply;
GetFileSystemContext()->operation_runner()->CreateDirectory(
GetFileSystemURL(),
!!(make_directory_flags & PP_MAKEDIRECTORYFLAG_EXCLUSIVE),
@@ -105,7 +106,7 @@ int32_t PepperInternalFileRefBackend::MakeDirectory(
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
- PpapiPluginMsg_FileRef_MakeDirectoryReply()));
+ reply));
return PP_OK_COMPLETIONPENDING;
}
@@ -116,6 +117,7 @@ int32_t PepperInternalFileRefBackend::Touch(
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
+ PpapiPluginMsg_FileRef_TouchReply reply;
GetFileSystemContext()->operation_runner()->TouchFile(
GetFileSystemURL(),
ppapi::PPTimeToTime(last_access_time),
@@ -123,7 +125,7 @@ int32_t PepperInternalFileRefBackend::Touch(
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
- PpapiPluginMsg_FileRef_TouchReply()));
+ reply));
return PP_OK_COMPLETIONPENDING;
}
@@ -132,13 +134,14 @@ int32_t PepperInternalFileRefBackend::Delete(
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
+ PpapiPluginMsg_FileRef_DeleteReply reply;
GetFileSystemContext()->operation_runner()->Remove(
GetFileSystemURL(),
false,
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
- PpapiPluginMsg_FileRef_DeleteReply()));
+ reply));
return PP_OK_COMPLETIONPENDING;
}
@@ -154,6 +157,7 @@ int32_t PepperInternalFileRefBackend::Rename(
if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
return PP_ERROR_FAILED;
+ PpapiPluginMsg_FileRef_RenameReply reply;
GetFileSystemContext()->operation_runner()->Move(
GetFileSystemURL(),
new_url,
@@ -161,7 +165,7 @@ int32_t PepperInternalFileRefBackend::Rename(
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
- PpapiPluginMsg_FileRef_RenameReply()));
+ reply));
return PP_OK_COMPLETIONPENDING;
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
index 2d07e2a54f6..211906a15a9 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
@@ -106,7 +106,7 @@ void PepperNetworkMonitorHost::SendNetworkList(
network_copy.addresses.resize(
1, ppapi::NetAddressPrivateImpl::kInvalidNetAddress);
bool result = ppapi::NetAddressPrivateImpl::IPEndPointToNetAddress(
- network.address, 0, &(network_copy.addresses[0]));
+ network.address.bytes(), 0, &(network_copy.addresses[0]));
DCHECK(result);
// TODO(sergeyu): Currently net::NetworkInterfaceList provides
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
index b80d1c6f9c3..1f9ac0effa6 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
@@ -10,6 +10,7 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -58,6 +59,9 @@ PepperNetworkProxyHost::~PepperNetworkProxyHost() {
PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {}
+PepperNetworkProxyHost::UIThreadData::UIThreadData(const UIThreadData& other) =
+ default;
+
PepperNetworkProxyHost::UIThreadData::~UIThreadData() {}
// static
@@ -67,13 +71,9 @@ PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
bool is_external_plugin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PepperNetworkProxyHost::UIThreadData result;
- RenderProcessHost* render_process_host =
- RenderProcessHost::FromID(render_process_id);
- if (render_process_host && render_process_host->GetBrowserContext()) {
- result.context_getter =
- render_process_host->GetBrowserContext()
- ->GetRequestContextForRenderProcess(render_process_id);
- }
+ RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
+ if (rph)
+ result.context_getter = rph->GetStoragePartition()->GetURLRequestContext();
SocketPermissionRequest request(
content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0);
@@ -146,6 +146,7 @@ void PepperNetworkProxyHost::TryToSendUnsentRequests() {
request.reply_context,
base::Owned(proxy_info));
int result = proxy_service_->ResolveProxy(request.url,
+ std::string(),
net::LOAD_NORMAL,
proxy_info,
callback,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
index 0992c9fc68d..309e692db09 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
@@ -48,6 +48,7 @@ class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
// DidGetUIThreadData, which sets allowed_ and proxy_service_.
struct UIThreadData {
UIThreadData();
+ UIThreadData(const UIThreadData& other);
~UIThreadData();
bool is_allowed;
scoped_refptr<net::URLRequestContextGetter> context_getter;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index 94ee8d71c81..cb87538b016 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -181,11 +181,12 @@ std::string AddressToFirewallString(const net::IPAddressNumber& address) {
void OpenFirewallHole(const net::IPEndPoint& address,
chromeos::FirewallHole::PortType type,
FirewallHoleOpenCallback callback) {
- if (IsLoopbackAddress(address.address())) {
+ if (IsLoopbackAddress(address.address().bytes())) {
callback.Run(nullptr);
return;
}
- std::string address_string = AddressToFirewallString(address.address());
+ std::string address_string =
+ AddressToFirewallString(address.address().bytes());
chromeos::FirewallHole::Open(type, address.port(), address_string, callback);
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index e342c233ba1..080a63a385c 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h"
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -15,9 +16,9 @@
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/socket_permission_request.h"
+#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -172,7 +173,7 @@ void PepperTCPServerSocketMessageFilter::DoListen(
int32_t backlog) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- net::IPAddressNumber address;
+ std::vector<uint8_t> address;
uint16_t port;
if (state_ != STATE_BEFORE_LISTENING ||
!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
@@ -186,7 +187,7 @@ void PepperTCPServerSocketMessageFilter::DoListen(
socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
int net_result = net::OK;
do {
- net::IPEndPoint ip_end_point(address, port);
+ net::IPEndPoint ip_end_point(net::IPAddress(address), port);
net_result = socket_->Open(ip_end_point.GetFamily());
if (net_result != net::OK)
break;
@@ -235,7 +236,7 @@ void PepperTCPServerSocketMessageFilter::OnListenCompleted(
return;
}
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- end_point.address(), end_point.port(), &addr)) {
+ end_point.address().bytes(), end_point.port(), &addr)) {
SendListenError(context, PP_ERROR_FAILED);
state_ = STATE_BEFORE_LISTENING;
return;
@@ -301,12 +302,10 @@ void PepperTCPServerSocketMessageFilter::OnAcceptCompleted(
return;
}
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- ip_end_point_local.address(),
- ip_end_point_local.port(),
+ ip_end_point_local.address().bytes(), ip_end_point_local.port(),
&local_addr) ||
!NetAddressPrivateImpl::IPEndPointToNetAddress(
- accepted_address_.address(),
- accepted_address_.port(),
+ accepted_address_.address().bytes(), accepted_address_.port(),
&remote_addr)) {
SendAcceptError(context, PP_ERROR_FAILED);
return;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 91a851228a7..661fdc52e5d 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -6,6 +6,7 @@
#include <cstring>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/location.h"
@@ -23,6 +24,7 @@
#include "net/base/address_family.h"
#include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/dns/single_request_host_resolver.h"
#include "net/socket/client_socket_factory.h"
@@ -573,14 +575,14 @@ void PepperTCPSocketMessageFilter::DoBind(
int pp_result = PP_OK;
do {
- net::IPAddressNumber address;
+ std::vector<uint8_t> address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(
net_addr, &address, &port)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
break;
}
- net::IPEndPoint bind_addr(address, port);
+ net::IPEndPoint bind_addr(net::IPAddress(address), port);
DCHECK(!socket_->IsValid());
pp_result = NetErrorToPepperError(socket_->Open(bind_addr.GetFamily()));
@@ -604,8 +606,7 @@ void PepperTCPSocketMessageFilter::DoBind(
PP_NetAddress_Private local_addr =
NetAddressPrivateImpl::kInvalidNetAddress;
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- ip_end_point_local.address(),
- ip_end_point_local.port(),
+ ip_end_point_local.address().bytes(), ip_end_point_local.port(),
&local_addr)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
break;
@@ -834,12 +835,10 @@ void PepperTCPSocketMessageFilter::OnConnectCompleted(
PP_NetAddress_Private remote_addr =
NetAddressPrivateImpl::kInvalidNetAddress;
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- ip_end_point_local.address(),
- ip_end_point_local.port(),
+ ip_end_point_local.address().bytes(), ip_end_point_local.port(),
&local_addr) ||
!NetAddressPrivateImpl::IPEndPointToNetAddress(
- ip_end_point_remote.address(),
- ip_end_point_remote.port(),
+ ip_end_point_remote.address().bytes(), ip_end_point_remote.port(),
&remote_addr)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
break;
@@ -1007,12 +1006,10 @@ void PepperTCPSocketMessageFilter::OnAcceptCompleted(
return;
}
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- ip_end_point_local.address(),
- ip_end_point_local.port(),
+ ip_end_point_local.address().bytes(), ip_end_point_local.port(),
&local_addr) ||
!NetAddressPrivateImpl::IPEndPointToNetAddress(
- accepted_address_.address(),
- accepted_address_.port(),
+ accepted_address_.address().bytes(), accepted_address_.port(),
&remote_addr)) {
SendAcceptError(context, PP_ERROR_ADDRESS_INVALID);
return;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index 2dc256b3dae..b5f6e14c89e 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -53,12 +53,14 @@ size_t g_num_instances = 0;
namespace content {
PepperUDPSocketMessageFilter::PendingSend::PendingSend(
- const net::IPAddressNumber& address,
+ const net::IPAddress& address,
int port,
const scoped_refptr<net::IOBufferWithSize>& buffer,
const ppapi::host::ReplyMessageContext& context)
- : address(address), port(port), buffer(buffer), context(context) {
-}
+ : address(address), port(port), buffer(buffer), context(context) {}
+
+PepperUDPSocketMessageFilter::PendingSend::PendingSend(
+ const PendingSend& other) = default;
PepperUDPSocketMessageFilter::PendingSend::~PendingSend() {
}
@@ -361,13 +363,13 @@ int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
if (!socket_)
return PP_ERROR_FAILED;
- net::IPAddressNumber group;
+ std::vector<uint8_t> group;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
- return NetErrorToPepperError(socket_->JoinGroup(group));
+ return NetErrorToPepperError(socket_->JoinGroup(net::IPAddress(group)));
}
int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
@@ -382,13 +384,13 @@ int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
if (!socket_)
return PP_ERROR_FAILED;
- net::IPAddressNumber group;
+ std::vector<uint8_t> group;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
- return NetErrorToPepperError(socket_->LeaveGroup(group));
+ return NetErrorToPepperError(socket_->LeaveGroup(net::IPAddress(group)));
}
void PepperUDPSocketMessageFilter::DoBind(
@@ -405,13 +407,13 @@ void PepperUDPSocketMessageFilter::DoBind(
net::DatagramSocket::DEFAULT_BIND, net::RandIntCallback(),
NULL, net::NetLog::Source()));
- net::IPAddressNumber address;
+ std::vector<uint8_t> address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
- net::IPEndPoint end_point(address, port);
+ net::IPEndPoint end_point(net::IPAddress(address), port);
{
int net_result = socket->Open(end_point.GetFamily());
if (net_result != net::OK) {
@@ -492,7 +494,8 @@ void PepperUDPSocketMessageFilter::DoBind(
PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- bound_address.address(), bound_address.port(), &net_address)) {
+ bound_address.address().bytes(), bound_address.port(),
+ &net_address)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
@@ -585,7 +588,7 @@ void PepperUDPSocketMessageFilter::DoSendTo(
return;
}
- net::IPAddressNumber address;
+ std::vector<uint8_t> address;
uint16_t port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
@@ -603,7 +606,8 @@ void PepperUDPSocketMessageFilter::DoSendTo(
return;
}
- pending_sends_.push(PendingSend(address, port, buffer, context));
+ pending_sends_.push(
+ PendingSend(net::IPAddress(address), port, buffer, context));
// If there are other sends pending, we can't start yet.
if (num_pending_sends)
return;
@@ -644,7 +648,8 @@ void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
if (pp_result >= 0 &&
!NetAddressPrivateImpl::IPEndPointToNetAddress(
- recvfrom_address_.address(), recvfrom_address_.port(), &addr)) {
+ recvfrom_address_.address().bytes(), recvfrom_address_.port(),
+ &addr)) {
pp_result = PP_ERROR_ADDRESS_INVALID;
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
index 314599beedf..64205819d09 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
@@ -19,6 +19,7 @@
#include "content/common/content_export.h"
#include "content/public/common/process_type.h"
#include "net/base/completion_callback.h"
+#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/udp/udp_socket.h"
#include "ppapi/c/pp_instance.h"
@@ -75,13 +76,14 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
};
struct PendingSend {
- PendingSend(const net::IPAddressNumber& address,
+ PendingSend(const net::IPAddress& address,
int port,
const scoped_refptr<net::IOBufferWithSize>& buffer,
const ppapi::host::ReplyMessageContext& context);
+ PendingSend(const PendingSend& other);
~PendingSend();
- net::IPAddressNumber address;
+ net::IPAddress address;
int port;
scoped_refptr<net::IOBufferWithSize> buffer;
ppapi::host::ReplyMessageContext context;
diff --git a/chromium/content/browser/renderer_host/pepper/quota_reservation.cc b/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
index 5343cbd153f..518421a7031 100644
--- a/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
+++ b/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "storage/browser/fileapi/quota/open_file_handle.h"
diff --git a/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc b/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
index c1068db228b..1416587d0fb 100644
--- a/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
+++ b/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
@@ -13,6 +13,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
diff --git a/chromium/content/browser/renderer_host/render_message_filter.cc b/chromium/content/browser/renderer_host/render_message_filter.cc
index cec7b8b1225..8d5ae8e9d47 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.cc
+++ b/chromium/content/browser/renderer_host/render_message_filter.cc
@@ -24,17 +24,20 @@
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/download/download_stats.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_widget_helper.h"
+#include "content/browser/resource_context_impl.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/child_process_messages.h"
#include "content/common/content_constants_internal.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/common/render_process_messages.h"
#include "content/common/view_messages.h"
@@ -42,12 +45,14 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/download_save_info.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_url_parameters.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/url_constants.h"
+#include "gpu/ipc/client/gpu_memory_buffer_impl.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_platform_file.h"
#include "media/audio/audio_manager.h"
@@ -62,6 +67,7 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/shared_impl/file_type_conversion.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "ui/gfx/color_profile.h"
#include "url/gurl.h"
@@ -100,6 +106,21 @@ base::LazyInstance<gfx::ColorProfile>::Leaky g_color_profile =
LAZY_INSTANCE_INITIALIZER;
#endif
+void DownloadUrlOnUIThread(scoped_ptr<DownloadUrlParameters> parameters) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderProcessHost* render_process_host =
+ RenderProcessHost::FromID(parameters->render_process_host_id());
+ if (!render_process_host)
+ return;
+
+ BrowserContext* browser_context = render_process_host->GetBrowserContext();
+ DownloadManager* download_manager =
+ BrowserContext::GetDownloadManager(browser_context);
+ RecordDownloadSource(INITIATED_BY_RENDERER);
+ download_manager->DownloadUrl(std::move(parameters));
+}
+
} // namespace
RenderMessageFilter::RenderMessageFilter(
@@ -118,9 +139,11 @@ RenderMessageFilter::RenderMessageFilter(
resource_context_(browser_context->GetResourceContext()),
render_widget_helper_(render_widget_helper),
dom_storage_context_(dom_storage_context),
+ gpu_process_id_(0),
render_process_id_(render_process_id),
audio_manager_(audio_manager),
- media_internals_(media_internals) {
+ media_internals_(media_internals),
+ weak_ptr_factory_(this) {
DCHECK(request_context_.get());
if (render_widget_helper)
@@ -169,6 +192,10 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
OnAllocateGpuMemoryBuffer)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ChildProcessHostMsg_EstablishGpuChannel,
+ OnEstablishGpuChannel)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ChildProcessHostMsg_HasGpuProcess,
+ OnHasGpuProcess)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
OnDeletedGpuMemoryBuffer)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_AllocatedSharedBitmap,
@@ -372,19 +399,26 @@ void RenderMessageFilter::DownloadUrl(int render_view_id,
if (!resource_context_)
return;
- scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
- save_info->suggested_name = suggested_name;
- save_info->prompt_for_save_location = use_prompt;
- scoped_ptr<net::URLRequest> request(
- resource_context_->GetRequestContext()->CreateRequest(
- url, net::DEFAULT_PRIORITY, NULL));
- RecordDownloadSource(INITIATED_BY_RENDERER);
- resource_dispatcher_host_->BeginDownload(
- std::move(request), referrer,
- true, // is_content_initiated
- resource_context_, render_process_id_, render_view_id, render_frame_id,
- false, false, std::move(save_info), DownloadItem::kInvalidId,
- ResourceDispatcherHostImpl::DownloadStartedCallback());
+ scoped_ptr<DownloadUrlParameters> parameters(
+ new DownloadUrlParameters(url, render_process_id_, render_view_id,
+ render_frame_id, resource_context_));
+ parameters->set_content_initiated(true);
+ parameters->set_suggested_name(suggested_name);
+ parameters->set_prompt(use_prompt);
+ parameters->set_referrer(referrer);
+
+ if (url.SchemeIsBlob()) {
+ ChromeBlobStorageContext* blob_context =
+ GetChromeBlobStorageContextForResourceContext(resource_context_);
+ parameters->set_blob_data_handle(
+ blob_context->context()->GetBlobDataFromPublicURL(url));
+ // Don't care if the above fails. We are going to let the download go
+ // through and allow it to be interrupted so that the embedder can deal.
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DownloadUrlOnUIThread, base::Passed(&parameters)));
}
void RenderMessageFilter::OnDownloadUrl(int render_view_id,
@@ -639,6 +673,74 @@ void RenderMessageFilter::GpuMemoryBufferAllocated(
Send(reply);
}
+void RenderMessageFilter::OnEstablishGpuChannel(
+ CauseForGpuLaunch cause_for_gpu_launch,
+ IPC::Message* reply_ptr) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ scoped_ptr<IPC::Message> reply(reply_ptr);
+
+#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
+ // TODO(jbauman): Remove this when we know why renderer processes are
+ // hanging on x86-64. https://crbug.com/577127
+ if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
+ reply->set_reply_error();
+ Send(reply.release());
+ return;
+ }
+#endif
+
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
+ if (!host) {
+ host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ cause_for_gpu_launch);
+ if (!host) {
+ reply->set_reply_error();
+ Send(reply.release());
+ return;
+ }
+
+ gpu_process_id_ = host->host_id();
+ }
+
+ bool preempts = false;
+ bool allow_view_command_buffers = false;
+ bool allow_real_time_streams = false;
+ host->EstablishGpuChannel(
+ render_process_id_,
+ ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
+ render_process_id_),
+ preempts, allow_view_command_buffers, allow_real_time_streams,
+ base::Bind(&RenderMessageFilter::EstablishChannelCallback,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&reply)));
+}
+
+void RenderMessageFilter::OnHasGpuProcess(IPC::Message* reply_ptr) {
+ scoped_ptr<IPC::Message> reply(reply_ptr);
+ GpuProcessHost::GetProcessHandles(
+ base::Bind(&RenderMessageFilter::GetGpuProcessHandlesCallback,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&reply)));
+}
+
+void RenderMessageFilter::EstablishChannelCallback(
+ scoped_ptr<IPC::Message> reply,
+ const IPC::ChannelHandle& channel,
+ const gpu::GPUInfo& gpu_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ChildProcessHostMsg_EstablishGpuChannel::WriteReplyParams(
+ reply.get(), render_process_id_, channel, gpu_info);
+ Send(reply.release());
+}
+
+void RenderMessageFilter::GetGpuProcessHandlesCallback(
+ scoped_ptr<IPC::Message> reply,
+ const std::list<base::ProcessHandle>& handles) {
+ bool has_gpu_process = handles.size() > 0;
+ ChildProcessHostMsg_HasGpuProcess::WriteReplyParams(reply.get(),
+ has_gpu_process);
+ Send(reply.release());
+}
+
void RenderMessageFilter::OnDeletedGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gpu::SyncToken& sync_token) {
diff --git a/chromium/content/browser/renderer_host/render_message_filter.h b/chromium/content/browser/renderer_host/render_message_filter.h
index ce07dfee796..a42690e2808 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.h
+++ b/chromium/content/browser/renderer_host/render_message_filter.h
@@ -15,13 +15,16 @@
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "cc/resources/shared_bitmap_manager.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/common/host_discardable_shared_memory_manager.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/browser/browser_message_filter.h"
+#include "gpu/config/gpu_info.h"
#include "ipc/message_filter.h"
#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
@@ -160,6 +163,16 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
void OnGetMonitorColorProfile(std::vector<char>* profile);
#endif
+ // Message handlers called on the browser IO thread:
+ void OnEstablishGpuChannel(CauseForGpuLaunch, IPC::Message* reply);
+ void OnHasGpuProcess(IPC::Message* reply);
+ // Helper callbacks for the message handlers.
+ void EstablishChannelCallback(scoped_ptr<IPC::Message> reply,
+ const IPC::ChannelHandle& channel,
+ const gpu::GPUInfo& gpu_info);
+ void GetGpuProcessHandlesCallback(
+ scoped_ptr<IPC::Message> reply,
+ const std::list<base::ProcessHandle>& handles);
// Used to ask the browser to allocate a block of shared memory for the
// renderer to send back data in, since shared memory can't be created
// in the renderer on POSIX due to the sandbox.
@@ -234,11 +247,14 @@ class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
scoped_refptr<DOMStorageContextWrapper> dom_storage_context_;
+ int gpu_process_id_;
int render_process_id_;
media::AudioManager* audio_manager_;
MediaInternals* media_internals_;
+ base::WeakPtrFactory<RenderMessageFilter> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RenderMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.cc b/chromium/content/browser/renderer_host/render_process_host_impl.cc
index 667dc22a081..248555b5937 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.cc
@@ -24,8 +24,11 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/metrics/field_trial.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
@@ -45,6 +48,7 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/background_sync/background_sync_service_impl.h"
#include "content/browser/bad_message.h"
+#include "content/browser/blob_storage/blob_dispatcher_host.h"
#include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
#include "content/browser/browser_child_process_host_impl.h"
#include "content/browser/browser_main.h"
@@ -80,7 +84,7 @@
#include "content/browser/message_port_message_filter.h"
#include "content/browser/mime_registry_message_filter.h"
#include "content/browser/mojo/mojo_application_host.h"
-#include "content/browser/navigator_connect/service_port_service_impl.h"
+#include "content/browser/mojo/mojo_child_connection.h"
#include "content/browser/notifications/notification_message_filter.h"
#include "content/browser/permissions/permission_service_context.h"
#include "content/browser/permissions/permission_service_impl.h"
@@ -91,13 +95,11 @@
#include "content/browser/renderer_host/database_message_filter.h"
#include "content/browser/renderer_host/file_utilities_message_filter.h"
#include "content/browser/renderer_host/gamepad_browser_message_filter.h"
-#include "content/browser/renderer_host/gpu_message_filter.h"
#include "content/browser/renderer_host/media/audio_input_renderer_host.h"
#include "content/browser/renderer_host/media/audio_renderer_host.h"
#include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
#include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
#include "content/browser/renderer_host/media/video_capture_host.h"
-#include "content/browser/renderer_host/memory_benchmark_message_filter.h"
#include "content/browser/renderer_host/pepper/pepper_message_filter.h"
#include "content/browser/renderer_host/pepper/pepper_renderer_connection.h"
#include "content/browser/renderer_host/render_message_filter.h"
@@ -121,17 +123,18 @@
#include "content/common/child_process_messages.h"
#include "content/common/content_switches_internal.h"
#include "content/common/frame_messages.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu_host_messages.h"
#include "content/common/in_process_child_thread_params.h"
#include "content/common/mojo/channel_init.h"
#include "content/common/mojo/mojo_messages.h"
+#include "content/common/mojo/mojo_shell_connection_impl.h"
#include "content/common/render_process_messages.h"
#include "content/common/resource_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/navigator_connect_context.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host_factory.h"
@@ -165,12 +168,11 @@
#include "ipc/ipc_switches.h"
#include "ipc/mojo/ipc_channel_mojo.h"
#include "media/base/media_switches.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/shell/runner/common/switches.h"
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/shared_impl/ppapi_switches.h"
#include "storage/browser/fileapi/sandbox_file_system_backend.h"
-#include "third_party/icu/source/common/unicode/unistr.h"
-#include "third_party/icu/source/i18n/unicode/timezone.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_switches.h"
@@ -197,14 +199,18 @@
#include "ui/gfx/win/dpi.h"
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
#include "content/browser/bootstrap_sandbox_manager_mac.h"
#include "content/browser/mach_broker_mac.h"
#endif
+#if defined(OS_POSIX)
+#include "content/browser/zygote_host/zygote_communication_linux.h"
+#include "content/browser/zygote_host/zygote_host_impl_linux.h"
+#include "content/public/browser/zygote_handle_linux.h"
+#endif // defined(OS_POSIX)
+
#if defined(USE_OZONE)
-#include "ui/ozone/public/client_native_pixmap_factory.h"
-#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#endif
@@ -217,7 +223,7 @@
#endif
#if defined(ENABLE_WEBRTC)
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
#include "content/browser/renderer_host/media/media_stream_track_metrics_host.h"
#include "content/browser/renderer_host/media/webrtc_identity_service_host.h"
#include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
@@ -225,11 +231,6 @@
#include "content/common/media/media_stream_messages.h"
#endif
-#if defined(MOJO_SHELL_CLIENT)
-#include "content/browser/mojo/mojo_shell_client_host.h"
-#include "content/common/mojo/mojo_shell_connection_impl.h"
-#endif
-
#if defined(OS_WIN)
#define IntToStringType base::IntToString16
#else
@@ -284,8 +285,7 @@ void GetContexts(
#if defined(ENABLE_WEBRTC)
// Creates a file used for handing over to the renderer.
-IPC::PlatformFileForTransit CreateFileForProcess(base::FilePath file_path,
- base::ProcessHandle process) {
+IPC::PlatformFileForTransit CreateFileForProcess(base::FilePath file_path) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::File dump_file(file_path,
base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
@@ -294,16 +294,12 @@ IPC::PlatformFileForTransit CreateFileForProcess(base::FilePath file_path,
<< dump_file.error_details();
return IPC::InvalidPlatformFileForTransit();
}
- return IPC::TakeFileHandleForProcess(std::move(dump_file), process);
+ return IPC::TakePlatformFileForTransit(std::move(dump_file));
}
// Allow us to only run the trial in the first renderer.
bool has_done_stun_trials = false;
-// Does nothing. Just to avoid races between enable and disable.
-void DisableAecDumpOnFileThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-}
#endif
// the global list of all renderer processes
@@ -363,6 +359,12 @@ SiteProcessMap* GetSiteProcessMapForBrowserContext(BrowserContext* context) {
return map;
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+// This static member variable holds the zygote communication information for
+// the renderer.
+ZygoteHandle g_render_zygote;
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
// NOTE: changes to this class need to be reviewed by the security team.
class RendererSandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
@@ -390,13 +392,17 @@ class RendererSandboxedProcessLauncherDelegate
}
#elif defined(OS_POSIX)
- bool ShouldUseZygote() override {
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+ ZygoteHandle* GetZygote() override {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType renderer_prefix =
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
- return renderer_prefix.empty();
+ if (!renderer_prefix.empty())
+ return nullptr;
+ return GetGenericZygote();
}
+#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); }
#endif // OS_WIN
@@ -439,24 +445,6 @@ std::string UintVectorToString(const std::vector<unsigned>& vector) {
return str;
}
-// Copies kEnableFeatures and kDisableFeatures to the renderer command line.
-// Generates them from the FeatureList override state, to take into account
-// overrides from FieldTrials.
-void CopyEnableDisableFeatureFlagsToRenderer(base::CommandLine* renderer_cmd) {
- std::string enabled_features;
- std::string disabled_features;
- base::FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
- &disabled_features);
- if (!enabled_features.empty()) {
- renderer_cmd->AppendSwitchASCII(switches::kEnableFeatures,
- enabled_features);
- }
- if (!disabled_features.empty()) {
- renderer_cmd->AppendSwitchASCII(switches::kDisableFeatures,
- disabled_features);
- }
-}
-
} // namespace
RendererMainThreadFactoryFunction g_renderer_main_thread_factory = NULL;
@@ -526,6 +514,18 @@ void RenderProcessHost::SetMaxRendererProcessCount(size_t count) {
g_max_renderer_count_override = count;
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+// static
+void RenderProcessHostImpl::EarlyZygoteLaunch() {
+ DCHECK(!g_render_zygote);
+ // TODO(kerrnel): Investigate doing this without the ZygoteHostImpl as a
+ // proxy. It is currently done this way due to concerns about race
+ // conditions.
+ ZygoteHostImpl::GetInstance()->SetRendererSandboxStatus(
+ (*GetGenericZygote())->GetSandboxStatus());
+}
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
RenderProcessHostImpl::RenderProcessHostImpl(
BrowserContext* browser_context,
StoragePartitionImpl* storage_partition_impl,
@@ -592,17 +592,13 @@ RenderProcessHostImpl::RenderProcessHostImpl(
// render process. This ensures that when a test is being run in one of the
// single process modes, the global attachment broker is the privileged
// attachment broker, rather than an unprivileged attachment broker.
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded(
MachBroker::GetInstance());
#else
IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded();
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif // defined(OS_MACOSX)
#endif // USE_ATTACHMENT_BROKER
-
-#if defined(MOJO_SHELL_CLIENT)
- RegisterChildWithExternalShell(id_, this);
-#endif
}
// static
@@ -681,6 +677,8 @@ bool RenderProcessHostImpl::Init() {
if (channel_)
return true;
+ shell_pipe_token_ = MojoConnectToChild(id_, instance_id_++, this);
+
base::CommandLine::StringType renderer_prefix;
// A command prefix is something prepended to the command line of the spawned
// process.
@@ -709,10 +707,6 @@ bool RenderProcessHostImpl::Init() {
const std::string channel_id =
IPC::Channel::GenerateVerifiedChannelID(std::string());
channel_ = CreateChannelProxy(channel_id);
-#if USE_ATTACHMENT_BROKER
- IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel(
- channel_.get());
-#endif
// Setup the Mojo channel.
mojo_application_host_->Init();
@@ -735,7 +729,8 @@ bool RenderProcessHostImpl::Init() {
g_renderer_main_thread_factory(InProcessChildThreadParams(
channel_id,
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
- ->task_runner())));
+ ->task_runner(),
+ in_process_renderer_handle_.release())));
base::Thread::Options options;
#if defined(OS_WIN) && !defined(OS_MACOSX)
@@ -792,11 +787,18 @@ scoped_ptr<IPC::ChannelProxy> RenderProcessHostImpl::CreateChannelProxy(
const std::string& channel_id) {
scoped_refptr<base::SingleThreadTaskRunner> runner =
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
- scoped_refptr<base::SequencedTaskRunner> mojo_task_runner =
- BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
- ->task_runner();
if (ShouldUseMojoChannel()) {
VLOG(1) << "Mojo Channel is enabled on host";
+ mojo::ScopedMessagePipeHandle handle;
+
+ if (run_renderer_in_process()) {
+ mojo::MessagePipe pipe;
+ handle = std::move(pipe.handle0);
+ in_process_renderer_handle_ = std::move(pipe.handle1);
+ } else {
+ mojo_channel_token_ = mojo::edk::GenerateRandomToken();
+ handle = mojo::edk::CreateParentMessagePipe(mojo_channel_token_);
+ }
// Do NOT expand ifdef or run time condition checks here! Synchronous
// IPCs from browser process are banned. It is only narrowly allowed
@@ -806,14 +808,20 @@ scoped_ptr<IPC::ChannelProxy> RenderProcessHostImpl::CreateChannelProxy(
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIPCSyncCompositing)) {
return IPC::SyncChannel::Create(
- IPC::ChannelMojo::CreateServerFactory(mojo_task_runner, channel_id),
- this, runner.get(), true, &never_signaled_);
+ IPC::ChannelMojo::CreateServerFactory(std::move(handle)), this,
+ runner.get(), true, &never_signaled_);
}
#endif // OS_ANDROID
- return IPC::ChannelProxy::Create(
- IPC::ChannelMojo::CreateServerFactory(mojo_task_runner, channel_id),
- this, runner.get());
+ std::unique_ptr<IPC::ChannelProxy> channel(
+ new IPC::ChannelProxy(this, runner.get()));
+#if USE_ATTACHMENT_BROKER
+ IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel(
+ channel.get(), content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::IO));
+#endif
+ channel->Init(IPC::ChannelMojo::CreateServerFactory(std::move(handle)), true);
+ return channel;
}
// Do NOT expand ifdef or run time condition checks here! See comment above.
@@ -825,8 +833,15 @@ scoped_ptr<IPC::ChannelProxy> RenderProcessHostImpl::CreateChannelProxy(
}
#endif // OS_ANDROID
- return IPC::ChannelProxy::Create(channel_id, IPC::Channel::MODE_SERVER, this,
- runner.get());
+ std::unique_ptr<IPC::ChannelProxy> channel(
+ new IPC::ChannelProxy(this, runner.get()));
+#if USE_ATTACHMENT_BROKER
+ IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel(
+ channel.get(), content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::IO));
+#endif
+ channel->Init(channel_id, IPC::Channel::MODE_SERVER, true);
+ return channel;
}
void RenderProcessHostImpl::CreateMessageFilters() {
@@ -843,10 +858,12 @@ void RenderProcessHostImpl::CreateMessageFilters() {
new BrowserPluginMessageFilter(GetID()));
AddFilter(bp_message_filter.get());
+ scoped_refptr<net::URLRequestContextGetter> request_context(
+ storage_partition_impl_->GetURLRequestContext());
scoped_refptr<RenderMessageFilter> render_message_filter(
new RenderMessageFilter(
GetID(), GetBrowserContext(),
- GetBrowserContext()->GetRequestContextForRenderProcess(GetID()),
+ request_context.get(),
widget_helper_.get(), audio_manager, media_internals,
storage_partition_impl_->GetDOMStorageContext()));
AddFilter(render_message_filter.get());
@@ -858,13 +875,11 @@ void RenderProcessHostImpl::CreateMessageFilters() {
nullptr,
#endif
GetBrowserContext(),
- GetBrowserContext()->GetRequestContextForRenderProcess(GetID()),
+ request_context.get(),
widget_helper_.get()));
BrowserContext* browser_context = GetBrowserContext();
ResourceContext* resource_context = browser_context->GetResourceContext();
- scoped_refptr<net::URLRequestContextGetter> request_context(
- browser_context->GetRequestContextForRenderProcess(GetID()));
scoped_refptr<net::URLRequestContextGetter> media_request_context(
browser_context->GetMediaRequestContextForRenderProcess(GetID()));
@@ -872,10 +887,14 @@ void RenderProcessHostImpl::CreateMessageFilters() {
base::Bind(&GetContexts, browser_context->GetResourceContext(),
request_context, media_request_context));
+ // Several filters need the Blob storage context, so fetch it in advance.
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context =
+ ChromeBlobStorageContext::GetFor(browser_context);
+
ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
GetID(), PROCESS_TYPE_RENDERER,
storage_partition_impl_->GetAppCacheService(),
- ChromeBlobStorageContext::GetFor(browser_context),
+ blob_storage_context.get(),
storage_partition_impl_->GetFileSystemContext(),
storage_partition_impl_->GetServiceWorkerContext(),
storage_partition_impl_->GetHostZoomLevelContext(),
@@ -907,10 +926,8 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new IndexedDBDispatcherHost(
GetID(), storage_partition_impl_->GetURLRequestContext(),
storage_partition_impl_->GetIndexedDBContext(),
- ChromeBlobStorageContext::GetFor(browser_context)));
+ blob_storage_context.get()));
- gpu_message_filter_ = new GpuMessageFilter(GetID());
- AddFilter(gpu_message_filter_);
#if defined(ENABLE_WEBRTC)
AddFilter(new WebRTCIdentityServiceHost(
GetID(), storage_partition_impl_->GetWebRTCIdentityStore(),
@@ -930,8 +947,8 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new FileAPIMessageFilter(
GetID(), storage_partition_impl_->GetURLRequestContext(),
storage_partition_impl_->GetFileSystemContext(),
- ChromeBlobStorageContext::GetFor(browser_context),
- StreamContext::GetFor(browser_context)));
+ blob_storage_context.get(), StreamContext::GetFor(browser_context)));
+ AddFilter(new BlobDispatcherHost(blob_storage_context.get()));
AddFilter(new FileUtilitiesMessageFilter(GetID()));
AddFilter(new MimeRegistryMessageFilter());
AddFilter(
@@ -959,8 +976,9 @@ void RenderProcessHostImpl::CreateMessageFilters() {
base::Bind(&GetRequestContext, request_context, media_request_context,
RESOURCE_TYPE_SUB_RESOURCE));
- AddFilter(
- new WebSocketDispatcherHost(GetID(), websocket_request_context_callback));
+ AddFilter(new WebSocketDispatcherHost(
+ GetID(), websocket_request_context_callback, blob_storage_context.get(),
+ storage_partition_impl_));
message_port_message_filter_ = new MessagePortMessageFilter(
base::Bind(&RenderWidgetHelper::GetNextRoutingID,
@@ -994,14 +1012,12 @@ void RenderProcessHostImpl::CreateMessageFilters() {
#if defined(ENABLE_WEBRTC)
p2p_socket_dispatcher_host_ = new P2PSocketDispatcherHost(
- resource_context,
- browser_context->GetRequestContextForRenderProcess(GetID()));
+ resource_context, request_context.get());
AddFilter(p2p_socket_dispatcher_host_.get());
#endif
AddFilter(new TraceMessageFilter(GetID()));
- AddFilter(new ResolveProxyMsgHelper(
- browser_context->GetRequestContextForRenderProcess(GetID())));
+ AddFilter(new ResolveProxyMsgHelper(request_context.get()));
AddFilter(new QuotaDispatcherHost(
GetID(), storage_partition_impl_->GetQuotaManager(),
GetContentClient()->browser()->CreateQuotaPermissionContext()));
@@ -1018,19 +1034,22 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new DeviceOrientationAbsoluteMessageFilter());
AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER));
AddFilter(new HistogramMessageFilter());
-#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
- if (browser_command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
- AddFilter(new MemoryBenchmarkMessageFilter());
-#endif
AddFilter(new MemoryMessageFilter(this));
AddFilter(new PushMessagingMessageFilter(
GetID(), storage_partition_impl_->GetServiceWorkerContext()));
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
AddFilter(new ScreenOrientationMessageFilterAndroid());
#endif
AddFilter(new GeofencingDispatcherHost(
storage_partition_impl_->GetGeofencingManager()));
- if (browser_command_line.HasSwitch(switches::kEnableWebBluetooth)) {
+
+ bool enable_web_bluetooth =
+ browser_command_line.HasSwitch(switches::kEnableWebBluetooth);
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+ enable_web_bluetooth = true;
+#endif
+
+ if (enable_web_bluetooth) {
bluetooth_dispatcher_host_ = new BluetoothDispatcherHost(GetID());
AddFilter(bluetooth_dispatcher_host_.get());
}
@@ -1053,10 +1072,9 @@ void RenderProcessHostImpl::RegisterMojoServices() {
&BackgroundSyncContextImpl::CreateService,
base::Unretained(storage_partition_impl_->GetBackgroundSyncContext())));
- mojo_application_host_->service_registry()->AddService(base::Bind(
- &content::ServicePortServiceImpl::Create,
- make_scoped_refptr(storage_partition_impl_->GetNavigatorConnectContext()),
- message_port_message_filter_));
+ mojo_application_host_->service_registry()->AddService(
+ base::Bind(&RenderProcessHostImpl::CreateStoragePartitionService,
+ base::Unretained(this)));
#if defined(OS_ANDROID)
ServiceRegistrarAndroid::RegisterProcessHostServices(
@@ -1067,6 +1085,15 @@ void RenderProcessHostImpl::RegisterMojoServices() {
mojo_application_host_->service_registry());
}
+void RenderProcessHostImpl::CreateStoragePartitionService(
+ mojo::InterfaceRequest<mojom::StoragePartitionService> request) {
+ // DO NOT REMOVE THIS COMMAND LINE CHECK WITHOUT SECURITY REVIEW!
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kMojoLocalStorage)) {
+ storage_partition_impl_->Bind(std::move(request));
+ }
+}
+
int RenderProcessHostImpl::GetNextRoutingID() {
return widget_helper_->GetNextRoutingID();
}
@@ -1085,6 +1112,11 @@ ServiceRegistry* RenderProcessHostImpl::GetServiceRegistry() {
return mojo_application_host_->service_registry();
}
+scoped_ptr<base::SharedPersistentMemoryAllocator>
+RenderProcessHostImpl::TakeMetricsAllocator() {
+ return std::move(metrics_allocator_);
+}
+
const base::TimeTicks& RenderProcessHostImpl::GetInitTimeForNavigationMetrics()
const {
return init_time_;
@@ -1227,9 +1259,6 @@ StoragePartition* RenderProcessHostImpl::GetStoragePartition() const {
}
static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
- if (IsPropertyTreeVerificationEnabled())
- command_line->AppendSwitch(cc::switches::kEnablePropertyTreeVerification);
-
command_line->AppendSwitchASCII(
switches::kNumRasterThreads,
base::IntToString(NumberOfRendererRasterThreads()));
@@ -1245,8 +1274,8 @@ static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
if (IsZeroCopyUploadEnabled())
command_line->AppendSwitch(switches::kEnableZeroCopy);
- if (IsPartialRasterEnabled())
- command_line->AppendSwitch(switches::kEnablePartialRaster);
+ if (!IsPartialRasterEnabled())
+ command_line->AppendSwitch(switches::kDisablePartialRaster);
if (IsForceGpuRasterizationEnabled())
command_line->AppendSwitch(switches::kForceGpuRasterization);
@@ -1259,6 +1288,9 @@ static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
// Persistent buffers may come at a performance hit (not all platform specific
// buffers support it), so only enable them if partial raster is enabled and
// we are actually going to use them.
+ // TODO(dcastagna): Once GPU_READ_CPU_READ_WRITE_PERSISTENT is removed
+ // kContentImageTextureTarget and kVideoImageTextureTarget can be merged into
+ // one flag.
gfx::BufferUsage buffer_usage =
IsPartialRasterEnabled()
? gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT
@@ -1274,10 +1306,15 @@ static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
command_line->AppendSwitchASCII(switches::kContentImageTextureTarget,
UintVectorToString(image_targets));
- command_line->AppendSwitchASCII(
- switches::kVideoImageTextureTarget,
- base::UintToString(BrowserGpuMemoryBufferManager::GetImageTextureTarget(
- gfx::BufferFormat::R_8, gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)));
+ for (size_t format = 0;
+ format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) {
+ image_targets[format] =
+ BrowserGpuMemoryBufferManager::GetImageTextureTarget(
+ static_cast<gfx::BufferFormat>(format),
+ gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
+ }
+ command_line->AppendSwitchASCII(switches::kVideoImageTextureTarget,
+ UintVectorToString(image_targets));
// Appending disable-gpu-feature switches due to software rendering list.
GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
@@ -1306,16 +1343,6 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
GetContentClient()->browser()->GetApplicationLocale();
command_line->AppendSwitchASCII(switches::kLang, locale);
- // If we run base::FieldTrials, we want to pass to their state to the
- // renderer so that it can act in accordance with each state, or record
- // histograms relating to the base::FieldTrial states.
- std::string field_trial_states;
- base::FieldTrialList::AllStatesToString(&field_trial_states);
- if (!field_trial_states.empty()) {
- command_line->AppendSwitchASCII(switches::kForceFieldTrials,
- field_trial_states);
- }
-
GetContentClient()->browser()->AppendExtraCommandLineSwitches(command_line,
GetID());
@@ -1328,6 +1355,11 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
#endif
AppendCompositorCommandLineFlags(command_line);
+
+ if (!mojo_channel_token_.empty()) {
+ command_line->AppendSwitchASCII(switches::kMojoChannelToken,
+ mojo_channel_token_);
+ }
}
void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
@@ -1337,27 +1369,27 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// with any associated values) if present in the browser command line.
static const char* const kSwitchNames[] = {
switches::kAgcStartupMinVolume,
+ switches::kAecRefinedAdaptiveFilter,
switches::kAllowLoopbackInPeerConnection,
+ switches::kAndroidFontsPath,
switches::kAudioBufferSize,
switches::kBlinkPlatformLogChannels,
switches::kBlinkSettings,
switches::kDefaultTileWidth,
switches::kDefaultTileHeight,
+ switches::kDisable2dCanvasImageChromium,
switches::kDisable3DAPIs,
switches::kDisableAcceleratedJpegDecoding,
switches::kDisableAcceleratedVideoDecode,
switches::kDisableBlinkFeatures,
switches::kDisableBreakpad,
- switches::kDisableCompositorAnimationTimelines,
switches::kDisablePreferCompositingToLCDText,
switches::kDisableDatabases,
- switches::kDisableDelayAgnosticAec,
- switches::kDisableDirectNPAPIRequests,
switches::kDisableDisplayList2dCanvas,
switches::kDisableDistanceFieldText,
- switches::kDisableEncryptedMedia,
switches::kDisableFileSystem,
switches::kDisableGestureRequirementForMediaPlayback,
+ switches::kDisableGestureRequirementForPresentation,
switches::kDisableGpuCompositing,
switches::kDisableGpuMemoryBufferVideoFrames,
switches::kDisableGpuVsync,
@@ -1367,9 +1399,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableLCDText,
switches::kDisableLocalStorage,
switches::kDisableLogging,
- switches::kDisableMediaSource,
switches::kDisableMediaSuspend,
- switches::kDisableMojoChannel,
switches::kDisableNotifications,
switches::kDisableOverlayScrollbar,
switches::kDisablePermissionsAPI,
@@ -1386,10 +1416,11 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableTouchAdjustment,
switches::kDisableTouchDragDrop,
switches::kDisableV8IdleTasks,
+ switches::kDisableWebGLImageChromium,
+ switches::kDisableWheelGestures,
switches::kDomAutomationController,
switches::kEnableBlinkFeatures,
switches::kEnableBrowserSideNavigation,
- switches::kEnableCredentialManagerAPI,
switches::kEnableDisplayList2dCanvas,
switches::kEnableDistanceFieldText,
switches::kEnableExperimentalCanvasFeatures,
@@ -1403,19 +1434,19 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableLinkDisambiguationPopup,
switches::kEnableLowResTiling,
switches::kEnableMediaSuspend,
+ switches::kEnableMojoChannel,
switches::kEnableInbandTextTracks,
switches::kEnableLCDText,
switches::kEnableLogging,
switches::kEnableMemoryBenchmarking,
switches::kEnableNetworkInformation,
+ switches::kEnableNotificationActionIcons,
switches::kEnableOverlayScrollbar,
switches::kEnablePinch,
switches::kEnablePluginPlaceholderTesting,
switches::kEnablePreciseMemoryInfo,
switches::kEnablePreferCompositingToLCDText,
- switches::kEnablePrefixedEncryptedMedia,
switches::kEnableRGBA4444Textures,
- switches::kEnableRendererMojoChannel,
switches::kEnableSkiaBenchmarking,
switches::kEnableSlimmingPaintV2,
switches::kEnableSmoothScrolling,
@@ -1430,6 +1461,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableWebGLDraftExtensions,
switches::kEnableWebGLImageChromium,
switches::kEnableWebVR,
+ switches::kEnableWheelGestures,
switches::kExplicitlyAllowedPorts,
switches::kForceDeviceScaleFactor,
switches::kForceDisplayList2dCanvas,
@@ -1443,6 +1475,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kMaxUntiledLayerWidth,
switches::kMaxUntiledLayerHeight,
switches::kMemoryMetrics,
+ switches::kMojoLocalStorage,
switches::kNoReferrers,
switches::kNoSandbox,
switches::kOverridePluginPowerSaverForTesting,
@@ -1457,6 +1490,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kSitePerProcess,
switches::kStatsCollectionController,
switches::kTestType,
+ switches::kTopDocumentIsolation,
switches::kTouchEvents,
switches::kTouchTextSelectionStrategy,
switches::kTraceConfigFile,
@@ -1467,8 +1501,6 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// --in-process-webgl.
switches::kUseGL,
switches::kUseMobileUserAgent,
- switches::kUseNewMediaCache,
- switches::kUseNormalPriorityForTileTaskWorkerThreads,
switches::kUseRemoteCompositing,
switches::kV,
switches::kVideoThreads,
@@ -1478,24 +1510,23 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// also be added to chrome/browser/chromeos/login/chrome_restart_request.cc.
cc::switches::kDisableCachedPictureRaster,
cc::switches::kDisableCompositedAntialiasing,
- cc::switches::kDisableCompositorPropertyTrees,
cc::switches::kDisableMainFrameBeforeActivation,
cc::switches::kDisableThreadedAnimation,
cc::switches::kEnableBeginFrameScheduling,
cc::switches::kEnableGpuBenchmarking,
cc::switches::kEnableMainFrameBeforeActivation,
+ cc::switches::kEnableTileCompression,
cc::switches::kShowCompositedLayerBorders,
+ cc::switches::kShowFPSCounter,
cc::switches::kShowLayerAnimationBounds,
cc::switches::kShowPropertyChangedRects,
cc::switches::kShowReplicaScreenSpaceRects,
cc::switches::kShowScreenSpaceRects,
cc::switches::kShowSurfaceDamageRects,
cc::switches::kSlowDownRasterScaleFactor,
- cc::switches::kStrictLayerPropertyChangeChecking,
cc::switches::kTopControlsHideThreshold,
cc::switches::kTopControlsShowThreshold,
- scheduler::switches::kEnableVirtualizedTime,
scheduler::switches::kDisableBackgroundTimerThrottling,
#if defined(ENABLE_PLUGINS)
@@ -1514,8 +1545,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableLowEndDeviceMode,
switches::kDisableLowEndDeviceMode,
#if defined(OS_ANDROID)
- switches::kDisableWebAudio,
- switches::kEnableUnifiedMediaPipeline,
+ switches::kDisableUnifiedMediaPipeline,
switches::kIPCSyncCompositing,
switches::kRendererWaitForJavaDebugger,
#endif
@@ -1526,6 +1556,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
#if defined(OS_WIN)
switches::kDisableDirectWrite,
switches::kDisableWin32kRendererLockDown,
+ switches::kTrySupportedChannelLayouts,
switches::kTraceExportEventsToETW,
#endif
#if defined(USE_OZONE)
@@ -1534,12 +1565,11 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
#if defined(OS_CHROMEOS)
switches::kDisableVaapiAcceleratedVideoEncode,
#endif
- "use-new-edk", // TODO(use_chrome_edk): temporary.
};
renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
arraysize(kSwitchNames));
- CopyEnableDisableFeatureFlagsToRenderer(renderer_cmd);
+ BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd);
if (browser_cmd.HasSwitch(switches::kTraceStartup) &&
BrowserMainLoop::GetInstance()->is_tracing_startup_for_duration()) {
@@ -1578,9 +1608,19 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
}
}
-#if defined(MOJO_SHELL_CLIENT)
- if (IsRunningInMojoShell())
- renderer_cmd->AppendSwitch(switches::kEnableMojoShellConnection);
+ if (!shell_pipe_token_.empty()) {
+ renderer_cmd->AppendSwitchASCII(switches::kPrimordialPipeToken,
+ shell_pipe_token_);
+ }
+
+#if defined(OS_WIN) && !defined(OFFICIAL_BUILD)
+ // Needed because we can't show the dialog from the sandbox. Don't pass
+ // --no-sandbox in official builds because that would bypass the bad_flgs
+ // prompt.
+ if (renderer_cmd->HasSwitch(switches::kRendererStartupDialog) &&
+ !renderer_cmd->HasSwitch(switches::kNoSandbox)) {
+ renderer_cmd->AppendSwitch(switches::kNoSandbox);
+ }
#endif
}
@@ -1651,9 +1691,18 @@ bool RenderProcessHostImpl::FastShutdownIfPossible() {
bool RenderProcessHostImpl::Send(IPC::Message* msg) {
TRACE_EVENT0("renderer_host", "RenderProcessHostImpl::Send");
+#if !defined(OS_ANDROID)
+ DCHECK(!msg->is_sync());
+#endif
+
if (!channel_) {
+#if defined(OS_ANDROID)
+ if (msg->is_sync()) {
+ delete msg;
+ return false;
+ }
+#endif
if (!is_initialized_) {
- DCHECK(!msg->is_sync());
queued_messages_.push(msg);
return true;
} else {
@@ -1663,6 +1712,12 @@ bool RenderProcessHostImpl::Send(IPC::Message* msg) {
}
if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
+#if defined(OS_ANDROID)
+ if (msg->is_sync()) {
+ delete msg;
+ return false;
+ }
+#endif
queued_messages_.push(msg);
return true;
}
@@ -1741,12 +1796,6 @@ void RenderProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
tracked_objects::ThreadData::status();
Send(new ChildProcessMsg_SetProfilerStatus(status));
-#if defined(USE_OZONE)
- Send(new ChildProcessMsg_InitializeClientNativePixmapFactory(
- base::FileDescriptor(
- ui::OzonePlatform::GetInstance()->OpenClientNativePixmapDevice())));
-#endif
-
// Inform AudioInputRendererHost about the new render process PID.
// AudioInputRendererHost is reference counted, so its lifetime is
// guaranteed during the lifetime of the closure.
@@ -1820,10 +1869,8 @@ void RenderProcessHostImpl::Cleanup() {
}
#if defined(ENABLE_WEBRTC)
- if (is_initialized_) {
- BrowserMainLoop::GetInstance()->media_stream_manager()->
- UnregisterNativeLogCallback(GetID());
- }
+ if (is_initialized_)
+ ClearWebRtcLogMessageCallback();
#endif
// When there are no other owners of this object, we can delete ourselves.
@@ -1882,7 +1929,6 @@ void RenderProcessHostImpl::Cleanup() {
channel_.reset();
// The following members should be cleared in ProcessDied() as well!
- gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
RemoveUserData(kSessionStorageHolderKey);
@@ -1922,10 +1968,6 @@ base::TimeDelta RenderProcessHostImpl::GetChildProcessIdleTime() const {
return base::TimeTicks::Now() - child_process_activity_time_;
}
-void RenderProcessHostImpl::ResumeRequestsForView(int route_id) {
- widget_helper_->ResumeRequestsForView(route_id);
-}
-
void RenderProcessHostImpl::FilterURL(bool empty_allowed, GURL* url) {
FilterURL(this, empty_allowed, url);
}
@@ -1960,7 +2002,7 @@ void RenderProcessHostImpl::DisableAudioDebugRecordings() {
// for avoiding races between enable and disable. Nothing is done on the FILE
// thread.
BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE, base::Bind(&DisableAecDumpOnFileThread),
+ BrowserThread::FILE, FROM_HERE, base::Bind(&base::DoNothing),
base::Bind(&RenderProcessHostImpl::SendDisableAecDumpToRenderer,
weak_factory_.GetWeakPtr()));
@@ -1992,7 +2034,7 @@ void RenderProcessHostImpl::DisableEventLogRecordings() {
// for avoiding races between enable and disable. Nothing is done on the FILE
// thread.
BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE, base::Bind(&DisableAecDumpOnFileThread),
+ BrowserThread::FILE, FROM_HERE, base::Bind(&base::DoNothing),
base::Bind(&RenderProcessHostImpl::SendDisableEventLogToRenderer,
weak_factory_.GetWeakPtr()));
}
@@ -2005,6 +2047,14 @@ void RenderProcessHostImpl::SetWebRtcLogMessageCallback(
#endif
}
+void RenderProcessHostImpl::ClearWebRtcLogMessageCallback() {
+#if defined(ENABLE_WEBRTC)
+ BrowserMainLoop::GetInstance()
+ ->media_stream_manager()
+ ->UnregisterNativeLogCallback(GetID());
+#endif
+}
+
RenderProcessHostImpl::WebRtcStopRtpDumpCallback
RenderProcessHostImpl::StartRtpDump(
bool incoming,
@@ -2076,11 +2126,6 @@ void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph,
if (empty_allowed && url->is_empty())
return;
- // The browser process should never hear the swappedout:// URL from any
- // of the renderer's messages. Check for this in debug builds, but don't
- // let it crash a release browser.
- DCHECK(GURL(kSwappedOutURL) != *url);
-
if (!url->is_valid()) {
// Have to use about:blank for the denied case, instead of an empty GURL.
// This is because the browser treats navigation to an empty GURL as a
@@ -2309,6 +2354,31 @@ void RenderProcessHostImpl::RegisterProcessHostForSite(
map->RegisterProcess(site, process);
}
+void RenderProcessHostImpl::CreateSharedRendererHistogramAllocator() {
+ DCHECK(!metrics_allocator_);
+
+ // Create a persistent memory segment for renderer histograms only if
+ // they're active in the browser.
+ if (!base::GlobalHistogramAllocator::Get())
+ return;
+
+ // Get handle to the renderer process. Stop if there is none.
+ base::ProcessHandle destination = GetHandle();
+ if (destination == base::kNullProcessHandle)
+ return;
+
+ // TODO(bcwhite): Update this with the correct memory size.
+ scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
+ shm->CreateAndMapAnonymous(2 << 20); // 2 MiB
+ metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator(
+ std::move(shm), GetID(), "RendererMetrics", /*readonly=*/false));
+
+ base::SharedMemoryHandle shm_handle;
+ metrics_allocator_->shared_memory()->ShareToProcess(destination, &shm_handle);
+ Send(new ChildProcessMsg_SetHistogramMemory(
+ shm_handle, metrics_allocator_->shared_memory()->mapped_size()));
+}
+
void RenderProcessHostImpl::ProcessDied(bool already_dead,
RendererClosedDetails* known_details) {
// Our child process has died. If we didn't expect it, it's a crash.
@@ -2346,7 +2416,6 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead,
}
RendererClosedDetails details(status, exit_code);
- mojo_application_host_->WillDestroySoon();
child_process_launcher_.reset();
#if USE_ATTACHMENT_BROKER
@@ -2374,7 +2443,6 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead,
RenderProcessExited(this, status, exit_code));
within_process_died_observer_ = false;
- gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
RemoveUserData(kSessionStorageHolderKey);
@@ -2434,8 +2502,6 @@ void RenderProcessHostImpl::OnShutdownRequest() {
FOR_EACH_OBSERVER(RenderProcessHostObserver, observers_,
RenderProcessWillExit(this));
- mojo_application_host_->WillDestroySoon();
-
Send(new ChildProcessMsg_Shutdown());
}
@@ -2507,17 +2573,17 @@ void RenderProcessHostImpl::OnProcessLaunched() {
is_process_backgrounded_ =
child_process_launcher_->GetProcess().IsProcessBackgrounded();
-#if defined(OS_WIN)
- // Experiment with not setting the initial priority of a renderer, as this
- // might be a visible tab but since no widgets are currently present, it
- // will get backgrounded. See https://crbug.com/560446.
- if (base::FeatureList::IsEnabled(
- features::kUpdateRendererPriorityOnStartup)) {
- UpdateProcessPriority();
- }
-#else
+ // Disable updating process priority on startup for now as it incorrectly
+ // results in backgrounding foreground navigations until their first commit
+ // is made. A better long term solution would be to be aware of the tab's
+ // visibility at this point. https://crbug.com/560446.
+ // Except on Android for now because of https://crbug.com/601184 :-(.
+#if defined(OS_ANDROID)
UpdateProcessPriority();
#endif
+
+ // Share histograms between the renderer and this process.
+ CreateSharedRendererHistogramAllocator();
}
// NOTE: This needs to be before sending queued messages because
@@ -2531,35 +2597,6 @@ void RenderProcessHostImpl::OnProcessLaunched() {
Source<RenderProcessHost>(this),
NotificationService::NoDetails());
- if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk") &&
- child_process_launcher_.get()) {
- base::ProcessHandle process_handle =
- child_process_launcher_->GetProcess().Handle();
- mojo::embedder::ScopedPlatformHandle client_pipe;
-#if defined(MOJO_SHELL_CLIENT)
- if (IsRunningInMojoShell()) {
- client_pipe = RegisterProcessWithBroker(
- child_process_launcher_->GetProcess().Pid());
- } else
-#endif
- {
- client_pipe = mojo::embedder::ChildProcessLaunched(process_handle);
- }
- Send(new ChildProcessMsg_SetMojoParentPipeHandle(
- IPC::GetFileHandleForProcess(
-#if defined(OS_WIN)
- client_pipe.release().handle,
-#else
- client_pipe.release().fd,
-#endif
- process_handle, true)));
- }
-
-#if defined(MOJO_SHELL_CLIENT)
- // Send the mojo shell handle to the renderer.
- SendExternalMojoShellHandleToChild(GetHandle(), this);
-#endif
-
// Allow Mojo to be setup before the renderer sees any Chrome IPC messages.
// This way, Mojo can be safely used from the renderer in response to any
// Chrome IPC message.
@@ -2618,20 +2655,7 @@ void RenderProcessHostImpl::OnCloseACK(int old_route_id) {
}
void RenderProcessHostImpl::OnGpuSwitched() {
- // We are updating all widgets including swapped out ones.
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHostImpl::GetAllRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- RenderViewHost* rvh = RenderViewHost::From(widget);
- if (!rvh)
- continue;
-
- // Skip widgets in other processes.
- if (rvh->GetProcess()->GetID() != GetID())
- continue;
-
- rvh->OnWebkitPreferencesChanged();
- }
+ RecomputeAndUpdateWebKitPreferences();
}
#if defined(ENABLE_WEBRTC)
@@ -2712,8 +2736,7 @@ void RenderProcessHostImpl::EnableAecDumpForId(const base::FilePath& file,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE, FROM_HERE,
- base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id)),
- GetHandle()),
+ base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id))),
base::Bind(&RenderProcessHostImpl::SendAecDumpFileToRenderer,
weak_factory_.GetWeakPtr(), id));
}
@@ -2723,8 +2746,7 @@ void RenderProcessHostImpl::EnableEventLogForId(const base::FilePath& file,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE, FROM_HERE,
- base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id)),
- GetHandle()),
+ base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id))),
base::Bind(&RenderProcessHostImpl::SendEventLogFileToRenderer,
weak_factory_.GetWeakPtr(), id));
}
@@ -2775,4 +2797,21 @@ BluetoothDispatcherHost* RenderProcessHostImpl::GetBluetoothDispatcherHost() {
return bluetooth_dispatcher_host_.get();
}
+void RenderProcessHostImpl::RecomputeAndUpdateWebKitPreferences() {
+ // We are updating all widgets including swapped out ones.
+ scoped_ptr<RenderWidgetHostIterator> widgets(
+ RenderWidgetHostImpl::GetAllRenderWidgetHosts());
+ while (RenderWidgetHost* widget = widgets->GetNextHost()) {
+ RenderViewHost* rvh = RenderViewHost::From(widget);
+ if (!rvh)
+ continue;
+
+ // Skip widgets in other processes.
+ if (rvh->GetProcess()->GetID() != GetID())
+ continue;
+
+ rvh->OnWebkitPreferencesChanged();
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.h b/chromium/content/browser/renderer_host/render_process_host_impl.h
index 79154957c35..6d83d4b0515 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.h
@@ -13,6 +13,7 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/process/process.h"
@@ -53,7 +54,6 @@ class AudioRendererHost;
class BluetoothDispatcherHost;
class BrowserCdmManager;
class BrowserDemuxerAndroid;
-class GpuMessageFilter;
class InProcessChildThreadParams;
class MessagePortMessageFilter;
class MojoApplicationHost;
@@ -71,6 +71,10 @@ class RenderWidgetHostViewFrameSubscriber;
class StoragePartition;
class StoragePartitionImpl;
+namespace mojom {
+class StoragePartitionService;
+}
+
typedef base::Thread* (*RendererMainThreadFactoryFunction)(
const InProcessChildThreadParams& params);
@@ -138,7 +142,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
bool FastShutdownForPageCount(size_t count) override;
bool FastShutdownStarted() const override;
base::TimeDelta GetChildProcessIdleTime() const override;
- void ResumeRequestsForView(int route_id) override;
void FilterURL(bool empty_allowed, GURL* url) override;
#if defined(ENABLE_WEBRTC)
void EnableAudioDebugRecordings(const base::FilePath& file) override;
@@ -147,6 +150,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void DisableEventLogRecordings() override;
void SetWebRtcLogMessageCallback(
base::Callback<void(const std::string&)> callback) override;
+ void ClearWebRtcLogMessageCallback() override;
WebRtcStopRtpDumpCallback StartRtpDump(
bool incoming,
bool outgoing,
@@ -155,6 +159,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
void ResumeDeferredNavigation(const GlobalRequestID& request_id) override;
void NotifyTimezoneChange(const std::string& timezone) override;
ServiceRegistry* GetServiceRegistry() override;
+ scoped_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
+ override;
const base::TimeTicks& GetInitTimeForNavigationMetrics() const override;
bool SubscribeUniformEnabled() const override;
void OnAddSubscription(unsigned int target) override;
@@ -263,6 +269,13 @@ class CONTENT_EXPORT RenderProcessHostImpl
BluetoothDispatcherHost* GetBluetoothDispatcherHost();
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+ // Launch the zygote early in the browser startup.
+ static void EarlyZygoteLaunch();
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
+ void RecomputeAndUpdateWebKitPreferences();
+
protected:
// A proxy for our IPC::Channel that lives on the IO thread.
scoped_ptr<IPC::ChannelProxy> channel_;
@@ -296,6 +309,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Registers Mojo services to be exposed to the renderer.
void RegisterMojoServices();
+ void CreateStoragePartitionService(
+ mojo::InterfaceRequest<mojom::StoragePartitionService> request);
+
// Control message handlers.
void OnShutdownRequest();
void SuddenTerminationChanged(bool enabled);
@@ -318,6 +334,12 @@ class CONTENT_EXPORT RenderProcessHostImpl
// change.
void UpdateProcessPriority();
+ // Creates a PersistentMemoryAllocator and shares it with the renderer
+ // process for it to store histograms from that process. The allocator is
+ // available for extraction by a SubprocesMetricsProvider in order to
+ // report those histograms to UMA.
+ void CreateSharedRendererHistogramAllocator();
+
// Handle termination of our process.
void ProcessDied(bool already_dead, RendererClosedDetails* known_details);
@@ -346,6 +368,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
base::FilePath GetEventLogFilePathWithExtensions(const base::FilePath& file);
#endif
+ // The token to be passed to the child process and exchanged for a message
+ // pipe to the shell.
+ std::string shell_pipe_token_;
+
scoped_ptr<MojoApplicationHost> mojo_application_host_;
// The registered IPC listener objects. When this list is empty, we should
@@ -365,14 +391,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
// IO thread.
scoped_refptr<RenderWidgetHelper> widget_helper_;
- // The filter for GPU-related messages coming from the renderer.
- // Thread safety note: this field is to be accessed from the UI thread.
- // We don't keep a reference to it, to avoid it being destroyed on the UI
- // thread, but we clear this field when we clear channel_. When channel_ goes
- // away, it posts a task to the IO thread to destroy it there, so we know that
- // it's valid if non-NULL.
- GpuMessageFilter* gpu_message_filter_;
-
// The filter for MessagePort messages coming from the renderer.
scoped_refptr<MessagePortMessageFilter> message_port_message_filter_;
@@ -403,6 +421,11 @@ class CONTENT_EXPORT RenderProcessHostImpl
// The globally-unique identifier for this RPH.
const int id_;
+ // A secondary ID used by the Mojo shell to distinguish different incarnations
+ // of the same RPH from each other. Unlike |id_| this is not globally unique,
+ // but it is guaranteed to change every time Init() is called.
+ int instance_id_ = 1;
+
BrowserContext* browser_context_;
// Owned by |browser_context_|.
@@ -477,7 +500,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
// for UMA.
int max_worker_count_;
- // Context shared for each PermissionService instance created for this RPH.
+ // Context shared for each mojom::PermissionService instance created for this
+ // RPH.
scoped_ptr<PermissionServiceContext> permission_service_context_;
// This is a set of all subscription targets valuebuffers in the GPU process
@@ -494,6 +518,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Whether or not the CHROMIUM_subscribe_uniform WebGL extension is enabled
bool subscribe_uniform_enabled_;
+ // The memory allocator, if any, in which the renderer will write its metrics.
+ scoped_ptr<base::SharedPersistentMemoryAllocator> metrics_allocator_;
+
bool channel_connected_;
bool sent_render_process_ready_;
@@ -506,6 +533,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
base::WaitableEvent never_signaled_;
#endif
+ std::string mojo_channel_token_;
+ mojo::ScopedMessagePipeHandle in_process_renderer_handle_;
+
base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
diff --git a/chromium/content/browser/renderer_host/render_view_host_factory.cc b/chromium/content/browser/renderer_host/render_view_host_factory.cc
index 13b2c082480..bcd1c9ab1bd 100644
--- a/chromium/content/browser/renderer_host/render_view_host_factory.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_factory.cc
@@ -15,6 +15,9 @@ namespace content {
RenderViewHostFactory* RenderViewHostFactory::factory_ = nullptr;
// static
+bool RenderViewHostFactory::is_real_render_view_host_ = false;
+
+// static
RenderViewHost* RenderViewHostFactory::Create(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
diff --git a/chromium/content/browser/renderer_host/render_view_host_factory.h b/chromium/content/browser/renderer_host/render_view_host_factory.h
index 62b23900d6a..a6f7dd5e6ce 100644
--- a/chromium/content/browser/renderer_host/render_view_host_factory.h
+++ b/chromium/content/browser/renderer_host/render_view_host_factory.h
@@ -39,6 +39,18 @@ class RenderViewHostFactory {
return !!factory_;
}
+ // Returns true if the RenderViewHost instance is not a test instance.
+ CONTENT_EXPORT static bool is_real_render_view_host() {
+ return is_real_render_view_host_;
+ }
+
+ // Sets the is_real_render_view_host flag which indicates that the
+ // RenderViewHost instance is not a test instance.
+ CONTENT_EXPORT static void set_is_real_render_view_host(
+ bool is_real_render_view_host) {
+ is_real_render_view_host_ = is_real_render_view_host;
+ }
+
protected:
RenderViewHostFactory() {}
virtual ~RenderViewHostFactory() {}
@@ -67,6 +79,10 @@ class RenderViewHostFactory {
// create the default RenderViewHosts.
CONTENT_EXPORT static RenderViewHostFactory* factory_;
+ // Set to true if the RenderViewHost is not a test instance. Defaults to
+ // false.
+ CONTENT_EXPORT static bool is_real_render_view_host_;
+
DISALLOW_COPY_AND_ASSIGN(RenderViewHostFactory);
};
diff --git a/chromium/content/browser/renderer_host/render_view_host_impl.cc b/chromium/content/browser/renderer_host/render_view_host_impl.cc
index f8175ab639c..f4891f2d404 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.cc
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/command_line.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h"
@@ -35,10 +36,10 @@
#include "content/browser/host_zoom_map_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/renderer_host/dip_util.h"
-#include "content/browser/renderer_host/media/audio_renderer_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/content_switches_internal.h"
@@ -46,6 +47,7 @@
#include "content/common/frame_messages.h"
#include "content/common/input_messages.h"
#include "content/common/inter_process_time_ticks_converter.h"
+#include "content/common/site_isolation_policy.h"
#include "content/common/speech_recognition_messages.h"
#include "content/common/swapped_out_messages.h"
#include "content/common/view_messages.h"
@@ -74,7 +76,7 @@
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "net/base/filename_util.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/fileapi/isolated_context.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -220,7 +222,6 @@ RenderViewHostImpl::RenderViewHostImpl(SiteInstance* instance,
enabled_bindings_(0),
page_id_(-1),
is_active_(!swapped_out),
- is_pending_deletion_(false),
is_swapped_out_(swapped_out),
main_frame_routing_id_(main_frame_routing_id),
is_waiting_for_close_ack_(false),
@@ -240,21 +241,11 @@ RenderViewHostImpl::RenderViewHostImpl(SiteInstance* instance,
GetProcess()->EnableSendQueue();
if (ResourceDispatcherHostImpl::Get()) {
- bool has_active_audio = false;
- if (has_initialized_audio_host) {
- scoped_refptr<AudioRendererHost> arh =
- static_cast<RenderProcessHostImpl*>(GetProcess())
- ->audio_renderer_host();
- if (arh.get())
- has_active_audio =
- arh->RenderFrameHasActiveAudio(main_frame_routing_id_);
- }
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostCreated,
base::Unretained(ResourceDispatcherHostImpl::Get()),
- GetProcess()->GetID(), GetRoutingID(),
- !GetWidget()->is_hidden(), has_active_audio));
+ GetProcess()->GetID(), GetRoutingID()));
}
}
@@ -300,6 +291,14 @@ bool RenderViewHostImpl::CreateRenderView(
CHECK(main_frame_routing_id_ != MSG_ROUTING_NONE ||
proxy_route_id != MSG_ROUTING_NONE);
+ // We should not set both main_frame_routing_id_ and proxy_route_id. Log
+ // cases that this happens (without crashing) to track down
+ // https://crbug.com/574245.
+ // TODO(creis): Remove this once we've found the cause.
+ if (main_frame_routing_id_ != MSG_ROUTING_NONE &&
+ proxy_route_id != MSG_ROUTING_NONE)
+ base::debug::DumpWithoutCrashing();
+
GetWidget()->set_renderer_initialized(true);
// Ensure the RenderView starts with a next_page_id larger than any existing
@@ -365,7 +364,7 @@ bool RenderViewHostImpl::CreateRenderView(
RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_routing_id_)
->SetRenderFrameCreated(true);
}
- GetWidget()->SendScreenRects();
+ GetWidget()->delegate()->SendScreenRects();
PostRenderViewReady();
return true;
@@ -403,11 +402,6 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
!command_line.HasSwitch(switches::kDisableLocalStorage);
prefs.databases_enabled =
!command_line.HasSwitch(switches::kDisableDatabases);
-#if defined(OS_ANDROID)
- // WebAudio is enabled by default on x86 and ARM.
- prefs.webaudio_enabled =
- !command_line.HasSwitch(switches::kDisableWebAudio);
-#endif
prefs.experimental_webgl_enabled =
GpuProcessHost::gpu_enabled() &&
@@ -482,8 +476,9 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
!command_line.HasSwitch(switches::kDisableTouchAdjustment);
prefs.enable_scroll_animator =
- !command_line.HasSwitch(switches::kDisableSmoothScrolling) &&
- gfx::Animation::ShouldRenderRichAnimation();
+ command_line.HasSwitch(switches::kEnableSmoothScrolling) ||
+ (!command_line.HasSwitch(switches::kDisableSmoothScrolling) &&
+ gfx::Animation::ScrollAnimationsEnabledBySystem());
// Certain GPU features might have been blacklisted.
GpuDataManagerImpl::GetInstance()->UpdateRendererWebPrefs(&prefs);
@@ -530,14 +525,13 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
prefs.v8_cache_options = GetV8CacheOptions();
+ prefs.user_gesture_required_for_presentation = !command_line.HasSwitch(
+ switches::kDisableGestureRequirementForPresentation);
+
GetContentClient()->browser()->OverrideWebkitPrefs(this, &prefs);
return prefs;
}
-void RenderViewHostImpl::SuppressDialogsUntilSwapOut() {
- Send(new ViewMsg_SuppressDialogsUntilSwapOut(GetRoutingID()));
-}
-
void RenderViewHostImpl::ClosePage() {
is_waiting_for_close_ack_ = true;
GetWidget()->StartHangMonitorTimeout(
@@ -572,19 +566,6 @@ void RenderViewHostImpl::ClosePageIgnoringUnloadEvents() {
delegate_->Close(this);
}
-#if defined(OS_ANDROID)
-void RenderViewHostImpl::ActivateNearestFindResult(int request_id,
- float x,
- float y) {
- Send(new InputMsg_ActivateNearestFindResult(GetRoutingID(),
- request_id, x, y));
-}
-
-void RenderViewHostImpl::RequestFindMatchRects(int current_version) {
- Send(new ViewMsg_FindMatchRects(GetRoutingID(), current_version));
-}
-#endif
-
void RenderViewHostImpl::RenderProcessReady(RenderProcessHost* host) {
if (render_view_ready_on_process_launch_) {
render_view_ready_on_process_launch_ = false;
@@ -886,9 +867,6 @@ bool RenderViewHostImpl::SuddenTerminationAllowed() const {
// RenderViewHostImpl, IPC message handlers:
bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
- if (!BrowserMessageFilter::CheckCanDispatchOnUI(msg, GetWidget()))
- return true;
-
// Filter out most IPC messages if this renderer is swapped out.
// We still want to handle certain ACKs to keep our state consistent.
if (is_swapped_out_) {
@@ -959,26 +937,6 @@ void RenderViewHostImpl::ShutdownAndDestroy() {
delete this;
}
-void RenderViewHostImpl::RenderWidgetWillBeHidden() {
- if (ResourceDispatcherHostImpl::Get()) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostWasHidden,
- base::Unretained(ResourceDispatcherHostImpl::Get()),
- GetProcess()->GetID(), GetRoutingID()));
- }
-}
-
-void RenderViewHostImpl::RenderWidgetWillBeShown() {
- if (ResourceDispatcherHostImpl::Get()) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostWasShown,
- base::Unretained(ResourceDispatcherHostImpl::Get()),
- GetProcess()->GetID(), GetRoutingID()));
- }
-}
-
void RenderViewHostImpl::CreateNewWindow(
int32_t route_id,
int32_t main_frame_route_id,
@@ -1015,8 +973,7 @@ void RenderViewHostImpl::OnShowView(int route_id,
void RenderViewHostImpl::OnShowWidget(int route_id,
const gfx::Rect& initial_rect) {
- if (is_active_)
- delegate_->ShowCreatedWidget(route_id, initial_rect);
+ delegate_->ShowCreatedWidget(route_id, initial_rect);
Send(new ViewMsg_Move_ACK(route_id));
}
diff --git a/chromium/content/browser/renderer_host/render_view_host_impl.h b/chromium/content/browser/renderer_host/render_view_host_impl.h
index 9d9455dfab7..4ec87ca0711 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.h
@@ -150,11 +150,6 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
void OnWebkitPreferencesChanged() override;
void SelectWordAroundCaret() override;
-#if defined(OS_ANDROID)
- void ActivateNearestFindResult(int request_id, float x, float y) override;
- void RequestFindMatchRects(int current_version) override;
-#endif
-
// RenderProcessHostObserver implementation
void RenderProcessReady(RenderProcessHost* host) override;
void RenderProcessExited(RenderProcessHost* host,
@@ -193,16 +188,6 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
bool is_active() const { return is_active_; }
void set_is_active(bool is_active) { is_active_ = is_active; }
- // Tracks whether this RenderViewHost is pending deletion. This is tracked
- // separately from the main frame pending deletion state, because the
- // RenderViewHost's main frame is cleared when the main frame's
- // RenderFrameHost is marked for deletion.
- //
- // TODO(nasko,alexmos): This should not be necessary once swapped-out is
- // removed.
- bool is_pending_deletion() const { return is_pending_deletion_; }
- void set_pending_deletion() { is_pending_deletion_ = true; }
-
// Tracks whether this RenderViewHost is swapped out, according to its main
// frame RenderFrameHost.
void set_is_swapped_out(bool is_swapped_out) {
@@ -212,12 +197,6 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
// TODO(creis): Remove as part of http://crbug.com/418265.
bool is_waiting_for_close_ack() const { return is_waiting_for_close_ack_; }
- // Tells the renderer that this RenderView will soon be swapped out, and thus
- // not to create any new modal dialogs until it happens. This must be done
- // separately so that the PageGroupLoadDeferrers of any current dialogs are no
- // longer on the stack when we attempt to swap it out.
- void SuppressDialogsUntilSwapOut();
-
// Tells the renderer process to run the page's unload handler.
// A ClosePage_ACK ack is sent back when the handler execution completes.
void ClosePage();
@@ -255,6 +234,11 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
// Creates a full screen RenderWidget.
void CreateNewFullscreenWidget(int32_t route_id);
+ // TODO(creis): Remove after debugging https:/crbug.com/575245.
+ int main_frame_routing_id() const {
+ return main_frame_routing_id_;
+ }
+
void set_main_frame_routing_id(int routing_id) {
main_frame_routing_id_ = routing_id;
}
@@ -264,15 +248,15 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
size_t end_offset);
// Increases the refcounting on this RVH. This is done by the FrameTree on
- // creation of a RenderFrameHost.
+ // creation of a RenderFrameHost or RenderFrameProxyHost.
void increment_ref_count() { ++frames_ref_count_; }
// Decreases the refcounting on this RVH. This is done by the FrameTree on
- // destruction of a RenderFrameHost.
+ // destruction of a RenderFrameHost or RenderFrameProxyHost.
void decrement_ref_count() { --frames_ref_count_; }
// Returns the refcount on this RVH, that is the number of RenderFrameHosts
- // currently using it.
+ // and RenderFrameProxyHosts currently using it.
int ref_count() { return frames_ref_count_; }
// NOTE: Do not add functions that just send an IPC message that are called in
@@ -286,8 +270,6 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
void RenderWidgetDidInit() override;
void RenderWidgetWillSetIsLoading(bool is_loading) override;
void RenderWidgetGotFocus() override;
- void RenderWidgetWillBeHidden() override;
- void RenderWidgetWillBeShown() override;
void RenderWidgetDidForwardMouseEvent(
const blink::WebMouseEvent& mouse_event) override;
bool MayRenderWidgetForwardKeyboardEvent(
@@ -334,6 +316,9 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
FRIEND_TEST_ALL_PREFIXES(RenderViewHostTest, RoutingIdSane);
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest,
CleanUpSwappedOutRVHOnProcessCrash);
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+ NavigateMainFrameToChildSite);
+
// Send RenderViewReady to observers once the process is launched, but not
// re-entrantly.
void PostRenderViewReady();
@@ -392,9 +377,6 @@ class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost,
// it is not visible to the user in any of these cases.
bool is_active_;
- // True if this RenderViewHost is pending deletion.
- bool is_pending_deletion_;
-
// Tracks whether the main frame RenderFrameHost is swapped out. Unlike
// is_active_, this is false when the frame is pending swap out or deletion.
// TODO(creis): Remove this when we no longer use swappedout://.
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.cc b/chromium/content/browser/renderer_host/render_widget_helper.cc
index 93283733b31..e6a225c7ab3 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.cc
+++ b/chromium/content/browser/renderer_host/render_widget_helper.cc
@@ -82,17 +82,6 @@ void RenderWidgetHelper::ResumeDeferredNavigation(
request_id));
}
-void RenderWidgetHelper::ResumeRequestsForView(int route_id) {
- // We only need to resume blocked requests if we used a valid route_id.
- // See CreateNewWindow.
- if (route_id != MSG_ROUTING_NONE) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&RenderWidgetHelper::OnResumeRequestsForView,
- this, route_id));
- }
-}
-
void RenderWidgetHelper::OnResumeDeferredNavigation(
const GlobalRequestID& request_id) {
resource_dispatcher_host_->ResumeDeferredNavigation(request_id);
@@ -122,17 +111,19 @@ void RenderWidgetHelper::CreateNewWindow(
// should be updated to give the widget a distinct routing ID.
// https://crbug.com/545684
*main_frame_widget_route_id = *route_id;
- // Block resource requests until the view is created, since the HWND might
- // be needed if a response ends up creating a plugin.
+ // Block resource requests until the frame is created, since the HWND might
+ // be needed if a response ends up creating a plugin. We'll only have a
+ // single frame at this point. These requests will be resumed either in
+ // WebContentsImpl::CreateNewWindow or RenderFrameHost::Init.
resource_dispatcher_host_->BlockRequestsForRoute(
- render_process_id_, *route_id);
+ GlobalFrameRoutingId(render_process_id_, *main_frame_route_id));
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI, this, params,
*route_id, *main_frame_route_id, *main_frame_widget_route_id,
- make_scoped_refptr(session_storage_namespace)));
+ base::RetainedRef(session_storage_namespace)));
}
void RenderWidgetHelper::OnCreateWindowOnUI(
@@ -149,11 +140,6 @@ void RenderWidgetHelper::OnCreateWindowOnUI(
session_storage_namespace);
}
-void RenderWidgetHelper::OnResumeRequestsForView(int route_id) {
- resource_dispatcher_host_->ResumeBlockedRequestsForRoute(
- render_process_id_, route_id);
-}
-
void RenderWidgetHelper::CreateNewWidget(int opener_id,
blink::WebPopupType popup_type,
int* route_id) {
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.h b/chromium/content/browser/renderer_host/render_widget_helper.h
index c4b8baf7bf4..43878c707a5 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.h
+++ b/chromium/content/browser/renderer_host/render_widget_helper.h
@@ -96,10 +96,6 @@ class RenderWidgetHelper
// for documentation.
void ResumeDeferredNavigation(const GlobalRequestID& request_id);
- // Called to resume the requests for a view after it's ready. The view was
- // created by CreateNewWindow which initially blocked the requests.
- void ResumeRequestsForView(int route_id);
-
// IO THREAD ONLY -----------------------------------------------------------
void CreateNewWindow(const ViewHostMsg_CreateWindow_Params& params,
@@ -128,9 +124,6 @@ class RenderWidgetHelper
int32_t main_frame_widget_route_id,
SessionStorageNamespace* session_storage_namespace);
- // Called on the IO thread after a window was created on the UI thread.
- void OnResumeRequestsForView(int route_id);
-
// Called on the UI thread to finish creating a widget.
void OnCreateWidgetOnUI(int32_t opener_id,
int32_t route_id,
diff --git a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc b/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
index c158a41c529..e08c7da3e47 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -34,13 +34,6 @@ BrowserAccessibilityManager*
return NULL;
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible
- RenderWidgetHostDelegate::GetParentNativeViewAccessible() {
- return NULL;
-}
-#endif
-
// If a delegate does not override this, the RenderWidgetHostView will
// assume it is the sole platform event consumer.
RenderWidgetHostInputEventRouter*
diff --git a/chromium/content/browser/renderer_host/render_widget_host_delegate.h b/chromium/content/browser/renderer_host/render_widget_host_delegate.h
index f7fbb0e3622..aa38066ec28 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.h
@@ -78,22 +78,18 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// the event itself.
virtual bool HandleWheelEvent(const blink::WebMouseWheelEvent& event);
- // Notification the user has performed a direct interaction (mouse down, mouse
- // wheel, raw key down, or gesture tap) while focus was on the page. Informs
- // the delegate that a user is interacting with a site. Only the first mouse
- // wheel event during a scroll will trigger this method.
- virtual void OnUserInteraction(const blink::WebInputEvent::Type type) {}
+ // Notification the user has performed a direct interaction (mouse down,
+ // scroll, raw key down, gesture tap, or browser-initiated navigation) while
+ // focus was on the page. Informs the delegate that a user is interacting with
+ // a site.
+ virtual void OnUserInteraction(RenderWidgetHostImpl* render_widget_host,
+ const blink::WebInputEvent::Type type) {}
// Callback to give the browser a chance to handle the specified gesture
// event before sending it to the renderer.
// Returns true if the |event| was handled.
virtual bool PreHandleGestureEvent(const blink::WebGestureEvent& event);
- // Notification the user has made a gesture while focus was on the
- // page. This is used to avoid uninitiated user downloads (aka carpet
- // bombing), see DownloadRequestLimiter for details.
- virtual void OnUserGesture(RenderWidgetHostImpl* render_widget_host) {}
-
// Notifies that screen rects were sent to renderer process.
virtual void DidSendScreenRects(RenderWidgetHostImpl* rwh) {}
@@ -171,15 +167,20 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// Notification that the widget has lost the mouse lock.
virtual void LostMouseLock(RenderWidgetHostImpl* render_widget_host) {}
-#if defined(OS_WIN)
- virtual gfx::NativeViewAccessible GetParentNativeViewAccessible();
-#endif
-
- // Called when the widget has sent a compositor proto. This is used in Blimp
+ // Called when the widget has sent a compositor proto. This is used in Btlimp
// mode with the RemoteChannel compositor.
virtual void ForwardCompositorProto(RenderWidgetHostImpl* render_widget_host,
const std::vector<uint8_t>& proto) {}
+ // Called when the visibility of the RenderFrameProxyHost in outter
+ // WebContents changes. This method is only called on an inner WebContents and
+ // will eventually notify all the RenderWidgetHostViews belonging to that
+ // WebContents.
+ virtual void OnRenderFrameProxyVisibilityChanged(bool visible) {}
+
+ // Update the renderer's cache of the screen rect of the view and window.
+ virtual void SendScreenRects() {}
+
protected:
virtual ~RenderWidgetHostDelegate() {}
};
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.cc b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
index 6516e5ec903..88a1a613cce 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
@@ -45,15 +45,16 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_constants_internal.h"
#include "content/common/content_switches_internal.h"
#include "content/common/cursors/webcursor.h"
#include "content/common/frame_messages.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/common/input_messages.h"
+#include "content/common/resize_params.h"
#include "content/common/view_messages.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_service.h"
@@ -65,6 +66,7 @@
#include "content/public/common/web_preferences.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
@@ -75,10 +77,6 @@
#include "ui/gfx/skbitmap_operations.h"
#include "ui/snapshot/snapshot.h"
-#if defined(OS_WIN)
-#include "content/common/plugin_constants_win.h"
-#endif
-
#if defined(OS_MACOSX)
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#endif
@@ -96,13 +94,6 @@ using blink::WebTextDirection;
namespace content {
namespace {
-// The amount of time after a mouse wheel event is sent to the delegate
-// OnUserInteraction method before another mouse wheel event will be sent. This
-// interval is used by the Blink EventHandler in its orthogonal heuristic for
-// detecting the end of a scroll event (if no event has been seen in 0.1
-// seconds, send an end scroll).
-const double kMouseWheelCoalesceIntervalInSeconds = 0.1;
-
bool g_check_for_pending_resize_ack = true;
// <process id, routing id>
@@ -206,16 +197,17 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
pending_mouse_lock_request_(false),
allow_privileged_mouse_lock_(false),
has_touch_handler_(false),
- is_in_gesture_scroll_(false),
+ is_in_touchpad_gesture_scroll_(false),
+ is_in_touchscreen_gesture_scroll_(false),
received_paint_after_load_(false),
next_browser_snapshot_id_(1),
owned_by_render_frame_host_(false),
is_focused_(false),
+ scale_input_to_viewport_(IsUseZoomForDSFEnabled()),
hung_renderer_delay_(
base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
new_content_rendering_delay_(
base::TimeDelta::FromMilliseconds(kNewContentRenderingDelayMs)),
- mouse_wheel_coalesce_timer_(new base::ElapsedTimer()),
weak_factory_(this) {
CHECK(delegate_);
CHECK_NE(MSG_ROUTING_NONE, routing_id_);
@@ -374,8 +366,6 @@ void RenderWidgetHostImpl::SendScreenRects() {
last_window_screen_rect_ = view_->GetBoundsInRootWindow();
Send(new ViewMsg_UpdateScreenRects(
GetRoutingID(), last_view_screen_rect_, last_window_screen_rect_));
- if (delegate_)
- delegate_->DidSendScreenRects(this);
waiting_for_screen_rects_ack_ = true;
}
@@ -399,8 +389,6 @@ void RenderWidgetHostImpl::Init() {
renderer_initialized_ = true;
- GetProcess()->ResumeRequestsForView(routing_id_);
-
// If the RWHV has not yet been set, the surface ID namespace will get
// passed down by the call to SetView().
if (view_) {
@@ -437,12 +425,17 @@ bool RenderWidgetHostImpl::IsLoading() const {
}
bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
+ // Only process messages if the RenderWidget is alive.
+ if (!renderer_initialized())
+ return false;
+
if (owner_delegate_ && owner_delegate_->OnMessageReceived(msg))
return true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostImpl, msg)
IPC_MESSAGE_HANDLER(FrameHostMsg_RenderProcessGone, OnRenderProcessGone)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_HittestData, OnHittestData)
IPC_MESSAGE_HANDLER(InputHostMsg_QueueSyntheticGesture,
OnQueueSyntheticGesture)
IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
@@ -465,12 +458,6 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionChanged, OnSelectionChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionBoundsChanged,
OnSelectionBoundsChanged)
-#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowCreated,
- OnWindowlessPluginDummyWindowCreated)
- IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowDestroyed,
- OnWindowlessPluginDummyWindowDestroyed)
-#endif
IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
OnImeCompositionRangeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstPaintAfterLoad,
@@ -509,9 +496,6 @@ void RenderWidgetHostImpl::WasHidden() {
if (is_hidden_)
return;
- if (owner_delegate_)
- owner_delegate_->RenderWidgetWillBeHidden();
-
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::WasHidden");
is_hidden_ = true;
@@ -536,9 +520,6 @@ void RenderWidgetHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
if (!is_hidden_)
return;
- if (owner_delegate_)
- owner_delegate_->RenderWidgetWillBeShown();
-
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::WasShown");
is_hidden_ = false;
@@ -580,9 +561,8 @@ void RenderWidgetHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
WasResized();
}
-bool RenderWidgetHostImpl::GetResizeParams(
- ViewMsg_Resize_Params* resize_params) {
- *resize_params = ViewMsg_Resize_Params();
+bool RenderWidgetHostImpl::GetResizeParams(ResizeParams* resize_params) {
+ *resize_params = ResizeParams();
GetWebScreenInfo(&resize_params->screen_info);
if (delegate_) {
@@ -633,11 +613,10 @@ bool RenderWidgetHostImpl::GetResizeParams(
}
void RenderWidgetHostImpl::SetInitialRenderSizeParams(
- const ViewMsg_Resize_Params& resize_params) {
+ const ResizeParams& resize_params) {
resize_ack_pending_ = resize_params.needs_resize_ack;
- old_resize_params_ =
- make_scoped_ptr(new ViewMsg_Resize_Params(resize_params));
+ old_resize_params_ = make_scoped_ptr(new ResizeParams(resize_params));
}
void RenderWidgetHostImpl::WasResized() {
@@ -650,7 +629,7 @@ void RenderWidgetHostImpl::WasResized() {
return;
}
- scoped_ptr<ViewMsg_Resize_Params> params(new ViewMsg_Resize_Params);
+ scoped_ptr<ResizeParams> params(new ResizeParams);
if (color_profile_out_of_date_)
DispatchColorProfile();
if (!GetResizeParams(params.get()))
@@ -681,7 +660,7 @@ void RenderWidgetHostImpl::DispatchColorProfile() {
FROM_HERE,
base::Bind(&RenderWidgetHostImpl::SendColorProfile,
weak_factory_.GetWeakPtr()));
-#elif !defined(OS_CHROMEOS) && !defined(OS_IOS) && !defined(OS_ANDROID)
+#elif !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
// Only support desktop Mac and Linux at this time.
SendColorProfile();
#endif
@@ -1045,21 +1024,26 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
// TODO(wjmaclean) Remove the code for supporting resending gesture events
// when WebView transitions to OOPIF and BrowserPlugin is removed.
// http://crbug.com/533069
+ bool* is_in_gesture_scroll =
+ gesture_event.sourceDevice ==
+ blink::WebGestureDevice::WebGestureDeviceTouchpad
+ ? &is_in_touchpad_gesture_scroll_
+ : &is_in_touchscreen_gesture_scroll_;
if (gesture_event.type == blink::WebInputEvent::GestureScrollBegin) {
- DCHECK(!is_in_gesture_scroll_);
- is_in_gesture_scroll_ = true;
+ DCHECK(!(*is_in_gesture_scroll));
+ *is_in_gesture_scroll = true;
} else if (gesture_event.type == blink::WebInputEvent::GestureScrollEnd ||
gesture_event.type == blink::WebInputEvent::GestureFlingStart) {
- DCHECK(is_in_gesture_scroll_ ||
+ DCHECK(*is_in_gesture_scroll ||
(gesture_event.type == blink::WebInputEvent::GestureFlingStart &&
gesture_event.sourceDevice ==
blink::WebGestureDevice::WebGestureDeviceTouchpad));
- is_in_gesture_scroll_ = false;
+ *is_in_gesture_scroll = false;
}
bool scroll_update_needs_wrapping =
gesture_event.type == blink::WebInputEvent::GestureScrollUpdate &&
- gesture_event.resendingPluginId != -1 && !is_in_gesture_scroll_;
+ gesture_event.resendingPluginId != -1 && !(*is_in_gesture_scroll);
if (scroll_update_needs_wrapping) {
ForwardGestureEventWithLatencyInfo(
@@ -1135,13 +1119,6 @@ void RenderWidgetHostImpl::ForwardKeyboardEvent(
return;
}
- if (key_event.type == WebKeyboardEvent::Char &&
- (key_event.windowsKeyCode == ui::VKEY_RETURN ||
- key_event.windowsKeyCode == ui::VKEY_SPACE)) {
- if (delegate_)
- delegate_->OnUserGesture(this);
- }
-
// Double check the type to make sure caller hasn't sent us nonsense that
// will mess up our key queue.
if (!WebInputEvent::isKeyboardEventType(key_event.type))
@@ -1264,7 +1241,7 @@ void RenderWidgetHostImpl::GetWebScreenInfo(blink::WebScreenInfo* result) {
// TODO(sievers): find a way to make this done another way so the method
// can be const.
latency_tracker_.set_device_scale_factor(result->deviceScaleFactor);
- if (IsUseZoomForDSFEnabled())
+ if (scale_input_to_viewport_)
input_router_->SetDeviceScaleFactor(result->deviceScaleFactor);
}
@@ -1307,10 +1284,10 @@ const NativeWebKeyboardEvent*
}
void RenderWidgetHostImpl::OnSelectionChanged(const base::string16& text,
- size_t offset,
+ uint32_t offset,
const gfx::Range& range) {
if (view_)
- view_->SelectionChanged(text, offset, range);
+ view_->SelectionChanged(text, static_cast<size_t>(offset), range);
}
void RenderWidgetHostImpl::OnSelectionBoundsChanged(
@@ -1403,10 +1380,12 @@ void RenderWidgetHostImpl::NotifyTextDirection() {
void RenderWidgetHostImpl::ImeSetComposition(
const base::string16& text,
const std::vector<blink::WebCompositionUnderline>& underlines,
+ const gfx::Range& replacement_range,
int selection_start,
int selection_end) {
Send(new InputMsg_ImeSetComposition(
- GetRoutingID(), text, underlines, selection_start, selection_end));
+ GetRoutingID(), text, underlines, replacement_range,
+ selection_start, selection_end));
}
void RenderWidgetHostImpl::ImeConfirmComposition(
@@ -1419,7 +1398,8 @@ void RenderWidgetHostImpl::ImeConfirmComposition(
void RenderWidgetHostImpl::ImeCancelComposition() {
Send(new InputMsg_ImeSetComposition(GetRoutingID(), base::string16(),
- std::vector<blink::WebCompositionUnderline>(), 0, 0));
+ std::vector<blink::WebCompositionUnderline>(),
+ gfx::Range::InvalidRange(), 0, 0));
}
void RenderWidgetHostImpl::RejectMouseLockOrUnlockIfNecessary() {
@@ -1468,8 +1448,10 @@ void RenderWidgetHostImpl::Destroy(bool also_delete) {
if (delegate_)
delegate_->RenderWidgetDeleted(this);
- if (also_delete)
+ if (also_delete) {
+ CHECK(!owner_delegate_);
delete this;
+ }
}
void RenderWidgetHostImpl::RendererIsUnresponsive() {
@@ -1509,6 +1491,12 @@ void RenderWidgetHostImpl::OnRenderProcessGone(int status, int exit_code) {
}
}
+void RenderWidgetHostImpl::OnHittestData(
+ const FrameHostMsg_HittestData_Params& params) {
+ if (delegate_)
+ delegate_->GetInputEventRouter()->OnHittestData(params);
+}
+
void RenderWidgetHostImpl::OnClose() {
ShutdownAndDestroyWidget(true);
}
@@ -1679,14 +1667,6 @@ void RenderWidgetHostImpl::DidUpdateBackingStore(
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::DidUpdateBackingStore");
TimeTicks update_start = TimeTicks::Now();
- // Move the plugins if the view hasn't already been destroyed. Plugin moves
- // will not be re-issued, so must move them now, regardless of whether we
- // paint or not. MovePluginWindows attempts to move the plugin windows and
- // in the process could dispatch other window messages which could cause the
- // view to be destroyed.
- if (view_)
- view_->MovePluginWindows(params.plugin_window_moves);
-
NotificationService::current()->Notify(
NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
Source<RenderWidgetHost>(this),
@@ -1826,43 +1806,6 @@ void RenderWidgetHostImpl::OnShowDisambiguationPopup(
Send(new ViewMsg_ReleaseDisambiguationPopupBitmap(GetRoutingID(), id));
}
-#if defined(OS_WIN)
-void RenderWidgetHostImpl::OnWindowlessPluginDummyWindowCreated(
- gfx::NativeViewId dummy_activation_window) {
- HWND hwnd = reinterpret_cast<HWND>(dummy_activation_window);
-
- // This may happen as a result of a race condition when the plugin is going
- // away.
- wchar_t window_title[MAX_PATH + 1] = {0};
- if (!IsWindow(hwnd) ||
- !GetWindowText(hwnd, window_title, arraysize(window_title)) ||
- lstrcmpiW(window_title, kDummyActivationWindowName) != 0) {
- return;
- }
-
-#if defined(USE_AURA)
- SetParent(hwnd,
- reinterpret_cast<HWND>(view_->GetParentForWindowlessPlugin()));
-#else
- SetParent(hwnd, reinterpret_cast<HWND>(GetNativeViewId()));
-#endif
- dummy_windows_for_activation_.push_back(hwnd);
-}
-
-void RenderWidgetHostImpl::OnWindowlessPluginDummyWindowDestroyed(
- gfx::NativeViewId dummy_activation_window) {
- HWND hwnd = reinterpret_cast<HWND>(dummy_activation_window);
- std::list<HWND>::iterator i = dummy_windows_for_activation_.begin();
- for (; i != dummy_windows_for_activation_.end(); ++i) {
- if ((*i) == hwnd) {
- dummy_windows_for_activation_.erase(i);
- return;
- }
- }
- NOTREACHED() << "Unknown dummy window";
-}
-#endif
-
void RenderWidgetHostImpl::SetIgnoreInputEvents(bool ignore_input_events) {
ignore_input_events_ = ignore_input_events;
}
@@ -1900,25 +1843,11 @@ InputEventAckState RenderWidgetHostImpl::FilterInputEvent(
if (!process_->HasConnection())
return INPUT_EVENT_ACK_STATE_UNKNOWN;
- if (event.type == WebInputEvent::MouseDown ||
- event.type == WebInputEvent::GestureTapDown) {
- if (delegate_)
- delegate_->OnUserGesture(this);
- }
-
- if (delegate_) {
- if (event.type == WebInputEvent::MouseDown ||
- event.type == WebInputEvent::GestureTapDown ||
- event.type == WebInputEvent::RawKeyDown) {
- delegate_->OnUserInteraction(event.type);
- } else if (event.type == WebInputEvent::MouseWheel) {
- if (mouse_wheel_coalesce_timer_->Elapsed().InSecondsF() >
- kMouseWheelCoalesceIntervalInSeconds) {
- delegate_->OnUserInteraction(event.type);
- }
-
- mouse_wheel_coalesce_timer_.reset(new base::ElapsedTimer());
- }
+ if (delegate_ && (event.type == WebInputEvent::MouseDown ||
+ event.type == WebInputEvent::GestureScrollBegin ||
+ event.type == WebInputEvent::GestureTapDown ||
+ event.type == WebInputEvent::RawKeyDown)) {
+ delegate_->OnUserInteraction(this, event.type);
}
return view_ ? view_->FilterInputEvent(event)
@@ -1966,11 +1895,6 @@ void RenderWidgetHostImpl::OnKeyboardEventAck(
InputEventAckState ack_result) {
latency_tracker_.OnInputEventAck(event.event, &event.latency);
-#if defined(OS_MACOSX)
- if (!is_hidden() && view_ && view_->PostProcessEventForPluginIme(event.event))
- return;
-#endif
-
// We only send unprocessed key event upwards if we are not hidden,
// because the user has moved away from us and no longer expect any effect
// of this key event.
@@ -2245,11 +2169,4 @@ BrowserAccessibilityManager*
delegate_->GetOrCreateRootBrowserAccessibilityManager() : NULL;
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible
- RenderWidgetHostImpl::GetParentNativeViewAccessible() {
- return delegate_ ? delegate_->GetParentNativeViewAccessible() : NULL;
-}
-#endif
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.h b/chromium/content/browser/renderer_host/render_widget_host_impl.h
index d5d9d5ad654..04984b1e87f 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h
@@ -46,10 +46,14 @@
#include "ui/events/latency_info.h"
#include "ui/gfx/native_widget_types.h"
+struct FrameHostMsg_HittestData_Params;
struct ViewHostMsg_SelectionBounds_Params;
struct ViewHostMsg_TextInputState_Params;
struct ViewHostMsg_UpdateRect_Params;
-struct ViewMsg_Resize_Params;
+
+namespace base {
+class RefCountedBytes;
+}
namespace blink {
class WebInputEvent;
@@ -81,6 +85,7 @@ class TimeoutMonitor;
class TouchEmulator;
class WebCursor;
struct EditCommand;
+struct ResizeParams;
// This implements the RenderWidgetHost interface that is exposed to
// embedders of content, and adds things only visible to content.
@@ -289,7 +294,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// when it has received a message.
void ForwardGestureEventWithLatencyInfo(
const blink::WebGestureEvent& gesture_event,
- const ui::LatencyInfo& ui_latency);
+ const ui::LatencyInfo& ui_latency) override;
void ForwardTouchEventWithLatencyInfo(
const blink::WebTouchEvent& touch_event,
const ui::LatencyInfo& ui_latency);
@@ -338,6 +343,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
void ImeSetComposition(
const base::string16& text,
const std::vector<blink::WebCompositionUnderline>& underlines,
+ const gfx::Range& replacement_range,
int selection_start,
int selection_end);
@@ -469,10 +475,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
void RejectMouseLockOrUnlockIfNecessary();
-#if defined(OS_WIN)
- gfx::NativeViewAccessible GetParentNativeViewAccessible();
-#endif
-
void set_renderer_initialized(bool renderer_initialized) {
renderer_initialized_ = renderer_initialized;
}
@@ -485,11 +487,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// Fills in the |resize_params| struct.
// Returns |false| if the update is redundant, |true| otherwise.
- bool GetResizeParams(ViewMsg_Resize_Params* resize_params);
+ bool GetResizeParams(ResizeParams* resize_params);
// Sets the |resize_params| that were sent to the renderer bundled with the
// request to create a new RenderWidget.
- void SetInitialRenderSizeParams(const ViewMsg_Resize_Params& resize_params);
+ void SetInitialRenderSizeParams(const ResizeParams& resize_params);
// Called when we receive a notification indicating that the renderer process
// is gone. This will reset our state so that our state will be consistent if
@@ -506,6 +508,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
bool renderer_initialized() const { return renderer_initialized_; }
+ bool scale_input_to_viewport() const { return scale_input_to_viewport_; }
+ void set_scale_input_to_viewport(bool scale_input_to_viewport) {
+ scale_input_to_viewport_ = scale_input_to_viewport;
+ }
+
protected:
// Retrieves an id the renderer can use to refer to its view.
// This is used for various IPC messages, including plugins.
@@ -578,18 +585,13 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
void OnShowDisambiguationPopup(const gfx::Rect& rect_pixels,
const gfx::Size& size,
const cc::SharedBitmapId& id);
-#if defined(OS_WIN)
- void OnWindowlessPluginDummyWindowCreated(
- gfx::NativeViewId dummy_activation_window);
- void OnWindowlessPluginDummyWindowDestroyed(
- gfx::NativeViewId dummy_activation_window);
-#endif
void OnSelectionChanged(const base::string16& text,
- size_t offset,
+ uint32_t offset,
const gfx::Range& range);
void OnSelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params);
void OnForwardCompositorProto(const std::vector<uint8_t>& proto);
+ void OnHittestData(const FrameHostMsg_HittestData_Params& params);
// Called (either immediately or asynchronously) after we're done with our
// BackingStore and can send an ACK to the renderer so it can paint onto it
@@ -684,7 +686,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
gfx::Size current_size_;
// Resize information that was previously sent to the renderer.
- scoped_ptr<ViewMsg_Resize_Params> old_resize_params_;
+ scoped_ptr<ResizeParams> old_resize_params_;
// The next auto resize to send.
gfx::Size new_auto_size_;
@@ -767,7 +769,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// TODO(wjmaclean) Remove the code for supporting resending gesture events
// when WebView transitions to OOPIF and BrowserPlugin is removed.
// http://crbug.com/533069
- bool is_in_gesture_scroll_;
+ bool is_in_touchpad_gesture_scroll_;
+ bool is_in_touchscreen_gesture_scroll_;
scoped_ptr<SyntheticGestureController> synthetic_gesture_controller_;
@@ -792,10 +795,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// being sent, in which case the timer should fire).
bool received_paint_after_load_;
-#if defined(OS_WIN)
- std::list<HWND> dummy_windows_for_activation_;
-#endif
-
RenderWidgetHostLatencyTracker latency_tracker_;
int next_browser_snapshot_id_;
@@ -812,6 +811,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// causing HasFocus to return false when is_focused_ is true.
bool is_focused_;
+ // When true, the host will scale the input to viewport.
+ // TODO(oshima): Remove this once crbug.com/563730 is addressed.
+ bool scale_input_to_viewport_;
+
// This value indicates how long to wait before we consider a renderer hung.
base::TimeDelta hung_renderer_delay_;
@@ -819,11 +822,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
// renderer process before clearing any previously displayed content.
base::TimeDelta new_content_rendering_delay_;
- // Timer used to batch together mouse wheel events for the delegate
- // OnUserInteraction method. A wheel event is only dispatched when a wheel
- // event has not been seen for kMouseWheelCoalesceInterval seconds prior.
- scoped_ptr<base::ElapsedTimer> mouse_wheel_coalesce_timer_;
-
base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostImpl);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
index eef72ac2c73..3fd57796c7a 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -4,17 +4,98 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface_id_allocator.h"
#include "cc/surfaces/surface_manager.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/common/frame_messages.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+namespace {
+
+void TransformEventTouchPositions(blink::WebTouchEvent* event,
+ const gfx::Vector2d& delta) {
+ for (unsigned i = 0; i < event->touchesLength; ++i) {
+ event->touches[i].position.x += delta.x();
+ event->touches[i].position.y += delta.y();
+ }
+}
+
+} // anonymous namespace
+
namespace content {
+void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed(
+ RenderWidgetHostViewBase* view) {
+ view->RemoveObserver(this);
+
+ // Remove this view from the owner_map.
+ for (auto entry : owner_map_) {
+ if (entry.second == view) {
+ owner_map_.erase(entry.first);
+ // There will only be one instance of a particular view in the map.
+ break;
+ }
+ }
+
+ if (view == touch_target_) {
+ touch_target_ = nullptr;
+ touch_delta_ = gfx::Vector2d();
+ active_touches_ = 0;
+ }
+
+ // If the target that's being destroyed is in the gesture target queue, we
+ // replace it with nullptr so that we maintain the 1:1 correspondence between
+ // queue entries and the touch sequences that underly them.
+ for (size_t i = 0; i < gesture_target_queue_.size(); ++i) {
+ if (gesture_target_queue_[i].target == view)
+ gesture_target_queue_[i].target = nullptr;
+ }
+
+ if (view == gesture_target_) {
+ gesture_target_ = nullptr;
+ gesture_delta_ = gfx::Vector2d();
+ }
+}
+
+void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() {
+ for (auto entry : owner_map_)
+ entry.second->RemoveObserver(this);
+ owner_map_.clear();
+}
+
+RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate(
+ const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>&
+ hittest_data)
+ : hittest_data_(hittest_data) {}
+
+bool RenderWidgetHostInputEventRouter::HittestDelegate::RejectHitTarget(
+ const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) {
+ auto it = hittest_data_.find(surface_quad->surface_id);
+ if (it != hittest_data_.end() && it->second.ignored_for_hittest)
+ return true;
+ return false;
+}
+
+bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget(
+ const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) {
+ auto it = hittest_data_.find(surface_quad->surface_id);
+ if (it != hittest_data_.end() && !it->second.ignored_for_hittest)
+ return true;
+ return false;
+}
+
RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter()
- : active_touches_(0) {}
+ : touch_target_(nullptr),
+ gesture_target_(nullptr),
+ active_touches_(0) {}
RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() {
- owner_map_.clear();
+ // We may be destroyed before some of the owners in the map, so we must
+ // remove ourself from their observer lists.
+ ClearAllObserverRegistrations();
}
RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget(
@@ -28,12 +109,16 @@ RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget(
return root_view;
}
+ // The hittest delegate is used to reject hittesting quads based on extra
+ // hittesting data send by the renderer.
+ HittestDelegate delegate(hittest_data_);
+
// The conversion of point to transform_point is done over the course of the
// hit testing, and reflect transformations that would normally be applied in
// the renderer process if the event was being routed between frames within a
// single process with only one RenderWidgetHost.
uint32_t surface_id_namespace =
- root_view->SurfaceIdNamespaceAtPoint(point, transformed_point);
+ root_view->SurfaceIdNamespaceAtPoint(&delegate, point, transformed_point);
const SurfaceIdNamespaceOwnerMap::iterator iter =
owner_map_.find(surface_id_namespace);
// If the point hit a Surface whose namspace is no longer in the map, then
@@ -41,12 +126,8 @@ RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget(
// parent frame has not sent a new compositor frame since that happened.
if (iter == owner_map_.end())
return root_view;
- RenderWidgetHostViewBase* target = iter->second.get();
- // If we find the weak pointer is now null, it means the map entry is stale
- // and should be removed to free space.
- if (!target)
- owner_map_.erase(iter);
- return target;
+
+ return iter->second;
}
void RenderWidgetHostInputEventRouter::RouteMouseEvent(
@@ -79,6 +160,39 @@ void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent(
target->ProcessMouseWheelEvent(*event);
}
+void RenderWidgetHostInputEventRouter::RouteGestureEvent(
+ RenderWidgetHostViewBase* root_view,
+ blink::WebGestureEvent* event,
+ const ui::LatencyInfo& latency) {
+ // We use GestureTapDown to detect the start of a gesture sequence since there
+ // is no WebGestureEvent equivalent for ET_GESTURE_BEGIN. Note that this
+ // means the GestureFlingCancel that always comes between ET_GESTURE_BEGIN and
+ // GestureTapDown is sent to the previous target, in case it is still in a
+ // fling.
+ if (event->type == blink::WebInputEvent::GestureTapDown) {
+ if (gesture_target_queue_.empty()) {
+ LOG(ERROR) << "Gesture sequence start detected with no target available.";
+ // Ignore this gesture sequence as no target is available.
+ // TODO(wjmaclean): this only happens on Windows, and should not happen.
+ // https://crbug.com/595422
+ gesture_target_ = nullptr;
+ return;
+ }
+
+ const GestureTargetData& data = gesture_target_queue_.front();
+ gesture_target_ = data.target;
+ gesture_delta_ = data.delta;
+ gesture_target_queue_.pop_front();
+ }
+
+ if (!gesture_target_)
+ return;
+
+ event->x += gesture_delta_.x();
+ event->y += gesture_delta_.y();
+ gesture_target_->ProcessGestureEvent(*event, latency);
+}
+
void RenderWidgetHostInputEventRouter::RouteTouchEvent(
RenderWidgetHostViewBase* root_view,
blink::WebTouchEvent* event,
@@ -88,36 +202,50 @@ void RenderWidgetHostInputEventRouter::RouteTouchEvent(
if (!active_touches_) {
// Since this is the first touch, it defines the target for the rest
// of this sequence.
- DCHECK(!current_touch_target_);
+ DCHECK(!touch_target_);
gfx::Point transformed_point;
gfx::Point original_point(event->touches[0].position.x,
event->touches[0].position.y);
- RenderWidgetHostViewBase* target =
+ touch_target_ =
FindEventTarget(root_view, original_point, &transformed_point);
- if (!target)
- return;
- // Store the weak-ptr to the target, since it could disappear in the
- // middle of a touch sequence.
- current_touch_target_ = target->GetWeakPtr();
+ // TODO(wjmaclean): Instead of just computing a delta, we should extract
+ // the complete transform. We assume it doesn't change for the duration
+ // of the touch sequence, though this could be wrong; a better approach
+ // might be to always transform each point to the touch_target_
+ // for the duration of the sequence.
+ touch_delta_ = transformed_point - original_point;
+ gesture_target_queue_.emplace_back(touch_target_, touch_delta_);
+
+ if (!touch_target_)
+ return;
}
++active_touches_;
- if (current_touch_target_)
- current_touch_target_->ProcessTouchEvent(*event, latency);
+ if (touch_target_) {
+ TransformEventTouchPositions(event, touch_delta_);
+ touch_target_->ProcessTouchEvent(*event, latency);
+ }
break;
}
case blink::WebInputEvent::TouchMove:
- if (current_touch_target_)
- current_touch_target_->ProcessTouchEvent(*event, latency);
+ if (touch_target_) {
+ TransformEventTouchPositions(event, touch_delta_);
+ touch_target_->ProcessTouchEvent(*event, latency);
+ }
break;
case blink::WebInputEvent::TouchEnd:
case blink::WebInputEvent::TouchCancel:
+ if (!touch_target_)
+ break;
+
DCHECK(active_touches_);
- if (current_touch_target_)
- current_touch_target_->ProcessTouchEvent(*event, latency);
+ TransformEventTouchPositions(event, touch_delta_);
+ touch_target_->ProcessTouchEvent(*event, latency);
--active_touches_;
- if (!active_touches_)
- current_touch_target_ = WeakTarget();
+ if (!active_touches_) {
+ touch_target_ = nullptr;
+ touch_delta_ = gfx::Vector2d();
+ }
break;
default:
NOTREACHED();
@@ -128,12 +256,37 @@ void RenderWidgetHostInputEventRouter::AddSurfaceIdNamespaceOwner(
uint32_t id,
RenderWidgetHostViewBase* owner) {
DCHECK(owner_map_.find(id) == owner_map_.end());
- owner_map_.insert(std::make_pair(id, owner->GetWeakPtr()));
+ // We want to be notified if the owner is destroyed so we can remove it from
+ // our map.
+ owner->AddObserver(this);
+ owner_map_.insert(std::make_pair(id, owner));
}
void RenderWidgetHostInputEventRouter::RemoveSurfaceIdNamespaceOwner(
uint32_t id) {
- owner_map_.erase(id);
+ auto it_to_remove = owner_map_.find(id);
+ if (it_to_remove != owner_map_.end()) {
+ it_to_remove->second->RemoveObserver(this);
+ owner_map_.erase(it_to_remove);
+ }
+
+ for (auto it = hittest_data_.begin(); it != hittest_data_.end();) {
+ if (cc::SurfaceIdAllocator::NamespaceForId(it->first) == id)
+ it = hittest_data_.erase(it);
+ else
+ ++it;
+ }
+}
+
+void RenderWidgetHostInputEventRouter::OnHittestData(
+ const FrameHostMsg_HittestData_Params& params) {
+ if (owner_map_.find(cc::SurfaceIdAllocator::NamespaceForId(
+ params.surface_id)) == owner_map_.end()) {
+ return;
+ }
+ HittestData data;
+ data.ignored_for_hittest = params.ignored_for_hittest;
+ hittest_data_[params.surface_id] = data;
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
index 03902f5b3d1..b4123539c58 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -7,12 +7,22 @@
#include <stdint.h>
+#include <deque>
+#include <unordered_map>
+
#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
+#include "cc/surfaces/surface_hittest_delegate.h"
+#include "cc/surfaces/surface_id.h"
+#include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
#include "content/common/content_export.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+struct FrameHostMsg_HittestData_Params;
namespace blink {
+class WebGestureEvent;
class WebMouseEvent;
class WebMouseWheelEvent;
class WebTouchEvent;
@@ -36,15 +46,22 @@ class RenderWidgetHostViewBase;
// own. When an input event requires routing based on window coordinates,
// this class requests a Surface hit test from the provided |root_view| and
// forwards the event to the owning RWHV of the returned Surface ID.
-class CONTENT_EXPORT RenderWidgetHostInputEventRouter {
+class CONTENT_EXPORT RenderWidgetHostInputEventRouter
+ : public RenderWidgetHostViewBaseObserver {
public:
RenderWidgetHostInputEventRouter();
- ~RenderWidgetHostInputEventRouter();
+ ~RenderWidgetHostInputEventRouter() final;
+
+ void OnRenderWidgetHostViewBaseDestroyed(
+ RenderWidgetHostViewBase* view) override;
void RouteMouseEvent(RenderWidgetHostViewBase* root_view,
blink::WebMouseEvent* event);
void RouteMouseWheelEvent(RenderWidgetHostViewBase* root_view,
blink::WebMouseWheelEvent* event);
+ void RouteGestureEvent(RenderWidgetHostViewBase* root_view,
+ blink::WebGestureEvent* event,
+ const ui::LatencyInfo& latency);
void RouteTouchEvent(RenderWidgetHostViewBase* root_view,
blink::WebTouchEvent *event,
const ui::LatencyInfo& latency);
@@ -56,20 +73,57 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter {
return owner_map_.find(id) != owner_map_.end();
}
+ void OnHittestData(const FrameHostMsg_HittestData_Params& params);
+
private:
- using WeakTarget = base::WeakPtr<RenderWidgetHostViewBase>;
+ struct HittestData {
+ bool ignored_for_hittest;
+ };
+
+ class HittestDelegate : public cc::SurfaceHittestDelegate {
+ public:
+ HittestDelegate(
+ const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>&
+ hittest_data);
+ bool RejectHitTarget(const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) override;
+ bool AcceptHitTarget(const cc::SurfaceDrawQuad* surface_quad,
+ const gfx::Point& point_in_quad_space) override;
+
+ const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>&
+ hittest_data_;
+ };
+
using SurfaceIdNamespaceOwnerMap =
- base::hash_map<uint32_t, base::WeakPtr<RenderWidgetHostViewBase>>;
+ base::hash_map<uint32_t, RenderWidgetHostViewBase*>;
+ struct GestureTargetData {
+ RenderWidgetHostViewBase* target;
+ const gfx::Vector2d delta;
+
+ GestureTargetData(RenderWidgetHostViewBase* target, gfx::Vector2d delta)
+ : target(target), delta(delta) {}
+ };
+ using GestureTargetQueue = std::deque<GestureTargetData>;
+
+ void ClearAllObserverRegistrations();
RenderWidgetHostViewBase* FindEventTarget(RenderWidgetHostViewBase* root_view,
const gfx::Point& point,
gfx::Point* transformed_point);
SurfaceIdNamespaceOwnerMap owner_map_;
- WeakTarget current_touch_target_;
+ GestureTargetQueue gesture_target_queue_;
+ RenderWidgetHostViewBase* touch_target_;
+ RenderWidgetHostViewBase* gesture_target_;
+ gfx::Vector2d touch_delta_;
+ gfx::Vector2d gesture_delta_;
int active_touches_;
+ std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>
+ hittest_data_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouter);
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+ InputEventRouterGestureTargetQueueTest);
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_owner_delegate.h b/chromium/content/browser/renderer_host/render_widget_host_owner_delegate.h
index c2b0c45ec09..9bc1197fc6e 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_owner_delegate.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -41,10 +41,6 @@ class CONTENT_EXPORT RenderWidgetHostOwnerDelegate {
// The RenderWidgetHost got the focus.
virtual void RenderWidgetGotFocus() = 0;
- // The RenderWidgetHost will be hidden or shown.
- virtual void RenderWidgetWillBeHidden() = 0;
- virtual void RenderWidgetWillBeShown() = 0;
-
// The RenderWidgetHost forwarded a mouse event.
virtual void RenderWidgetDidForwardMouseEvent(
const blink::WebMouseEvent& mouse_event) = 0;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
index c76fc12376b..c56ec9ae858 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -22,6 +22,7 @@
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/common/input_messages.h"
+#include "content/common/resize_params.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/mock_render_process_host.h"
@@ -36,7 +37,7 @@
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#endif
-#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(USE_AURA) || defined(OS_MACOSX)
#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
#endif
@@ -124,6 +125,7 @@ class MockInputRouter : public InputRouter {
void RequestNotificationWhenFlushed() override {}
bool HasPendingEvents() const override { return false; }
void SetDeviceScaleFactor(float device_scale_factor) override {}
+ void SetFrameTreeNodeId(int frameTreeNodeId) override {}
// IPC::Listener
bool OnMessageReceived(const IPC::Message& message) override {
@@ -455,14 +457,14 @@ class RenderWidgetHostTest : public testing::Test {
browser_context_.reset(new TestBrowserContext());
delegate_.reset(new MockRenderWidgetHostDelegate());
process_ = new RenderWidgetHostProcess(browser_context_.get());
-#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(USE_AURA) || defined(OS_MACOSX)
ImageTransportFactory::InitializeForUnitTests(
scoped_ptr<ImageTransportFactory>(
new NoTransportImageTransportFactory));
#endif
#if defined(USE_AURA)
screen_.reset(aura::TestScreen::Create(gfx::Size()));
- gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
+ gfx::Screen::SetScreenInstance(screen_.get());
#endif
host_.reset(new MockRenderWidgetHost(delegate_.get(), process_,
process_->GetNextRoutingID()));
@@ -482,10 +484,10 @@ class RenderWidgetHostTest : public testing::Test {
browser_context_.reset();
#if defined(USE_AURA)
- gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, nullptr);
+ gfx::Screen::SetScreenInstance(nullptr);
screen_.reset();
#endif
-#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(USE_AURA) || defined(OS_MACOSX)
ImageTransportFactory::Terminate();
#endif
@@ -494,7 +496,7 @@ class RenderWidgetHostTest : public testing::Test {
}
void SetInitialRenderSizeParams() {
- ViewMsg_Resize_Params render_size_params;
+ ResizeParams render_size_params;
host_->GetResizeParams(&render_size_params);
host_->SetInitialRenderSizeParams(render_size_params);
}
@@ -1627,7 +1629,7 @@ TEST_F(RenderWidgetHostTest, ResizeParams) {
view_->set_bounds(bounds);
view_->SetMockPhysicalBackingSize(physical_backing_size);
- ViewMsg_Resize_Params resize_params;
+ ResizeParams resize_params;
host_->GetResizeParams(&resize_params);
EXPECT_EQ(bounds.size(), resize_params.new_size);
EXPECT_EQ(physical_backing_size, resize_params.physical_backing_size);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_android.cc b/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
index 841754602d9..acb9d446490 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -18,8 +18,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/threading/worker_pool.h"
-#include "cc/layers/delegated_frame_provider.h"
-#include "cc/layers/delegated_renderer_layer.h"
#include "cc/layers/layer.h"
#include "cc/layers/surface_layer.h"
#include "cc/output/compositor_frame.h"
@@ -40,6 +38,7 @@
#include "content/browser/android/overscroll_controller_android.h"
#include "content/browser/android/popup_touch_handle_drawable.h"
#include "content/browser/android/synchronous_compositor_base.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/compositor_util.h"
@@ -56,10 +55,9 @@
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "content/common/gpu/gpu_messages.h"
-#include "content/common/gpu/gpu_process_launch_causes.h"
+#include "content/common/gpu_host_messages.h"
+#include "content/common/gpu_process_launch_causes.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
@@ -118,25 +116,23 @@ const int kUndefinedOutputSurfaceId = -1;
static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
-class GLHelperHolder
- : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+class GLHelperHolder {
public:
static GLHelperHolder* Create();
- ~GLHelperHolder() override;
- void Initialize();
-
- // WebGraphicsContextLostCallback implementation.
- void onContextLost() override;
-
- GLHelper* GetGLHelper() { return gl_helper_.get(); }
- bool IsLost() { return !context_.get() || context_->isContextLost(); }
+ GLHelper* gl_helper() { return gl_helper_.get(); }
+ bool IsLost() {
+ if (!gl_helper_)
+ return true;
+ return provider_->ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+ }
private:
- GLHelperHolder();
- static scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext3D();
+ GLHelperHolder() = default;
+ void Initialize();
+ void OnContextLost();
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
+ scoped_refptr<ContextProviderCommandBuffer> provider_;
scoped_ptr<GLHelper> gl_helper_;
DISALLOW_COPY_AND_ASSIGN(GLHelperHolder);
@@ -145,49 +141,28 @@ class GLHelperHolder
GLHelperHolder* GLHelperHolder::Create() {
GLHelperHolder* holder = new GLHelperHolder;
holder->Initialize();
-
return holder;
}
-GLHelperHolder::GLHelperHolder() {
-}
-
-GLHelperHolder::~GLHelperHolder() {
-}
-
void GLHelperHolder::Initialize() {
- context_ = CreateContext3D();
- if (context_) {
- context_->setContextLostCallback(this);
- gl_helper_.reset(new GLHelper(context_->GetImplementation(),
- context_->GetContextSupport()));
- }
-}
+ auto* factory = BrowserGpuChannelHostFactory::instance();
+ scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
-void GLHelperHolder::onContextLost() {
- // Need to post a task because the command buffer client cannot be deleted
- // from within this callback.
- LOG(ERROR) << "Context lost.";
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&RenderWidgetHostViewAndroid::OnContextLost));
-}
-
-scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
-GLHelperHolder::CreateContext3D() {
- BrowserGpuChannelHostFactory* factory =
- BrowserGpuChannelHostFactory::instance();
- scoped_refptr<GpuChannelHost> gpu_channel_host(factory->GetGpuChannel());
- // GLHelper can only be used in asynchronous APIs for postprocessing after
- // Browser Compositor operations (i.e. readback).
- if (!gpu_channel_host.get()) {
- // The Browser Compositor is in charge of reestablishing the channel.
- return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
- }
+ // The Browser Compositor is in charge of reestablishing the channel if its
+ // missing.
+ if (!gpu_channel_host)
+ return;
+
+ // This is for an offscreen context, so we don't need the default framebuffer
+ // to have alpha, stencil, depth, antialiasing.
+ gpu::gles2::ContextCreationAttribHelper attributes;
+ attributes.alpha_size = -1;
+ attributes.stencil_size = 0;
+ attributes.depth_size = 0;
+ attributes.samples = 0;
+ attributes.sample_buffers = 0;
+ attributes.bind_generates_resource = false;
- blink::WebGraphicsContext3D::Attributes attrs;
- attrs.shareResources = true;
- GURL url("chrome://gpu/RenderWidgetHostViewAndroid");
static const size_t kBytesPerPixel = 4;
gfx::DeviceDisplayInfo display_info;
size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() *
@@ -201,23 +176,37 @@ GLHelperHolder::CreateContext3D() {
3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
limits.mapped_memory_reclaim_limit =
WebGraphicsContext3DCommandBufferImpl::kNoLimit;
- bool lose_context_when_out_of_memory = false;
+
+ bool share_resources = true;
+ // TODO(danakj): This should be false probably, it is for the main thread
+ // context which is used for GLHelper.
+ bool automatic_flushes = true;
+ GURL url("chrome://gpu/RenderWidgetHostViewAndroid");
+
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
new WebGraphicsContext3DCommandBufferImpl(
- 0, // offscreen
- url, gpu_channel_host.get(), attrs, lose_context_when_out_of_memory,
- limits, nullptr));
- context->SetContextType(BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
- if (context->InitializeOnCurrentThread()) {
- context->traceBeginCHROMIUM(
- "gpu_toplevel",
- base::StringPrintf("CmdBufferImageTransportFactory-%p",
- context.get()).c_str());
- } else {
- context.reset();
- }
+ gpu::kNullSurfaceHandle, // offscreen
+ url, gpu_channel_host.get(), attributes, gfx::PreferIntegratedGpu,
+ share_resources, automatic_flushes, limits, nullptr));
+ provider_ = ContextProviderCommandBuffer::Create(
+ std::move(context), BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
+ if (!provider_->BindToCurrentThread())
+ return;
+ provider_->ContextGL()->TraceBeginCHROMIUM(
+ "gpu_toplevel",
+ base::StringPrintf("CmdBufferImageTransportFactory-%p", provider_.get())
+ .c_str());
+ provider_->SetLostContextCallback(
+ base::Bind(&GLHelperHolder::OnContextLost, base::Unretained(this)));
+ gl_helper_.reset(
+ new GLHelper(provider_->ContextGL(), provider_->ContextSupport()));
+}
- return context;
+void GLHelperHolder::OnContextLost() {
+ // Need to post a task because the command buffer client cannot be deleted
+ // from within this callback.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&RenderWidgetHostViewAndroid::OnContextLost));
}
// This can only be used for readback postprocessing. It may return null if the
@@ -233,7 +222,7 @@ GLHelper* GetPostReadbackGLHelper() {
if (!g_readback_helper_holder)
g_readback_helper_holder = GLHelperHolder::Create();
- return g_readback_helper_holder->GetGLHelper();
+ return g_readback_helper_holder->gl_helper();
}
void CopyFromCompositingSurfaceFinished(
@@ -323,7 +312,6 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
is_window_visible_(true),
is_window_activity_started_(true),
content_view_core_(nullptr),
- content_view_core_window_android_(nullptr),
ime_adapter_android_(this),
cached_background_color_(SK_ColorWHITE),
last_output_surface_id_(kUndefinedOutputSurfaceId),
@@ -343,10 +331,10 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
}
RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() {
+ if (content_view_core_)
+ content_view_core_->RemoveObserver(this);
SetContentViewCore(NULL);
DCHECK(ack_callbacks_.empty());
- if (resource_collection_.get())
- resource_collection_->SetClient(NULL);
DCHECK(!surface_factory_);
DCHECK(surface_id_.is_null());
}
@@ -429,8 +417,7 @@ void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
src_subrect = gfx::Rect(bounds);
DCHECK_LE(src_subrect.width() + src_subrect.x(), bounds.width());
DCHECK_LE(src_subrect.height() + src_subrect.y(), bounds.height());
- const gfx::Display& display =
- gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
float device_scale_factor = display.device_scale_factor();
DCHECK_GT(device_scale_factor, 0);
gfx::Size dst_size(
@@ -444,21 +431,15 @@ void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
scoped_refptr<cc::Layer> RenderWidgetHostViewAndroid::CreateDelegatedLayer()
const {
scoped_refptr<cc::Layer> delegated_layer;
- if (!surface_id_.is_null()) {
- cc::SurfaceManager* manager = CompositorImpl::GetSurfaceManager();
- DCHECK(manager);
- // manager must outlive compositors using it.
- scoped_refptr<cc::SurfaceLayer> surface_layer = cc::SurfaceLayer::Create(
- Compositor::LayerSettings(),
- base::Bind(&SatisfyCallback, base::Unretained(manager)),
- base::Bind(&RequireCallback, base::Unretained(manager)));
- surface_layer->SetSurfaceId(surface_id_, 1.f, texture_size_in_layer_);
- delegated_layer = surface_layer;
- } else {
- DCHECK(frame_provider_.get());
- delegated_layer = cc::DelegatedRendererLayer::Create(
- Compositor::LayerSettings(), frame_provider_);
- }
+ DCHECK(!surface_id_.is_null());
+ cc::SurfaceManager* manager = CompositorImpl::GetSurfaceManager();
+ DCHECK(manager);
+ // manager must outlive compositors using it.
+ scoped_refptr<cc::SurfaceLayer> surface_layer = cc::SurfaceLayer::Create(
+ base::Bind(&SatisfyCallback, base::Unretained(manager)),
+ base::Bind(&RequireCallback, base::Unretained(manager)));
+ surface_layer->SetSurfaceId(surface_id_, 1.f, texture_size_in_layer_);
+ delegated_layer = surface_layer;
delegated_layer->SetBounds(texture_size_in_layer_);
delegated_layer->SetIsDrawable(true);
delegated_layer->SetContentsOpaque(true);
@@ -500,13 +481,6 @@ RenderWidgetHostViewAndroid::GetNativeViewAccessible() {
return NULL;
}
-void RenderWidgetHostViewAndroid::MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) {
- // We don't have plugin windows on Android. Do nothing. Note: this is called
- // from RenderWidgetHost::OnUpdateRect which is itself invoked while
- // processing the corresponding message from Renderer.
-}
-
void RenderWidgetHostViewAndroid::Focus() {
host_->Focus();
if (overscroll_controller_)
@@ -562,12 +536,14 @@ void RenderWidgetHostViewAndroid::LockCompositingSurface() {
}
void RenderWidgetHostViewAndroid::UnlockCompositingSurface() {
- if (!frame_evictor_->HasFrame() || locks_on_frame_count_ == 0)
+ if (!frame_evictor_->HasFrame()) {
+ DCHECK_EQ(locks_on_frame_count_, 0u);
return;
+ }
DCHECK(HasValidFrame());
- frame_evictor_->UnlockFrame();
locks_on_frame_count_--;
+ frame_evictor_->UnlockFrame();
if (locks_on_frame_count_ == 0) {
if (last_frame_info_) {
@@ -625,9 +601,20 @@ gfx::Rect RenderWidgetHostViewAndroid::GetViewBounds() const {
if (!content_view_core_)
return gfx::Rect(default_size_);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableOSKOverscroll))
+ return gfx::Rect(content_view_core_->GetViewSizeWithOSKHidden());
+
return gfx::Rect(content_view_core_->GetViewSize());
}
+gfx::Size RenderWidgetHostViewAndroid::GetVisibleViewportSize() const {
+ if (!content_view_core_)
+ return gfx::Rect(default_size_).size();
+
+ return gfx::Rect(content_view_core_->GetViewSize()).size();
+}
+
gfx::Size RenderWidgetHostViewAndroid::GetPhysicalBackingSize() const {
if (!content_view_core_)
return gfx::Size();
@@ -672,7 +659,7 @@ void RenderWidgetHostViewAndroid::TextInputStateChanged(
host_->Send(new InputMsg_ImeEventAck(host_->GetRoutingID()));
}
- if (!IsShowing())
+ if (!content_view_core_)
return;
content_view_core_->UpdateImeAdapter(
@@ -739,15 +726,15 @@ bool RenderWidgetHostViewAndroid::OnTouchEvent(
if (!result.succeeded)
return false;
- blink::WebTouchEvent web_event =
- ui::CreateWebTouchEventFromMotionEvent(event, result.did_generate_scroll);
+ blink::WebTouchEvent web_event = ui::CreateWebTouchEventFromMotionEvent(
+ event, result.moved_beyond_slop_region);
host_->ForwardTouchEventWithLatencyInfo(web_event, ui::LatencyInfo());
// Send a proactive BeginFrame for this vsync to reduce scroll latency for
// scroll-inducing touch events. Note that Android's Choreographer ensures
// that BeginFrame requests made during ACTION_MOVE dispatch will be honored
// in the same vsync phase.
- if (observing_root_window_ && result.did_generate_scroll)
+ if (observing_root_window_ && result.moved_beyond_slop_region)
RequestVSyncUpdate(BEGIN_FRAME);
return true;
@@ -798,7 +785,11 @@ void RenderWidgetHostViewAndroid::ImeCancelComposition() {
void RenderWidgetHostViewAndroid::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
- // TODO(yukawa): Implement this.
+ std::vector<gfx::RectF> character_bounds_float;
+ for (const gfx::Rect& rect : character_bounds) {
+ character_bounds_float.emplace_back(rect);
+ }
+ ime_adapter_android_.SetCharacterBounds(character_bounds_float);
}
void RenderWidgetHostViewAndroid::FocusedNodeChanged(bool is_editable_node) {
@@ -811,6 +802,7 @@ void RenderWidgetHostViewAndroid::RenderProcessGone(
}
void RenderWidgetHostViewAndroid::Destroy() {
+ host_->ViewDestroyed();
RemoveLayers();
SetContentViewCore(NULL);
@@ -885,8 +877,7 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
return;
}
- const gfx::Display& display =
- gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
float device_scale_factor = display.device_scale_factor();
gfx::Size dst_size_in_pixel =
gfx::ConvertRectToPixel(device_scale_factor, gfx::Rect(dst_size)).size();
@@ -901,27 +892,22 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
return;
}
- scoped_ptr<cc::CopyOutputRequest> request;
- scoped_refptr<cc::Layer> readback_layer;
- DCHECK(content_view_core_window_android_);
+ if (!content_view_core_ || !(content_view_core_->GetWindowAndroid())) {
+ callback.Run(SkBitmap(), READBACK_FAILED);
+ return;
+ }
ui::WindowAndroidCompositor* compositor =
- content_view_core_window_android_->GetCompositor();
+ content_view_core_->GetWindowAndroid()->GetCompositor();
DCHECK(compositor);
- DCHECK(frame_provider_.get() || !surface_id_.is_null());
- scoped_refptr<cc::Layer> layer = CreateDelegatedLayer();
- DCHECK(layer);
- layer->SetHideLayerAndSubtree(true);
- compositor->AttachLayerForReadback(layer);
-
- readback_layer = layer;
- request = cc::CopyOutputRequest::CreateRequest(
- base::Bind(&RenderWidgetHostViewAndroid::
- PrepareTextureCopyOutputResultForDelegatedReadback,
- dst_size_in_pixel, preferred_color_type, start_time,
- readback_layer, callback));
+ DCHECK(!surface_id_.is_null());
+ scoped_ptr<cc::CopyOutputRequest> request =
+ cc::CopyOutputRequest::CreateRequest(
+ base::Bind(&PrepareTextureCopyOutputResult,
+ dst_size_in_pixel, preferred_color_type, start_time,
+ callback));
if (!src_subrect_in_pixel.IsEmpty())
request->set_area(src_subrect_in_pixel);
- readback_layer->RequestCopyOfOutput(std::move(request));
+ layer_->RequestCopyOfOutput(std::move(request));
}
void RenderWidgetHostViewAndroid::CopyFromCompositingSurfaceToVideoFrame(
@@ -956,8 +942,6 @@ void RenderWidgetHostViewAndroid::SendDelegatedFrameAck(
cc::CompositorFrameAck ack;
if (!surface_returned_resources_.empty())
ack.resources.swap(surface_returned_resources_);
- if (resource_collection_.get())
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
host_->Send(new ViewMsg_SwapCompositorFrameAck(host_->GetRoutingID(),
output_surface_id, ack));
}
@@ -966,24 +950,13 @@ void RenderWidgetHostViewAndroid::SendReturnedDelegatedResources(
uint32_t output_surface_id) {
DCHECK(host_);
cc::CompositorFrameAck ack;
- if (!surface_returned_resources_.empty()) {
- ack.resources.swap(surface_returned_resources_);
- } else {
- DCHECK(resource_collection_.get());
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
- }
+ DCHECK(!surface_returned_resources_.empty());
+ ack.resources.swap(surface_returned_resources_);
host_->Send(new ViewMsg_ReclaimCompositorResources(host_->GetRoutingID(),
output_surface_id, ack));
}
-void RenderWidgetHostViewAndroid::UnusedResourcesAreAvailable() {
- DCHECK(surface_id_.is_null());
- if (ack_callbacks_.size())
- return;
- SendReturnedDelegatedResources(last_output_surface_id_);
-}
-
void RenderWidgetHostViewAndroid::ReturnResources(
const cc::ReturnedResourceArray& resources) {
if (resources.empty())
@@ -995,14 +968,12 @@ void RenderWidgetHostViewAndroid::ReturnResources(
}
void RenderWidgetHostViewAndroid::SetBeginFrameSource(
- cc::SurfaceId surface_id,
cc::BeginFrameSource* begin_frame_source) {
// TODO(tansell): Hook this up.
}
void RenderWidgetHostViewAndroid::DestroyDelegatedContent() {
RemoveLayers();
- frame_provider_ = NULL;
if (!surface_id_.is_null()) {
DCHECK(surface_factory_.get());
surface_factory_->Destroy(surface_id_);
@@ -1015,14 +986,6 @@ void RenderWidgetHostViewAndroid::CheckOutputSurfaceChanged(
uint32_t output_surface_id) {
if (output_surface_id == last_output_surface_id_)
return;
- // Drop the cc::DelegatedFrameResourceCollection so that we will not return
- // any resources from the old output surface with the new output surface id.
- if (resource_collection_.get()) {
- resource_collection_->SetClient(NULL);
- if (resource_collection_->LoseAllResources())
- SendReturnedDelegatedResources(last_output_surface_id_);
- resource_collection_ = NULL;
- }
DestroyDelegatedContent();
surface_factory_.reset();
if (!surface_returned_resources_.empty())
@@ -1034,53 +997,35 @@ void RenderWidgetHostViewAndroid::CheckOutputSurfaceChanged(
void RenderWidgetHostViewAndroid::SubmitCompositorFrame(
scoped_ptr<cc::CompositorFrame> frame) {
cc::SurfaceManager* manager = CompositorImpl::GetSurfaceManager();
- if (manager) {
- if (!surface_factory_) {
- surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
- }
- if (surface_id_.is_null() ||
- texture_size_in_layer_ != current_surface_size_ ||
- location_bar_content_translation_ !=
- frame->metadata.location_bar_content_translation ||
- current_viewport_selection_ != frame->metadata.selection) {
- RemoveLayers();
- if (!surface_id_.is_null())
- surface_factory_->Destroy(surface_id_);
- surface_id_ = id_allocator_->GenerateId();
- surface_factory_->Create(surface_id_);
- layer_ = CreateDelegatedLayer();
-
- DCHECK(layer_);
-
- current_surface_size_ = texture_size_in_layer_;
- location_bar_content_translation_ =
- frame->metadata.location_bar_content_translation;
- current_viewport_selection_ = frame->metadata.selection;
- AttachLayers();
- }
-
- cc::SurfaceFactory::DrawCallback ack_callback =
- base::Bind(&RenderWidgetHostViewAndroid::RunAckCallbacks,
- weak_ptr_factory_.GetWeakPtr());
- surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
- ack_callback);
- } else {
- if (!resource_collection_.get()) {
- resource_collection_ = new cc::DelegatedFrameResourceCollection;
- resource_collection_->SetClient(this);
- }
- if (!frame_provider_.get() ||
- texture_size_in_layer_ != frame_provider_->frame_size()) {
- RemoveLayers();
- frame_provider_ = new cc::DelegatedFrameProvider(
- resource_collection_.get(), std::move(frame->delegated_frame_data));
- layer_ = cc::DelegatedRendererLayer::Create(Compositor::LayerSettings(),
- frame_provider_);
- AttachLayers();
- } else {
- frame_provider_->SetFrameData(std::move(frame->delegated_frame_data));
- }
+ if (!surface_factory_) {
+ surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
}
+ if (surface_id_.is_null() ||
+ texture_size_in_layer_ != current_surface_size_ ||
+ location_bar_content_translation_ !=
+ frame->metadata.location_bar_content_translation ||
+ current_viewport_selection_ != frame->metadata.selection) {
+ RemoveLayers();
+ if (!surface_id_.is_null())
+ surface_factory_->Destroy(surface_id_);
+ surface_id_ = id_allocator_->GenerateId();
+ surface_factory_->Create(surface_id_);
+ layer_ = CreateDelegatedLayer();
+
+ DCHECK(layer_);
+
+ current_surface_size_ = texture_size_in_layer_;
+ location_bar_content_translation_ =
+ frame->metadata.location_bar_content_translation;
+ current_viewport_selection_ = frame->metadata.selection;
+ AttachLayers();
+ }
+
+ cc::SurfaceFactory::DrawCallback ack_callback =
+ base::Bind(&RenderWidgetHostViewAndroid::RunAckCallbacks,
+ weak_ptr_factory_.GetWeakPtr());
+ surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
+ ack_callback);
}
void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
@@ -1233,9 +1178,9 @@ bool RenderWidgetHostViewAndroid::SupportsAnimation() const {
}
void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
- DCHECK(content_view_core_window_android_);
+ DCHECK(content_view_core_ && content_view_core_->GetWindowAndroid());
DCHECK(using_browser_compositor_);
- content_view_core_window_android_->SetNeedsAnimate();
+ content_view_core_->GetWindowAndroid()->SetNeedsAnimate();
}
void RenderWidgetHostViewAndroid::MoveCaret(const gfx::PointF& position) {
@@ -1364,7 +1309,8 @@ void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
frame_metadata.scrollable_viewport_size,
frame_metadata.location_bar_offset,
frame_metadata.location_bar_content_translation,
- is_mobile_optimized);
+ is_mobile_optimized,
+ frame_metadata.selection.start);
#if defined(VIDEO_HOLE)
if (host_) {
WebContents* web_contents =
@@ -1473,17 +1419,20 @@ void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32_t requests) {
// vsync requests will be pushed if/when we resume observing in
// |StartObservingRootWindow()|.
if (observing_root_window_ && should_request_vsync)
- content_view_core_window_android_->RequestVSyncUpdate();
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
}
void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
- DCHECK(content_view_core_window_android_);
+ DCHECK(content_view_core_);
+ // TODO(yusufo): This will need to have a better fallback for cases where
+ // setContentViewCore is called with a valid ContentViewCore without a window.
+ DCHECK(content_view_core_->GetWindowAndroid());
DCHECK(is_showing_);
if (observing_root_window_)
return;
observing_root_window_ = true;
- content_view_core_window_android_->AddObserver(this);
+ content_view_core_->GetWindowAndroid()->AddObserver(this);
// Clear existing vsync requests to allow a request to the new window.
uint32_t outstanding_vsync_requests = outstanding_vsync_requests_;
@@ -1492,7 +1441,7 @@ void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
}
void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
- if (!content_view_core_window_android_) {
+ if (!content_view_core_ || !(content_view_core_->GetWindowAndroid())) {
DCHECK(!observing_root_window_);
return;
}
@@ -1504,7 +1453,7 @@ void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
is_window_activity_started_ = true;
is_window_visible_ = true;
observing_root_window_ = false;
- content_view_core_window_android_->RemoveObserver(this);
+ content_view_core_->GetWindowAndroid()->RemoveObserver(this);
}
void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time,
@@ -1547,9 +1496,10 @@ void RenderWidgetHostViewAndroid::RequestDisallowInterceptTouchEvent() {
}
void RenderWidgetHostViewAndroid::EvictDelegatedFrame() {
+ DCHECK_EQ(locks_on_frame_count_, 0u);
+ frame_evictor_->DiscardedFrame();
if (layer_.get())
DestroyDelegatedContent();
- frame_evictor_->DiscardedFrame();
}
bool RenderWidgetHostViewAndroid::HasAcceleratedSurface(
@@ -1660,22 +1610,12 @@ void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
BrowserAccessibilityManager*
RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) {
- // TODO(dmazzoni): Currently there can only be one
- // BrowserAccessibilityManager per ContentViewCore, so return NULL
- // if there's already a BrowserAccessibilityManager for the main
- // frame. Eventually, in order to support cross-process iframes on
- // Android we'll need to add support for a
- // BrowserAccessibilityManager for a child frame.
- // http://crbug.com/423846
- if (!host_ || host_->GetRootBrowserAccessibilityManager())
- return NULL;
-
- base::android::ScopedJavaLocalRef<jobject> obj;
- if (content_view_core_)
- obj = content_view_core_->GetJavaObject();
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
+ base::android::ScopedJavaLocalRef<jobject> content_view_core_obj;
+ if (for_root_frame && host_ && content_view_core_)
+ content_view_core_obj = content_view_core_->GetJavaObject();
return new BrowserAccessibilityManagerAndroid(
- obj,
+ content_view_core_obj,
BrowserAccessibilityManagerAndroid::GetEmptyDocument(),
delegate);
}
@@ -1772,6 +1712,9 @@ SkColor RenderWidgetHostViewAndroid::GetCachedBackgroundColor() const {
void RenderWidgetHostViewAndroid::DidOverscroll(
const DidOverscrollParams& params) {
+ if (sync_compositor_)
+ sync_compositor_->DidOverscroll(params);
+
if (!content_view_core_ || !layer_.get() || !is_showing_)
return;
@@ -1803,12 +1746,13 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
selection_controller_.reset();
ReleaseLocksOnSurface();
resize = true;
+ if (content_view_core_)
+ content_view_core_->RemoveObserver(this);
+ if (content_view_core)
+ content_view_core->AddObserver(this);
}
content_view_core_ = content_view_core;
- content_view_core_window_android_ =
- content_view_core_ ? content_view_core_->GetWindowAndroid() : nullptr;
- DCHECK_EQ(!!content_view_core_, !!content_view_core_window_android_);
BrowserAccessibilityManager* manager = NULL;
if (host_)
@@ -1836,7 +1780,7 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
selection_controller_ = CreateSelectionController(this, content_view_core_);
if (!overscroll_controller_ &&
- content_view_core_window_android_->GetCompositor()) {
+ content_view_core_->GetWindowAndroid()->GetCompositor()) {
overscroll_controller_ = CreateOverscrollController(content_view_core_);
}
@@ -1871,6 +1815,10 @@ void RenderWidgetHostViewAndroid::OnGestureEvent(
SendGestureEvent(web_gesture);
}
+void RenderWidgetHostViewAndroid::OnContentViewCoreDestroyed() {
+ SetContentViewCore(NULL);
+}
+
void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
RunAckCallbacks(cc::SurfaceDrawStatus::DRAWN);
}
@@ -1891,6 +1839,19 @@ void RenderWidgetHostViewAndroid::OnRootWindowVisibilityChanged(bool visible) {
HideInternal();
}
+void RenderWidgetHostViewAndroid::OnAttachedToWindow() {
+ if (is_showing_)
+ StartObservingRootWindow();
+ DCHECK(content_view_core_ && content_view_core_->GetWindowAndroid());
+ if (content_view_core_->GetWindowAndroid()->GetCompositor())
+ OnAttachCompositor();
+}
+
+void RenderWidgetHostViewAndroid::OnDetachedFromWindow() {
+ StopObservingRootWindow();
+ OnDetachCompositor();
+}
+
void RenderWidgetHostViewAndroid::OnAttachCompositor() {
DCHECK(content_view_core_);
if (!overscroll_controller_)
@@ -1954,19 +1915,10 @@ void RenderWidgetHostViewAndroid::OnLostResources() {
DCHECK(ack_callbacks_.empty());
}
-// static
-void RenderWidgetHostViewAndroid::
- PrepareTextureCopyOutputResultForDelegatedReadback(
- const gfx::Size& dst_size_in_pixel,
- SkColorType color_type,
- const base::TimeTicks& start_time,
- scoped_refptr<cc::Layer> readback_layer,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result) {
- readback_layer->RemoveFromParent();
- PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type, start_time,
- callback, std::move(result));
-}
+// TODO(wjmaclean): There is significant overlap between
+// PrepareTextureCopyOutputResult and CopyFromCompositingSurfaceFinished in
+// this file, and the versions in surface_utils.cc. They should
+// be merged. See https://crbug.com/582955
// static
void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
@@ -2057,8 +2009,7 @@ void RenderWidgetHostViewAndroid::OnStylusSelectTap(base::TimeTicks time,
// static
void RenderWidgetHostViewBase::GetDefaultScreenInfo(
blink::WebScreenInfo* results) {
- const gfx::Display& display =
- gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
+ const gfx::Display& display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
results->rect = display.bounds();
// TODO(husky): Remove any system controls from availableRect.
results->availableRect = display.work_area();
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_android.h b/chromium/content/browser/renderer_host/render_widget_host_view_android.h
index 0d51b7037fe..ed0cd31d666 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_android.h
@@ -18,11 +18,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
-#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/output/begin_frame_args.h"
#include "cc/surfaces/surface_factory_client.h"
#include "cc/surfaces/surface_id.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/android/content_view_core_impl_observer.h"
#include "content/browser/renderer_host/delegated_frame_evictor.h"
#include "content/browser/renderer_host/ime_adapter_android.h"
#include "content/browser/renderer_host/input/stylus_text_selector.h"
@@ -42,8 +42,6 @@ struct ViewHostMsg_TextInputState_Params;
namespace cc {
class CopyOutputResult;
-class DelegatedFrameProvider;
-class DelegatedRendererLayer;
class Layer;
class SurfaceFactory;
class SurfaceIdAllocator;
@@ -58,6 +56,7 @@ class WebMouseEvent;
namespace content {
class ContentViewCoreImpl;
+class ContentViewCoreObserver;
class OverscrollControllerAndroid;
class RenderWidgetHost;
class RenderWidgetHostImpl;
@@ -70,13 +69,13 @@ struct NativeWebKeyboardEvent;
// -----------------------------------------------------------------------------
class CONTENT_EXPORT RenderWidgetHostViewAndroid
: public RenderWidgetHostViewBase,
- public cc::DelegatedFrameResourceCollectionClient,
public cc::SurfaceFactoryClient,
public ui::GestureProviderClient,
public ui::WindowAndroidObserver,
public DelegatedFrameEvictorClient,
public StylusTextSelectorClient,
- public ui::TouchSelectionControllerClient {
+ public ui::TouchSelectionControllerClient,
+ public content::ContentViewCoreImplObserver {
public:
RenderWidgetHostViewAndroid(RenderWidgetHostImpl* widget,
ContentViewCoreImpl* content_view_core);
@@ -97,7 +96,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
gfx::NativeView GetNativeView() const override;
gfx::NativeViewId GetNativeViewId() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void Focus() override;
bool HasFocus() const override;
bool IsSurfaceAvailableForCopy() const override;
@@ -105,6 +103,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void Hide() override;
bool IsShowing() override;
gfx::Rect GetViewBounds() const override;
+ gfx::Size GetVisibleViewportSize() const override;
gfx::Size GetPhysicalBackingSize() const override;
bool DoTopControlsShrinkBlinkSize() const override;
float GetTopControlsHeight() const override;
@@ -149,7 +148,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void GestureEventAck(const blink::WebGestureEvent& event,
InputEventAckState ack_result) override;
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) override;
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) override;
bool LockMouse() override;
void UnlockMouse() override;
void OnSwapCompositorFrame(uint32_t output_surface_id,
@@ -168,13 +167,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
size_t end_offset) override;
void OnDidNavigateMainFrameToNewPage() override;
- // cc::DelegatedFrameResourceCollectionClient implementation.
- void UnusedResourcesAreAvailable() override;
-
// cc::SurfaceFactoryClient implementation.
void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void SetBeginFrameSource(cc::SurfaceId surface_id,
- cc::BeginFrameSource* begin_frame_source) override;
+ void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
// ui::GestureProviderClient implementation.
void OnGestureEvent(const ui::GestureEventData& gesture) override;
@@ -190,6 +185,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void OnActivityStopped() override;
void OnActivityStarted() override;
+ // content::ContentViewCoreImplObserver implementation.
+ void OnContentViewCoreDestroyed() override;
+ void OnAttachedToWindow() override;
+ void OnDetachedFromWindow() override;
+
// DelegatedFrameEvictor implementation
void EvictDelegatedFrame() override;
@@ -291,13 +291,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const base::TimeTicks& start_time,
const ReadbackRequestCallback& callback,
scoped_ptr<cc::CopyOutputResult> result);
- static void PrepareTextureCopyOutputResultForDelegatedReadback(
- const gfx::Size& dst_size_in_pixel,
- SkColorType color_type,
- const base::TimeTicks& start_time,
- scoped_refptr<cc::Layer> readback_layer,
- const ReadbackRequestCallback& callback,
- scoped_ptr<cc::CopyOutputResult> result);
// DevTools ScreenCast support for Android WebView.
void SynchronousCopyContents(const gfx::Rect& src_subrect_in_pixel,
@@ -350,20 +343,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// ContentViewCoreImpl is our interface to the view system.
ContentViewCoreImpl* content_view_core_;
- // Cache the WindowAndroid instance exposed by ContentViewCore to avoid
- // calling into ContentViewCore when it is being detached from the
- // WebContents during destruction. The WindowAndroid has stronger lifetime
- // guarantees, and should be safe to use for observer detachment.
- // This will be non-null iff |content_view_core_| is non-null.
- ui::WindowAndroid* content_view_core_window_android_;
-
ImeAdapterAndroid ime_adapter_android_;
// Body background color of the underlying document.
SkColor cached_background_color_;
- scoped_refptr<cc::DelegatedFrameResourceCollection> resource_collection_;
- scoped_refptr<cc::DelegatedFrameProvider> frame_provider_;
scoped_refptr<cc::Layer> layer_;
scoped_ptr<cc::SurfaceIdAllocator> id_allocator_;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
index c5494d9976f..30b07782949 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -25,6 +25,7 @@
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/bad_message.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
@@ -44,8 +45,7 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/ui_events_helper.h"
#include "content/browser/renderer_host/web_input_event_aura.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/content_switches_internal.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
#include "content/public/browser/content_browser_client.h"
@@ -54,6 +54,7 @@
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -99,10 +100,9 @@
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
-#include "content/common/plugin_constants_win.h"
#include "ui/base/win/hidden_window.h"
+#include "ui/display/win/screen_win.h"
#include "ui/gfx/gdi_util.h"
-#include "ui/gfx/screen_win.h"
#include "ui/gfx/win/dpi.h"
#endif
@@ -140,97 +140,6 @@ const int kMouseLockBorderPercentage = 15;
const int kResizeLockTimeoutMs = 67;
#if defined(OS_WIN)
-// Used to associate a plugin HWND with its RenderWidgetHostViewAura instance.
-const wchar_t kWidgetOwnerProperty[] = L"RenderWidgetHostViewAuraOwner";
-
-BOOL CALLBACK WindowDestroyingCallback(HWND window, LPARAM param) {
- RenderWidgetHostViewAura* widget =
- reinterpret_cast<RenderWidgetHostViewAura*>(param);
- if (GetProp(window, kWidgetOwnerProperty) == widget) {
- // Properties set on HWNDs must be removed to avoid leaks.
- RemoveProp(window, kWidgetOwnerProperty);
- RenderWidgetHostViewBase::DetachPluginWindowsCallback(window);
- }
- return TRUE;
-}
-
-BOOL CALLBACK HideWindowsCallback(HWND window, LPARAM param) {
- RenderWidgetHostViewAura* widget =
- reinterpret_cast<RenderWidgetHostViewAura*>(param);
- if (GetProp(window, kWidgetOwnerProperty) == widget)
- SetParent(window, ui::GetHiddenWindow());
- return TRUE;
-}
-
-BOOL CALLBACK ShowWindowsCallback(HWND window, LPARAM param) {
- RenderWidgetHostViewAura* widget =
- reinterpret_cast<RenderWidgetHostViewAura*>(param);
-
- if (GetProp(window, kWidgetOwnerProperty) == widget &&
- widget->GetNativeView()->GetHost()) {
- HWND parent = widget->GetNativeView()->GetHost()->GetAcceleratedWidget();
- SetParent(window, parent);
- }
- return TRUE;
-}
-
-struct CutoutRectsParams {
- RenderWidgetHostViewAura* widget;
- std::vector<gfx::Rect> cutout_rects;
- std::map<HWND, WebPluginGeometry>* geometry;
-};
-
-// Used to update the region for the windowed plugin to draw in. We start with
-// the clip rect from the renderer, then remove the cutout rects from the
-// renderer, and then remove the transient windows from the root window and the
-// constrained windows from the parent window.
-BOOL CALLBACK SetCutoutRectsCallback(HWND window, LPARAM param) {
- CutoutRectsParams* params = reinterpret_cast<CutoutRectsParams*>(param);
-
- if (GetProp(window, kWidgetOwnerProperty) == params->widget) {
- // First calculate the offset of this plugin from the root window, since
- // the cutouts are relative to the root window.
- HWND parent =
- params->widget->GetNativeView()->GetHost()->GetAcceleratedWidget();
- POINT offset;
- offset.x = offset.y = 0;
- MapWindowPoints(window, parent, &offset, 1);
-
- // Now get the cached clip rect and cutouts for this plugin window that came
- // from the renderer.
- std::map<HWND, WebPluginGeometry>::iterator i = params->geometry->begin();
- while (i != params->geometry->end() &&
- i->second.window != window &&
- GetParent(i->second.window) != window) {
- ++i;
- }
-
- if (i == params->geometry->end()) {
- NOTREACHED();
- return TRUE;
- }
-
- HRGN hrgn = CreateRectRgn(i->second.clip_rect.x(),
- i->second.clip_rect.y(),
- i->second.clip_rect.right(),
- i->second.clip_rect.bottom());
- // We start with the cutout rects that came from the renderer, then add the
- // ones that came from transient and constrained windows.
- std::vector<gfx::Rect> cutout_rects = i->second.cutout_rects;
- for (size_t i = 0; i < params->cutout_rects.size(); ++i) {
- gfx::Rect offset_cutout = params->cutout_rects[i];
- offset_cutout.Offset(-offset.x, -offset.y);
- cutout_rects.push_back(offset_cutout);
- }
- gfx::SubtractRectanglesFromRegion(hrgn, cutout_rects);
- // If we don't have any cutout rects then no point in messing with the
- // window region.
- if (cutout_rects.size())
- SetWindowRgn(window, hrgn, TRUE);
- }
- return TRUE;
-}
-
// A callback function for EnumThreadWindows to enumerate and dismiss
// any owned popup windows.
BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
@@ -261,9 +170,9 @@ bool IsXButtonUpEvent(const ui::MouseEvent* event) {
}
void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) {
- const gfx::Display display = window ?
- gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window) :
- gfx::Screen::GetScreenFor(window)->GetPrimaryDisplay();
+ gfx::Screen* screen = gfx::Screen::GetScreen();
+ const gfx::Display display = window ? screen->GetDisplayNearestWindow(window)
+ : screen->GetPrimaryDisplay();
results->rect = display.bounds();
results->availableRect = display.work_area();
// TODO(derat|oshima): Don't hardcode this. Get this from display object.
@@ -474,21 +383,20 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
#if defined(OS_WIN)
legacy_render_widget_host_HWND_(NULL),
legacy_window_destroyed_(false),
- showing_context_menu_(false),
#endif
has_snapped_to_boundary_(false),
is_guest_view_hack_(is_guest_view_hack),
begin_frame_observer_proxy_(this),
set_focus_on_mouse_down_or_key_event_(false),
device_scale_factor_(0.0f),
+ disable_input_event_router_for_testing_(false),
weak_ptr_factory_(this) {
if (!is_guest_view_hack_)
host_->SetView(this);
// Let the page-level input event router know about our surface ID
// namespace for surface-based hit testing.
- if (UseSurfacesEnabled() && host_->delegate() &&
- host_->delegate()->GetInputEventRouter()) {
+ if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
host_->delegate()->GetInputEventRouter()->AddSurfaceIdNamespaceOwner(
GetSurfaceIdNamespace(), this);
}
@@ -528,7 +436,7 @@ void RenderWidgetHostViewAura::InitAsChild(
parent_view->AddChild(GetNativeView());
const gfx::Display display =
- gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
@@ -581,7 +489,7 @@ void RenderWidgetHostViewAura::InitAsPopup(
event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));
const gfx::Display display =
- gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
@@ -604,8 +512,8 @@ void RenderWidgetHostViewAura::InitAsFullscreen(
host_tracker_.reset(new aura::WindowTracker);
host_tracker_->Add(reference_window);
}
- gfx::Display display = gfx::Screen::GetScreenFor(window_)->
- GetDisplayNearestWindow(reference_window);
+ gfx::Display display =
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(reference_window);
parent = reference_window->GetRootWindow();
bounds = display.bounds();
}
@@ -614,7 +522,7 @@ void RenderWidgetHostViewAura::InitAsFullscreen(
Focus();
const gfx::Display display =
- gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow(window_);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
@@ -659,29 +567,22 @@ void RenderWidgetHostViewAura::Show() {
GetNativeView()->GetHost()->GetAcceleratedWidget());
legacy_render_widget_host_HWND_->SetBounds(
window_->GetBoundsInRootWindow());
- }
- LPARAM lparam = reinterpret_cast<LPARAM>(this);
- EnumChildWindows(ui::GetHiddenWindow(), ShowWindowsCallback, lparam);
-
- if (legacy_render_widget_host_HWND_)
legacy_render_widget_host_HWND_->Show();
+ }
#endif
}
void RenderWidgetHostViewAura::Hide() {
window_->Hide();
+ // TODO(wjmaclean): can host_ ever be null?
if (host_ && !host_->is_hidden()) {
host_->WasHidden();
delegated_frame_host_->WasHidden();
#if defined(OS_WIN)
- constrained_rects_.clear();
aura::WindowTreeHost* host = window_->GetHost();
if (host) {
- HWND parent = host->GetAcceleratedWidget();
- LPARAM lparam = reinterpret_cast<LPARAM>(this);
- EnumChildWindows(parent, HideWindowsCallback, lparam);
// We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
// hidden window on the same lines as Windowed plugin windows.
if (legacy_render_widget_host_HWND_)
@@ -746,7 +647,7 @@ gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() {
BrowserAccessibilityManager* manager =
host_->GetOrCreateRootBrowserAccessibilityManager();
if (manager)
- return manager->GetRoot()->ToBrowserAccessibilityWin();
+ return ToBrowserAccessibilityWin(manager->GetRoot());
#endif
NOTIMPLEMENTED();
@@ -770,10 +671,14 @@ void RenderWidgetHostViewAura::SetKeyboardFocus() {
#if defined(OS_WIN)
if (CanFocus()) {
aura::WindowTreeHost* host = window_->GetHost();
- if (host)
- ::SetFocus(host->GetAcceleratedWidget());
+ if (host) {
+ gfx::AcceleratedWidget hwnd = host->GetAcceleratedWidget();
+ if (!(::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE))
+ ::SetFocus(hwnd);
+ }
}
#endif
+ // TODO(wjmaclean): can host_ ever be null?
if (host_ && set_focus_on_mouse_down_or_key_event_) {
set_focus_on_mouse_down_or_key_event_ = false;
host_->Focus();
@@ -795,12 +700,7 @@ RenderFrameHostImpl* RenderWidgetHostViewAura::GetFocusedFrame() {
bool RenderWidgetHostViewAura::CanRendererHandleEvent(
const ui::MouseEvent* event,
bool mouse_locked,
- bool selection_popup) {
-#if defined(OS_WIN)
- bool showing_context_menu = showing_context_menu_;
- showing_context_menu_ = false;
-#endif
-
+ bool selection_popup) const {
if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
return false;
@@ -811,7 +711,7 @@ bool RenderWidgetHostViewAura::CanRendererHandleEvent(
// Don't forward the mouse leave message which is received when the context
// menu is displayed by the page. This confuses the page and causes state
// changes.
- if (showing_context_menu)
+ if (IsShowingContextMenu())
return false;
#endif
return true;
@@ -870,7 +770,8 @@ bool RenderWidgetHostViewAura::ShouldRouteEvent(const ui::Event* event) const {
// frame. TODO(wjmaclean): At present, this doesn't work for OOPIF, but
// it should be a simple extension to modify RenderWidgetHostViewChildFrame
// in a similar manner to RenderWidgetHostViewGuest.
- bool result = host_->delegate() && host_->delegate()->GetInputEventRouter();
+ bool result = host_->delegate() && host_->delegate()->GetInputEventRouter() &&
+ !disable_input_event_router_for_testing_;
if (event->IsMouseEvent())
result = result && SiteIsolationPolicy::AreCrossProcessFramesPossible();
return result;
@@ -884,8 +785,14 @@ void RenderWidgetHostViewAura::HandleParentBoundsChanged() {
window_->GetBoundsInRootWindow());
}
#endif
- if (!in_shutdown_)
- host_->SendScreenRects();
+ if (!in_shutdown_) {
+ // Send screen rects through the delegate if there is one. Not every
+ // RenderWidgetHost has a delegate (for example, drop-down widgets).
+ if (host_->delegate())
+ host_->delegate()->SendScreenRects();
+ else
+ host_->SendScreenRects();
+ }
}
void RenderWidgetHostViewAura::ParentHierarchyChanged() {
@@ -894,58 +801,6 @@ void RenderWidgetHostViewAura::ParentHierarchyChanged() {
HandleParentBoundsChanged();
}
-void RenderWidgetHostViewAura::MovePluginWindows(
- const std::vector<WebPluginGeometry>& plugin_window_moves) {
-#if defined(OS_WIN)
- // We need to clip the rectangle to the tab's viewport, otherwise we will draw
- // over the browser UI.
- if (!window_->GetRootWindow()) {
- DCHECK(plugin_window_moves.empty());
- return;
- }
- HWND parent = window_->GetHost()->GetAcceleratedWidget();
- gfx::Rect view_bounds = window_->GetBoundsInRootWindow();
- std::vector<WebPluginGeometry> moves = plugin_window_moves;
-
- gfx::Rect view_port(view_bounds.size());
-
- for (size_t i = 0; i < moves.size(); ++i) {
- gfx::Rect clip(moves[i].clip_rect);
- gfx::Vector2d view_port_offset(
- moves[i].window_rect.OffsetFromOrigin());
- clip.Offset(view_port_offset);
- clip.Intersect(view_port);
- clip.Offset(-view_port_offset);
- moves[i].clip_rect = clip;
-
- moves[i].window_rect.Offset(view_bounds.OffsetFromOrigin());
-
- plugin_window_moves_[moves[i].window] = moves[i];
-
- // constrained_rects_ are relative to the root window. We want to convert
- // them to be relative to the plugin window.
- for (size_t j = 0; j < constrained_rects_.size(); ++j) {
- gfx::Rect offset_cutout = constrained_rects_[j];
- offset_cutout -= moves[i].window_rect.OffsetFromOrigin();
- moves[i].cutout_rects.push_back(offset_cutout);
- }
- }
-
- MovePluginWindowsHelper(parent, moves);
-
- // Make sure each plugin window (or its wrapper if it exists) has a pointer to
- // |this|.
- for (size_t i = 0; i < moves.size(); ++i) {
- HWND window = moves[i].window;
- if (GetParent(window) != parent) {
- window = GetParent(window);
- }
- if (!GetProp(window, kWidgetOwnerProperty))
- SetProp(window, kWidgetOwnerProperty, this);
- }
-#endif // defined(OS_WIN)
-}
-
void RenderWidgetHostViewAura::Focus() {
// Make sure we have a FocusClient before attempting to Focus(). In some
// situations we may not yet be in a valid Window hierarchy (such as reloading
@@ -994,8 +849,8 @@ void RenderWidgetHostViewAura::SetInsets(const gfx::Insets& insets) {
void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) {
current_cursor_ = cursor;
- const gfx::Display display = gfx::Screen::GetScreenFor(window_)->
- GetDisplayNearestWindow(window_);
+ const gfx::Display display =
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_);
current_cursor_.SetDisplayInfo(display);
UpdateCursorIfOverSelf();
}
@@ -1170,34 +1025,10 @@ bool RenderWidgetHostViewAura::UsesNativeWindowFrame() const {
return (legacy_render_widget_host_HWND_ != NULL);
}
-void RenderWidgetHostViewAura::UpdateConstrainedWindowRects(
- const std::vector<gfx::Rect>& rects) {
- // Check this before setting constrained_rects_, so that next time they're set
- // and we have a root window we don't early return.
- if (!window_->GetHost())
- return;
-
- if (rects == constrained_rects_)
- return;
-
- constrained_rects_ = rects;
-
- HWND parent = window_->GetHost()->GetAcceleratedWidget();
- CutoutRectsParams params;
- params.widget = this;
- params.cutout_rects = constrained_rects_;
- params.geometry = &plugin_window_moves_;
- LPARAM lparam = reinterpret_cast<LPARAM>(&params);
- EnumChildWindows(parent, SetCutoutRectsCallback, lparam);
-}
-
void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
- // Clip the cursor if chrome is running on regular desktop.
- if (gfx::Screen::GetScreenFor(window_) == gfx::Screen::GetNativeScreen()) {
- RECT window_rect =
- gfx::win::DIPToScreenRect(window_->GetBoundsInScreen()).ToRECT();
- ::ClipCursor(&window_rect);
- }
+ RECT window_rect =
+ gfx::win::DIPToScreenRect(window_->GetBoundsInScreen()).ToRECT();
+ ::ClipCursor(&window_rect);
}
void RenderWidgetHostViewAura::OnLegacyWindowDestroyed() {
@@ -1216,6 +1047,13 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
return;
cc::ViewportSelection selection = frame->metadata.selection;
+ if (IsUseZoomForDSFEnabled()) {
+ float viewportToDIPScale = 1.0f / current_device_scale_factor_;
+ selection.start.edge_top.Scale(viewportToDIPScale);
+ selection.start.edge_bottom.Scale(viewportToDIPScale);
+ selection.end.edge_top.Scale(viewportToDIPScale);
+ selection.end.edge_bottom.Scale(viewportToDIPScale);
+ }
delegated_frame_host_->SwapDelegatedFrame(output_surface_id,
std::move(frame));
@@ -1232,21 +1070,6 @@ void RenderWidgetHostViewAura::DidStopFlinging() {
selection_controller_client_->OnScrollCompleted();
}
-#if defined(OS_WIN)
-void RenderWidgetHostViewAura::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {
-}
-
-gfx::NativeViewId RenderWidgetHostViewAura::GetParentForWindowlessPlugin()
- const {
- if (legacy_render_widget_host_HWND_) {
- return reinterpret_cast<gfx::NativeViewId>(
- legacy_render_widget_host_HWND_->hwnd());
- }
- return NULL;
-}
-#endif
-
bool RenderWidgetHostViewAura::HasAcceleratedSurface(
const gfx::Size& desired_size) {
// Aura doesn't use GetBackingStore for accelerated pages, so it doesn't
@@ -1408,12 +1231,12 @@ InputEventAckState RenderWidgetHostViewAura::FilterInputEvent(
BrowserAccessibilityManager*
RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) {
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
BrowserAccessibilityManager* manager = NULL;
#if defined(OS_WIN)
manager = new BrowserAccessibilityManagerWin(
BrowserAccessibilityManagerWin::GetEmptyDocument(), delegate);
-#elif !defined(OS_ANDROID)
+#else
manager = BrowserAccessibilityManager::Create(
BrowserAccessibilityManager::GetEmptyDocument(), delegate);
#endif
@@ -1604,6 +1427,7 @@ void RenderWidgetHostViewAura::UnlockMouse() {
// RenderWidgetHostViewAura, ui::TextInputClient implementation:
void RenderWidgetHostViewAura::SetCompositionText(
const ui::CompositionText& composition) {
+ // TODO(wjmaclean): can host_ ever be null?
if (!host_)
return;
@@ -1625,6 +1449,7 @@ void RenderWidgetHostViewAura::SetCompositionText(
// TODO(suzhe): due to a bug of webkit, we can't use selection range with
// composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
host_->ImeSetComposition(composition.text, underlines,
+ gfx::Range::InvalidRange(),
composition.selection.end(),
composition.selection.end());
@@ -1632,6 +1457,7 @@ void RenderWidgetHostViewAura::SetCompositionText(
}
void RenderWidgetHostViewAura::ConfirmCompositionText() {
+ // TODO(wjmaclean): can host_ ever be null?
if (host_ && has_composition_text_) {
host_->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(),
false);
@@ -1640,6 +1466,7 @@ void RenderWidgetHostViewAura::ConfirmCompositionText() {
}
void RenderWidgetHostViewAura::ClearCompositionText() {
+ // TODO(wjmaclean): can host_ ever be null?
if (host_ && has_composition_text_)
host_->ImeCancelComposition();
has_composition_text_ = false;
@@ -1647,6 +1474,7 @@ void RenderWidgetHostViewAura::ClearCompositionText() {
void RenderWidgetHostViewAura::InsertText(const base::string16& text) {
DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE);
+ // TODO(wjmaclean): can host_ ever be null?
if (host_)
host_->ImeConfirmComposition(text, gfx::Range::InvalidRange(), false);
has_composition_text_ = false;
@@ -1659,6 +1487,7 @@ void RenderWidgetHostViewAura::InsertChar(const ui::KeyEvent& event) {
}
// Ignore character messages for VKEY_RETURN sent on CTRL+M. crbug.com/315547
+ // TODO(wjmaclean): can host_ ever be null?
if (host_ &&
(accept_return_character_ || event.GetCharacter() != ui::VKEY_RETURN)) {
// Send a blink::WebInputEvent::Char event to |host_|.
@@ -1794,6 +1623,7 @@ bool RenderWidgetHostViewAura::GetTextFromRange(
}
void RenderWidgetHostViewAura::OnInputMethodChanged() {
+ // TODO(wjmaclean): can host_ ever be null?
if (!host_)
return;
@@ -1803,6 +1633,7 @@ void RenderWidgetHostViewAura::OnInputMethodChanged() {
bool RenderWidgetHostViewAura::ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) {
+ // TODO(wjmaclean): can host_ ever be null?
if (!host_)
return false;
host_->UpdateTextDirection(
@@ -1852,7 +1683,7 @@ void RenderWidgetHostViewAura::OnDisplayRemoved(
void RenderWidgetHostViewAura::OnDisplayMetricsChanged(
const gfx::Display& display, uint32_t metrics) {
// The screen info should be updated regardless of the metric change.
- gfx::Screen* screen = gfx::Screen::GetScreenFor(window_);
+ gfx::Screen* screen = gfx::Screen::GetScreen();
if (display.id() == screen->GetDisplayNearestWindow(window_).id()) {
UpdateScreenInfo(window_);
current_cursor_.SetDisplayInfo(display);
@@ -1916,13 +1747,14 @@ void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context) {
void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
float device_scale_factor) {
+ // TODO(wjmaclean): can host_ ever be null?
if (!host_ || !window_->GetRootWindow())
return;
UpdateScreenInfo(window_);
device_scale_factor_ = device_scale_factor;
- const gfx::Display display = gfx::Screen::GetScreenFor(window_)->
+ const gfx::Display display = gfx::Screen::GetScreen()->
GetDisplayNearestWindow(window_);
DCHECK_EQ(device_scale_factor, display.device_scale_factor());
current_cursor_.SetDisplayInfo(display);
@@ -1931,17 +1763,6 @@ void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
#if defined(OS_WIN)
- HWND parent = NULL;
- // If the tab was hidden and it's closed, host_->is_hidden would have been
- // reset to false in RenderWidgetHostImpl::RendererExited.
- if (!window_->GetRootWindow() || host_->is_hidden()) {
- parent = ui::GetHiddenWindow();
- } else {
- parent = window_->GetHost()->GetAcceleratedWidget();
- }
- LPARAM lparam = reinterpret_cast<LPARAM>(this);
- EnumChildWindows(parent, WindowDestroyingCallback, lparam);
-
// The LegacyRenderWidgetHostHWND instance is destroyed when its window is
// destroyed. Normally we control when that happens via the Destroy call
// in the dtor. However there may be cases where the window is destroyed
@@ -2038,6 +1859,11 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnMouseEvent");
+ ForwardMouseEventToParent(event);
+ // TODO(mgiuca): Return if event->handled() returns true. This currently
+ // breaks drop-down lists which means something is incorrectly setting
+ // event->handled to true (http://crbug.com/577983).
+
if (mouse_locked_) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(window_->GetRootWindow());
@@ -2195,23 +2021,12 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
break;
}
- // Needed to propagate mouse event to |window_->parent()->delegate()|, but
- // note that it might be something other than a WebContentsViewAura instance.
- // TODO(pkotwicz): Find a better way of doing this.
- // In fullscreen mode which is typically used by flash, don't forward
- // the mouse events to the parent. The renderer and the plugin process
- // handle these events.
- if (!is_fullscreen_ && window_->parent() && window_->parent()->delegate() &&
- !(event->flags() & ui::EF_FROM_TOUCH)) {
- event->ConvertLocationToTarget(window_, window_->parent());
- window_->parent()->delegate()->OnMouseEvent(event);
- }
-
if (!IsXButtonUpEvent(event))
event->SetHandled();
}
uint32_t RenderWidgetHostViewAura::SurfaceIdNamespaceAtPoint(
+ cc::SurfaceHittestDelegate* delegate,
const gfx::Point& point,
gfx::Point* transformed_point) {
DCHECK(device_scale_factor_ != 0.0f);
@@ -2220,8 +2035,8 @@ uint32_t RenderWidgetHostViewAura::SurfaceIdNamespaceAtPoint(
// |point| from DIPs to pixels before hittesting.
gfx::Point point_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor_, point);
- cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(point_in_pixels,
- transformed_point);
+ cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(
+ delegate, point_in_pixels, transformed_point);
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
@@ -2248,12 +2063,24 @@ void RenderWidgetHostViewAura::ProcessTouchEvent(
host_->ForwardTouchEventWithLatencyInfo(event, latency);
}
+void RenderWidgetHostViewAura::ProcessGestureEvent(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) {
+ host_->ForwardGestureEventWithLatencyInfo(event, latency);
+}
+
void RenderWidgetHostViewAura::TransformPointToLocalCoordSpace(
const gfx::Point& point,
cc::SurfaceId original_surface,
gfx::Point* transformed_point) {
+ // Transformations use physical pixels rather than DIP, so conversion
+ // is necessary.
+ gfx::Point point_in_pixels =
+ gfx::ConvertPointToPixel(device_scale_factor_, point);
delegated_frame_host_->TransformPointToLocalCoordSpace(
- point, original_surface, transformed_point);
+ point_in_pixels, original_surface, transformed_point);
+ *transformed_point =
+ gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
}
void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
@@ -2356,11 +2183,21 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
blink::WebGestureEvent fling_cancel = gesture;
fling_cancel.type = blink::WebInputEvent::GestureFlingCancel;
fling_cancel.sourceDevice = blink::WebGestureDeviceTouchscreen;
- host_->ForwardGestureEvent(fling_cancel);
+ if (ShouldRouteEvent(event)) {
+ host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
+ this, &fling_cancel, ui::LatencyInfo());
+ } else {
+ host_->ForwardGestureEvent(fling_cancel);
+ }
}
if (gesture.type != blink::WebInputEvent::Undefined) {
- host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency());
+ if (ShouldRouteEvent(event)) {
+ host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
+ this, &gesture, *event->latency());
+ } else {
+ host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency());
+ }
if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
@@ -2447,7 +2284,7 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
// If we lose the focus while fullscreen, close the window; Pepper Flash
// won't do it for us (unlike NPAPI Flash). However, we do not close the
// window if we lose the focus to a window on another display.
- gfx::Screen* screen = gfx::Screen::GetScreenFor(window_);
+ gfx::Screen* screen = gfx::Screen::GetScreen();
bool focusing_other_display =
gained_focus && screen->GetNumDisplays() > 1 &&
(screen->GetDisplayNearestWindow(window_).id() !=
@@ -2498,11 +2335,6 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
selection_controller_.reset();
selection_controller_client_.reset();
- if (UseSurfacesEnabled() && host_->delegate() &&
- host_->delegate()->GetInputEventRouter()) {
- host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
- GetSurfaceIdNamespace());
- }
delegated_frame_host_.reset();
window_observer_.reset();
if (window_) {
@@ -2510,7 +2342,7 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
window_->GetHost()->RemoveObserver(this);
UnlockMouse();
aura::client::SetTooltipText(window_, NULL);
- gfx::Screen::GetScreenFor(window_)->RemoveObserver(this);
+ gfx::Screen::GetScreen()->RemoveObserver(this);
// This call is usually no-op since |this| object is already removed from
// the Aura root window and we don't have a way to get an input method
@@ -2546,7 +2378,7 @@ void RenderWidgetHostViewAura::CreateAuraWindow() {
aura::client::SetActivationDelegate(window_, this);
aura::client::SetFocusChangeObserver(window_, this);
window_->set_layer_owner_delegate(delegated_frame_host_.get());
- gfx::Screen::GetScreenFor(window_)->AddObserver(this);
+ gfx::Screen::GetScreen()->AddObserver(this);
}
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
@@ -2557,7 +2389,7 @@ void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
if (!root_window)
return;
- gfx::Screen* screen = gfx::Screen::GetScreenFor(GetNativeView());
+ gfx::Screen* screen = gfx::Screen::GetScreen();
DCHECK(screen);
gfx::Point cursor_screen_point = screen->GetCursorScreenPoint();
@@ -2577,8 +2409,8 @@ void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
if (hwnd_at_point == legacy_render_widget_host_HWND_->hwnd())
hwnd_at_point = legacy_render_widget_host_HWND_->GetParent();
- gfx::ScreenWin* screen_win = static_cast<gfx::ScreenWin*>(screen);
- DCHECK(screen_win);
+ display::win::ScreenWin* screen_win =
+ static_cast<display::win::ScreenWin*>(screen);
window_at_screen_point = screen_win->GetNativeWindowFromHWND(
hwnd_at_point);
}
@@ -2640,6 +2472,7 @@ bool RenderWidgetHostViewAura::NeedsMouseCapture() {
void RenderWidgetHostViewAura::FinishImeCompositionSession() {
if (!has_composition_text_)
return;
+ // TODO(wjmaclean): can host_ ever be null?
if (host_) {
host_->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(),
false);
@@ -2705,31 +2538,32 @@ void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary() {
// to avoid the web contents area looking blurry we translate the web contents
// in the +x, +y direction to land on the nearest pixel boundary. This may
// cause the bottom and right edges to be clipped slightly, but that's ok.
- aura::Window* snapped = NULL;
- // On desktop, use the root window. On alternative environment (ash),
- // use the toplevel window which must be already snapped.
- if (gfx::Screen::GetScreenFor(window_) !=
- gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE)) {
- snapped = window_->GetRootWindow();
- } else {
- snapped = window_->GetToplevelWindow();
- }
+ aura::Window* snapped = window_->GetRootWindow();
if (snapped && snapped != window_)
ui::SnapLayerToPhysicalPixelBoundary(snapped->layer(), window_->layer());
has_snapped_to_boundary_ = true;
}
-void RenderWidgetHostViewAura::OnShowContextMenu() {
+bool RenderWidgetHostViewAura::OnShowContextMenu(
+ const ContextMenuParams& params) {
#if defined(OS_WIN)
- showing_context_menu_ = true;
+ last_context_menu_params_.reset();
+
+ if (params.source_type == ui::MENU_SOURCE_LONG_PRESS) {
+ last_context_menu_params_.reset(new ContextMenuParams);
+ *last_context_menu_params_ = params;
+ return false;
+ }
#endif
+ return true;
}
void RenderWidgetHostViewAura::SetSelectionControllerClientForTest(
scoped_ptr<TouchSelectionControllerClientAura> client) {
selection_controller_client_.swap(client);
CreateSelectionController();
+ disable_input_event_router_for_testing_ = true;
}
void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
@@ -2742,15 +2576,8 @@ void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
delegated_frame_host_->WasResized();
#if defined(OS_WIN)
// Create the legacy dummy window which corresponds to the bounds of the
- // webcontents. This will be passed as the container window for windowless
- // plugins.
- // Plugins like Flash assume the container window which is returned via the
- // NPNVnetscapeWindow property corresponds to the bounds of the webpage.
- // This is not true in Aura where we have only HWND which is the main Aura
- // window. If we return this window to plugins like Flash then it causes the
- // coordinate translations done by these plugins to break.
- // Additonally the legacy dummy window is needed for accessibility and for
- // scrolling to work in legacy drivers for trackpoints/trackpads, etc.
+ // webcontents. It is needed for accessibility and for scrolling to work in
+ // legacy drivers for trackpoints/trackpads, etc.
if (!legacy_window_destroyed_ && GetNativeViewId()) {
if (!legacy_render_widget_host_HWND_) {
legacy_render_widget_host_HWND_ = LegacyRenderWidgetHostHWND::Create(
@@ -2931,17 +2758,86 @@ void RenderWidgetHostViewAura::HandleGestureForTouchSelection(
}
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
- selection_controller_->OnScrollBeginEvent();
selection_controller_client_->OnScrollStarted();
break;
case ui::ET_GESTURE_SCROLL_END:
selection_controller_client_->OnScrollCompleted();
break;
+#if defined(OS_WIN)
+ case ui::ET_GESTURE_LONG_TAP: {
+ if (!last_context_menu_params_)
+ break;
+
+ scoped_ptr<ContextMenuParams> context_menu_params =
+ std::move(last_context_menu_params_);
+
+ // On Windows we want to display the context menu when the long press
+ // gesture is released. To achieve that, we switch the saved context
+ // menu params source type to MENU_SOURCE_TOUCH. This is to ensure that
+ // the RenderWidgetHostViewAura::OnShowContextMenu function which is
+ // called from the ShowContextMenu call below, does not treat it as
+ // a context menu request coming in from the long press gesture.
+ DCHECK(context_menu_params->source_type == ui::MENU_SOURCE_LONG_PRESS);
+ context_menu_params->source_type = ui::MENU_SOURCE_TOUCH;
+
+ RenderViewHostDelegateView* delegate_view =
+ GetRenderViewHostDelegateView();
+ if (delegate_view)
+ delegate_view->ShowContextMenu(GetFocusedFrame(),
+ *context_menu_params);
+
+ event->SetHandled();
+ // WARNING: we may have been deleted during the call to ShowContextMenu().
+ break;
+ }
+#endif
default:
break;
}
}
+void RenderWidgetHostViewAura::ForwardMouseEventToParent(
+ ui::MouseEvent* event) {
+ // Needed to propagate mouse event to |window_->parent()->delegate()|, but
+ // note that it might be something other than a WebContentsViewAura instance.
+ // TODO(pkotwicz): Find a better way of doing this.
+ // In fullscreen mode which is typically used by flash, don't forward
+ // the mouse events to the parent. The renderer and the plugin process
+ // handle these events.
+ if (is_fullscreen_)
+ return;
+
+ if (event->flags() & ui::EF_FROM_TOUCH)
+ return;
+
+ if (!window_->parent() || !window_->parent()->delegate())
+ return;
+
+ // Take a copy of |event|, to avoid ConvertLocationToTarget mutating the
+ // event.
+ scoped_ptr<ui::Event> event_copy = ui::Event::Clone(*event);
+ ui::MouseEvent* mouse_event = static_cast<ui::MouseEvent*>(event_copy.get());
+ mouse_event->ConvertLocationToTarget(window_, window_->parent());
+ window_->parent()->delegate()->OnMouseEvent(mouse_event);
+ if (mouse_event->handled())
+ event->SetHandled();
+}
+
+RenderViewHostDelegateView*
+RenderWidgetHostViewAura::GetRenderViewHostDelegateView() {
+ // Use RenderViewHostDelegate to get to the WebContentsViewAura, which will
+ // actually show the disambiguation popup.
+ RenderViewHost* rvh = RenderViewHost::From(host_);
+ if (!rvh)
+ return nullptr;
+
+ RenderViewHostDelegate* delegate = rvh->GetDelegate();
+ if (!delegate)
+ return nullptr;
+
+ return delegate->GetDelegateView();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, public:
@@ -3027,6 +2923,10 @@ uint32_t RenderWidgetHostViewAura::GetSurfaceIdNamespace() {
return delegated_frame_host_->GetSurfaceIdNamespace();
}
+cc::SurfaceId RenderWidgetHostViewAura::SurfaceIdForTesting() const {
+ return delegated_frame_host_->SurfaceIdForTesting();
+}
+
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewBase, public:
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.h b/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
index 9aecd40beb6..05de299c6dc 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -22,13 +22,14 @@
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
-#include "content/browser/compositor/delegated_frame_host.h"
#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/compositor/owned_mailbox.h"
#include "content/browser/renderer_host/begin_frame_observer_proxy.h"
+#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
#include "content/common/cursors/webcursor.h"
+#include "content/public/common/context_menu_params.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/client/cursor_client_observer.h"
#include "ui/aura/client/focus_change_observer.h"
@@ -82,6 +83,7 @@ class LegacyRenderWidgetHostHWND;
class OverscrollController;
class RenderFrameHostImpl;
+class RenderViewHostDelegateView;
class RenderWidgetHostImpl;
class RenderWidgetHostView;
class TouchSelectionControllerClientAura;
@@ -131,7 +133,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void Focus() override;
void UpdateCursor(const WebCursor& cursor) override;
void SetIsLoading(bool is_loading) override;
@@ -178,7 +179,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
InputEventAckState FilterInputEvent(
const blink::WebInputEvent& input_event) override;
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) override;
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) override;
gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override;
gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
@@ -193,22 +194,19 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void LockCompositingSurface() override;
void UnlockCompositingSurface() override;
uint32_t GetSurfaceIdNamespace() override;
- uint32_t SurfaceIdNamespaceAtPoint(const gfx::Point& point,
+ uint32_t SurfaceIdNamespaceAtPoint(cc::SurfaceHittestDelegate* delegate,
+ const gfx::Point& point,
gfx::Point* transformed_point) override;
void ProcessMouseEvent(const blink::WebMouseEvent& event) override;
void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void ProcessTouchEvent(const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) override;
+ void ProcessGestureEvent(const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) override;
void TransformPointToLocalCoordSpace(const gfx::Point& point,
cc::SurfaceId original_surface,
gfx::Point* transformed_point) override;
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) override;
- gfx::NativeViewId GetParentForWindowlessPlugin() const override;
-#endif
-
// Overridden from ui::TextInputClient:
void SetCompositionText(const ui::CompositionText& composition) override;
void ConfirmCompositionText() override;
@@ -286,11 +284,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
const gfx::Point& new_origin) override;
#if defined(OS_WIN)
- // Sets the cutout rects from constrained windows. These are rectangles that
- // windowed NPAPI plugins shouldn't paint in. Overwrites any previous cutout
- // rects.
- void UpdateConstrainedWindowRects(const std::vector<gfx::Rect>& rects);
-
// Updates the cursor clip region. Used for mouse locking.
void UpdateMouseLockRegion();
@@ -330,13 +323,20 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
}
// Called when the context menu is about to be displayed.
- void OnShowContextMenu();
+ // Returns true if the context menu should be displayed. We only return false
+ // on Windows if the context menu is being displayed in response to a long
+ // press gesture. On Windows we should be consistent like other apps and
+ // display the menu when the touch is released.
+ bool OnShowContextMenu(const ContextMenuParams& params);
// Used in tests to set a mock client for touch selection controller. It will
// create a new touch selection controller for the new client.
void SetSelectionControllerClientForTest(
scoped_ptr<TouchSelectionControllerClientAura> client);
+ // Exposed for tests.
+ cc::SurfaceId SurfaceIdForTesting() const override;
+
protected:
~RenderWidgetHostViewAura() override;
@@ -346,6 +346,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
DelegatedFrameHost* GetDelegatedFrameHost() const {
return delegated_frame_host_.get();
}
+
const ui::MotionEventAura& pointer_state() const { return pointer_state_; }
private:
@@ -490,7 +491,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Returns true if the |event| passed in can be forwarded to the renderer.
bool CanRendererHandleEvent(const ui::MouseEvent* event,
bool mouse_locked,
- bool selection_popup);
+ bool selection_popup) const;
// Returns true when we can do SurfaceHitTesting for the event type.
bool ShouldRouteEvent(const ui::Event* event) const;
@@ -515,6 +516,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// handled if it should not be further processed.
void HandleGestureForTouchSelection(ui::GestureEvent* event);
+ // Forwards a mouse event to this view's parent window delegate.
+ void ForwardMouseEventToParent(ui::MouseEvent* event);
+
+ // Returns the RenderViewHostDelegateView instance for this view. Returns
+ // NULL on failure.
+ RenderViewHostDelegateView* GetRenderViewHostDelegateView();
+
// The model object.
RenderWidgetHostImpl* const host_;
@@ -618,17 +626,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
CursorVisibilityState cursor_visibility_state_in_renderer_;
#if defined(OS_WIN)
- // The list of rectangles from constrained windows over this view. Windowed
- // NPAPI plugins shouldn't draw over them.
- std::vector<gfx::Rect> constrained_rects_;
-
- typedef std::map<HWND, WebPluginGeometry> PluginWindowMoves;
- // Contains information about each windowed plugin's clip and cutout rects (
- // from the renderer). This is needed because when the transient windows
- // over this view changes, we need this information in order to create a new
- // region for the HWND.
- PluginWindowMoves plugin_window_moves_;
-
// The LegacyRenderWidgetHostHWND class provides a dummy HWND which is used
// for accessibility, as the container for windowless plugins like
// Flash/Silverlight, etc and for legacy drivers for trackpoints/trackpads,
@@ -645,9 +642,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// exercise.
bool legacy_window_destroyed_;
- // Set to true when a context menu is being displayed. Reset to false when
- // a mouse leave is received in this context.
- bool showing_context_menu_;
+ // Contains a copy of the last context menu request parameters. Only set when
+ // we receive a request to show the context menu on a long press.
+ scoped_ptr<ContextMenuParams> last_context_menu_params_;
#endif
bool has_snapped_to_boundary_;
@@ -685,6 +682,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
float device_scale_factor_;
+ // Allows tests to send gesture events for testing without first sending a
+ // corresponding touch sequence, as would be required by
+ // RenderWidgetHostInputEventRouter.
+ bool disable_input_event_router_for_testing_;
+
base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 4eef57c2d54..da442867180 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -23,27 +23,35 @@
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/compositor/gl_helper.h"
#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/input/input_router.h"
+#include "content/browser/renderer_host/input/mouse_wheel_event_queue.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
+#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/browser/renderer_host/resize_lock.h"
+#include "content/browser/web_contents/web_contents_view_aura.h"
#include "content/common/host_shared_bitmap_manager.h"
+#include "content/common/input/input_event_utils.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
+#include "content/public/browser/web_contents_view_delegate.h"
+#include "content/public/common/context_menu_params.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
+#include "content/test/test_render_view_host.h"
+#include "content/test/test_web_contents.h"
#include "ipc/ipc_test_sink.h"
+#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
@@ -144,9 +152,11 @@ class TestOverscrollDelegate : public OverscrollControllerDelegate {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
- MockRenderWidgetHostDelegate() {}
+ MockRenderWidgetHostDelegate() : rwh_(nullptr) {}
~MockRenderWidgetHostDelegate() override {}
const NativeWebKeyboardEvent* last_event() const { return last_event_.get(); }
+ void set_widget_host(RenderWidgetHostImpl* rwh) { rwh_ = rwh; }
+
protected:
// RenderWidgetHostDelegate:
bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
@@ -158,9 +168,14 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
void Copy() override {}
void Paste() override {}
void SelectAll() override {}
+ void SendScreenRects() override {
+ if (rwh_)
+ rwh_->SendScreenRects();
+ }
private:
scoped_ptr<NativeWebKeyboardEvent> last_event_;
+ RenderWidgetHostImpl* rwh_;
DISALLOW_COPY_AND_ASSIGN(MockRenderWidgetHostDelegate);
};
@@ -262,7 +277,7 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
FakeRenderWidgetHostViewAura(RenderWidgetHost* widget,
bool is_guest_view_hack)
: RenderWidgetHostViewAura(widget, is_guest_view_hack),
- has_resize_lock_(false) {}
+ can_create_resize_lock_(true) {}
void UseFakeDispatcher() {
dispatcher_ = new FakeWindowEventDispatcher(window()->GetHost());
@@ -279,7 +294,9 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
new FakeResizeLock(desired_size, defer_compositor_lock));
}
- bool DelegatedFrameCanCreateResizeLock() const override { return true; }
+ bool DelegatedFrameCanCreateResizeLock() const override {
+ return can_create_resize_lock_;
+ }
void RunOnCompositingDidCommit() {
GetDelegatedFrameHost()->OnCompositingDidCommitForTesting(
@@ -299,16 +316,12 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
}
}
- cc::DelegatedFrameProvider* frame_provider() const {
- return GetDelegatedFrameHost()->FrameProviderForTesting();
- }
-
cc::SurfaceId surface_id() const {
return GetDelegatedFrameHost()->SurfaceIdForTesting();
}
bool HasFrameData() const {
- return frame_provider() || !surface_id().is_null();
+ return !surface_id().is_null();
}
bool released_front_lock_active() const {
@@ -327,7 +340,7 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
return pointer_state();
}
- bool has_resize_lock_;
+ bool can_create_resize_lock_;
gfx::Size last_frame_size_;
scoped_ptr<cc::CopyOutputRequest> last_copy_request_;
FakeWindowEventDispatcher* dispatcher_;
@@ -402,8 +415,10 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
sink_ = &process_host_->sink();
int32_t routing_id = process_host_->GetNextRoutingID();
- parent_host_ =
- new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false);
+ delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate));
+ parent_host_ = new RenderWidgetHostImpl(delegates_.back().get(),
+ process_host_, routing_id, false);
+ delegates_.back()->set_widget_host(parent_host_);
parent_view_ = new RenderWidgetHostViewAura(parent_host_,
is_guest_view_hack_);
parent_view_->InitAsChild(NULL);
@@ -412,8 +427,10 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
gfx::Rect());
routing_id = process_host_->GetNextRoutingID();
- widget_host_ =
- new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false);
+ delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate));
+ widget_host_ = new RenderWidgetHostImpl(delegates_.back().get(),
+ process_host_, routing_id, false);
+ delegates_.back()->set_widget_host(widget_host_);
widget_host_->Init();
view_ = new FakeRenderWidgetHostViewAura(widget_host_, is_guest_view_hack_);
}
@@ -502,8 +519,8 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
return;
}
- if (!WebInputEventTraits::WillReceiveAckFromRenderer(
- *base::get<0>(params)))
+ InputEventDispatchType dispatch_type = base::get<2>(params);
+ if (dispatch_type == InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING)
return;
const blink::WebInputEvent* event = base::get<0>(params);
@@ -525,7 +542,7 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
BrowserThreadImpl browser_thread_for_ui_;
scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
scoped_ptr<BrowserContext> browser_context_;
- MockRenderWidgetHostDelegate delegate_;
+ std::vector<scoped_ptr<MockRenderWidgetHostDelegate>> delegates_;
MockRenderProcessHost* process_host_;
// Tests should set these to NULL if they've already triggered their
@@ -588,12 +605,27 @@ class RenderWidgetHostViewAuraOverscrollTest
protected:
void SetUpOverscrollEnvironmentWithDebounce(int debounce_interval_in_ms) {
- SetUpOverscrollEnvironmentImpl(debounce_interval_in_ms);
+ SetUpOverscrollEnvironmentImpl(debounce_interval_in_ms, false);
+ }
+
+ void SetUpOverscrollEnvironmentWithWheelGestures() {
+ SetUpOverscrollEnvironmentImpl(0, true);
+ }
+
+ void SetUpOverscrollEnvironment() {
+ SetUpOverscrollEnvironmentImpl(0, false);
}
- void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); }
+ void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms,
+ bool enable_wheel_gestures) {
+ CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWheelGestures) &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableWheelGestures));
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ enable_wheel_gestures ? switches::kEnableWheelGestures
+ : switches::kDisableWheelGestures);
- void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) {
ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
debounce_interval_in_ms);
@@ -1078,9 +1110,10 @@ TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
EXPECT_EQ(underlines[i].background_color,
base::get<1>(params)[i].backgroundColor);
}
+ EXPECT_EQ(gfx::Range::InvalidRange(), base::get<2>(params));
// highlighted range
- EXPECT_EQ(4, base::get<2>(params)) << "Should be the same to the caret pos";
EXPECT_EQ(4, base::get<3>(params)) << "Should be the same to the caret pos";
+ EXPECT_EQ(4, base::get<4>(params)) << "Should be the same to the caret pos";
}
view_->ImeCancelComposition();
@@ -1655,6 +1688,54 @@ TEST_F(RenderWidgetHostViewAuraTest, RecreateLayers) {
}
}
+// If the view size is larger than the compositor frame then extra layers
+// should be created to fill the gap.
+TEST_F(RenderWidgetHostViewAuraTest, DelegatedFrameGutter) {
+ gfx::Size large_size(100, 100);
+ gfx::Size small_size(40, 45);
+ gfx::Size medium_size(40, 95);
+
+ // Prevent the DelegatedFrameHost from skipping frames.
+ view_->can_create_resize_lock_ = false;
+
+ view_->InitAsChild(NULL);
+ aura::client::ParentWindowWithContext(
+ view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
+ gfx::Rect());
+ view_->SetSize(large_size);
+ view_->Show();
+ scoped_ptr<cc::CompositorFrame> frame =
+ MakeDelegatedFrame(1.f, small_size, gfx::Rect(small_size));
+ frame->metadata.root_background_color = SK_ColorRED;
+ view_->OnSwapCompositorFrame(0, std::move(frame));
+
+ ui::Layer* parent_layer = view_->GetNativeView()->layer();
+
+ ASSERT_EQ(2u, parent_layer->children().size());
+ EXPECT_EQ(gfx::Rect(40, 0, 60, 100), parent_layer->children()[0]->bounds());
+ EXPECT_EQ(SK_ColorRED, parent_layer->children()[0]->background_color());
+ EXPECT_EQ(gfx::Rect(0, 45, 40, 55), parent_layer->children()[1]->bounds());
+ EXPECT_EQ(SK_ColorRED, parent_layer->children()[1]->background_color());
+
+ view_->SetSize(medium_size);
+
+ // Right gutter is unnecessary.
+ ASSERT_EQ(1u, parent_layer->children().size());
+ EXPECT_EQ(gfx::Rect(0, 45, 40, 50), parent_layer->children()[0]->bounds());
+
+ frame = MakeDelegatedFrame(1.f, medium_size, gfx::Rect(medium_size));
+ view_->OnSwapCompositorFrame(0, std::move(frame));
+ EXPECT_EQ(0u, parent_layer->children().size());
+
+ view_->SetSize(large_size);
+ ASSERT_EQ(2u, parent_layer->children().size());
+
+ // This should evict the frame and remove the gutter layers.
+ view_->Hide();
+ view_->SetSize(small_size);
+ ASSERT_EQ(0u, parent_layer->children().size());
+}
+
TEST_F(RenderWidgetHostViewAuraTest, Resize) {
gfx::Size size1(100, 100);
gfx::Size size2(200, 200);
@@ -1920,8 +2001,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
// Create a bunch of renderers.
for (size_t i = 0; i < renderer_count; ++i) {
int32_t routing_id = process_host_->GetNextRoutingID();
- hosts[i] =
- new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false);
+ delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate));
+ hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_,
+ routing_id, false);
+ delegates_.back()->set_widget_host(hosts[i]);
hosts[i]->Init();
views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
views[i]->InitAsChild(NULL);
@@ -2084,8 +2167,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
// Create a bunch of renderers.
for (size_t i = 0; i < renderer_count; ++i) {
int32_t routing_id = process_host_->GetNextRoutingID();
- hosts[i] =
- new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false);
+ delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate));
+ hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_,
+ routing_id, false);
+ delegates_.back()->set_widget_host(hosts[i]);
hosts[i]->Init();
views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
views[i]->InitAsChild(NULL);
@@ -2153,8 +2238,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithMemoryPressure) {
// Create a bunch of renderers.
for (size_t i = 0; i < renderer_count; ++i) {
int32_t routing_id = process_host_->GetNextRoutingID();
- hosts[i] =
- new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false);
+ delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate));
+ hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_,
+ routing_id, false);
+ delegates_.back()->set_widget_host(hosts[i]);
hosts[i]->Init();
views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
views[i]->InitAsChild(NULL);
@@ -2215,9 +2302,6 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
view_->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size)));
- // Save the frame provider.
- scoped_refptr<cc::DelegatedFrameProvider> frame_provider =
- view_->frame_provider();
cc::SurfaceId surface_id = view_->surface_id();
// This frame will have the same number of physical pixels, but has a new
@@ -2225,13 +2309,10 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
view_->OnSwapCompositorFrame(
1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size)));
- // When we get a new frame with the same frame size in physical pixels, but a
- // different scale, we should generate a new frame provider, as the final
- // result will need to be scaled differently to the screen.
- if (frame_provider.get())
- EXPECT_NE(frame_provider.get(), view_->frame_provider());
- else
- EXPECT_NE(surface_id, view_->surface_id());
+ // When we get a new frame with the same frame size in physical pixels, but
+ // a different scale, we should generate a surface, as the final result will
+ // need to be scaled differently to the screen.
+ EXPECT_NE(surface_id, view_->surface_id());
}
class RenderWidgetHostViewAuraCopyRequestTest
@@ -2578,6 +2659,70 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollEventOverscrolls) {
EXPECT_EQ(1U, sink_->message_count());
}
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_WheelScrollEventOverscrollsWithWheelGestures \
+ DISABLED_WheelScrollEventOverscrollsWithWheelGestures
+#else
+#define MAYBE_WheelScrollEventOverscrollsWithWheelGestures \
+ WheelScrollEventOverscrollsWithWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_WheelScrollEventOverscrollsWithWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Simulate wheel events.
+ SimulateWheelEvent(-5, 0, 0, true); // sent directly
+ SimulateWheelEvent(-1, 1, 0, true); // enqueued
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-20, 6, 1, true); // enqueued, different modifiers
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Receive ACK the first wheel event as not processed.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // ScrollBegin, ScrollUpdate, MouseWheel will be queued events
+ EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Receive ACK for the second (coalesced) event as not processed. This will
+ // start a back navigation. However, this will also cause the queued next
+ // event to be sent to the renderer. But since overscroll navigation has
+ // started, that event will also be included in the overscroll computation
+ // instead of being sent to the renderer. So the result will be an overscroll
+ // back navigation, and no event will be sent to the renderer.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ // ScrollUpdate, MouseWheel will be queued events
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(-81.f, overscroll_delta_x());
+ EXPECT_EQ(-31.f, overscroll_delegate()->delta_x());
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
+ EXPECT_EQ(0U, sink_->message_count());
+
+ // Send a mouse-move event. This should cancel the overscroll navigation.
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(1U, sink_->message_count());
+}
+
// Tests that if some scroll events are consumed towards the start, then
// subsequent scrolls do not horizontal overscroll.
TEST_F(RenderWidgetHostViewAuraOverscrollTest,
@@ -2642,6 +2787,65 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
}
+// Tests that if some scroll events are consumed towards the start, then
+// subsequent scrolls do not horizontal overscroll.
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures \
+ DISABLED_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures
+#else
+#define MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures \
+ WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Simulate wheel events.
+ SimulateWheelEvent(-5, 0, 0, true); // sent directly
+ SimulateWheelEvent(-1, -1, 0, true); // enqueued
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-20, 6, 1, true); // enqueued, different modifiers
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Receive ACK the first wheel event as processed.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ // ScrollBegin, ScrollUpdate, MouseWheel will be queued events
+ EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Receive ACK for the second (coalesced) event as not processed. This should
+ // not initiate overscroll, since the beginning of the scroll has been
+ // consumed. The queued event with different modifiers should be sent to the
+ // renderer.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ // ScrollUpdate, MouseWheel will be queued events
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ // ScrollUpdate will be queued events
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ EXPECT_EQ(0U, sink_->message_count());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+}
+
// Tests that wheel-scrolling correctly turns overscroll on and off.
TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollOverscrollToggle) {
SetUpOverscrollEnvironment();
@@ -2701,6 +2905,95 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollOverscrollToggle) {
EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
}
+// Tests that wheel-scrolling correctly turns overscroll on and off.
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_WheelScrollOverscrollToggleWithWheelGestures \
+ DISABLED_WheelScrollOverscrollToggleWithWheelGestures
+#else
+#define MAYBE_WheelScrollOverscrollToggleWithWheelGestures \
+ WheelScrollOverscrollToggleWithWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_WheelScrollOverscrollToggleWithWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Send a wheel event. ACK the event as not processed. This should not
+ // initiate an overscroll gesture since it doesn't cross the threshold yet.
+ SimulateWheelEvent(10, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Scroll some more so as to not overscroll.
+ SimulateWheelEvent(10, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Scroll some more to initiate an overscroll.
+ SimulateWheelEvent(40, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(60.f, overscroll_delta_x());
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x());
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
+
+ // Scroll in the reverse direction enough to abort the overscroll.
+ SimulateWheelEvent(-20, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, sink_->message_count());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Continue to scroll in the reverse direction.
+ SimulateWheelEvent(-20, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Continue to scroll in the reverse direction enough to initiate overscroll
+ // in that direction.
+ SimulateWheelEvent(-55, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(-75.f, overscroll_delta_x());
+ EXPECT_EQ(-25.f, overscroll_delegate()->delta_x());
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
+}
+
TEST_F(RenderWidgetHostViewAuraOverscrollTest,
ScrollEventsOverscrollWithFling) {
SetUpOverscrollEnvironment();
@@ -2744,6 +3037,68 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_EQ(2U, sink_->message_count());
}
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures \
+ DISABLED_ScrollEventsOverscrollWithFlingAndWheelGestures
+#else
+#define MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures \
+ ScrollEventsOverscrollWithFlingAndWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Send a wheel event. ACK the event as not processed. This should not
+ // initiate an overscroll gesture since it doesn't cross the threshold yet.
+ SimulateWheelEvent(10, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+
+ // Scroll some more so as to not overscroll.
+ SimulateWheelEvent(20, 0, 0, true);
+ EXPECT_EQ(1U, sink_->message_count());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ sink_->ClearMessages();
+
+ // Scroll some more to initiate an overscroll.
+ SimulateWheelEvent(30, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(60.f, overscroll_delta_x());
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x());
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+
+ // Send a fling start, but with a small velocity, so that the overscroll is
+ // aborted. The fling should proceed to the renderer, through the gesture
+ // event filter.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(3U, sink_->message_count());
+}
+
// Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that
// the zero-velocity fling does not reach the renderer.
TEST_F(RenderWidgetHostViewAuraOverscrollTest,
@@ -2788,6 +3143,70 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_EQ(2U, sink_->message_count());
}
+// Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that
+// the zero-velocity fling does not reach the renderer.
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures \
+ DISABLED_ScrollEventsOverscrollWithZeroFlingAndWheelGestures
+#else
+#define MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures \
+ ScrollEventsOverscrollWithZeroFlingAndWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Send a wheel event. ACK the event as not processed. This should not
+ // initiate an overscroll gesture since it doesn't cross the threshold yet.
+ SimulateWheelEvent(10, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+
+ // Scroll some more so as to not overscroll.
+ SimulateWheelEvent(20, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Scroll some more to initiate an overscroll.
+ SimulateWheelEvent(30, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(60.f, overscroll_delta_x());
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x());
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y());
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+
+ // Send a fling start, but with a small velocity, so that the overscroll is
+ // aborted. The fling should proceed to the renderer, through the gesture
+ // event filter.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureFlingStartEvent(10.f, 0.f, blink::WebGestureDeviceTouchpad);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(3U, sink_->message_count());
+}
+
// Tests that a fling in the opposite direction of the overscroll cancels the
// overscroll nav instead of completing it.
TEST_F(RenderWidgetHostViewAuraOverscrollTest, ReverseFlingCancelsOverscroll) {
@@ -3260,6 +3679,61 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
}
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures \
+ DISABLED_OverscrollDirectionChangeMouseWheelWithWheelGestures
+#else
+#define MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures \
+ OverscrollDirectionChangeMouseWheelWithWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ // Send wheel event and receive ack as not consumed.
+ SimulateWheelEvent(125, -5, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // ScrollBegin, ScrollUpdate messages.
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+
+ // Send another wheel event, but in the reverse direction. The overscroll
+ // controller will not consume the event, because it is not triggering
+ // gesture-nav.
+
+ SimulateWheelEvent(-260, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Since it was unhandled; the overscroll should now be west
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+
+ SimulateWheelEvent(-20, 0, 0, true);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // wheel event ack generates gesture scroll update; which gets consumed
+ // solely by the overflow controller.
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+}
+
// Tests that if a mouse-move event completes the overscroll gesture, future
// move events do reach the renderer.
TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) {
@@ -3340,6 +3814,101 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) {
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
}
+// Tests that if a mouse-move event completes the overscroll gesture, future
+// move events do reach the renderer.
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_OverscrollMouseMoveCompletionWheelGestures \
+ DISABLED_OverscrollMouseMoveCompletionWheelGestures
+#else
+#define MAYBE_OverscrollMouseMoveCompletionWheelGestures \
+ OverscrollMouseMoveCompletionWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_OverscrollMouseMoveCompletionWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+
+ SimulateWheelEvent(5, 0, 0, true); // sent directly
+ SimulateWheelEvent(-1, 0, 0, true); // enqueued
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Receive ACK the first wheel event as not processed.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+
+ // Receive ACK for the second (coalesced) event as not processed. This will
+ // start an overcroll gesture.
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(0U, sink_->message_count());
+
+ // Send a mouse-move event. This should cancel the overscroll navigation
+ // (since the amount overscrolled is not above the threshold), and so the
+ // mouse-move should reach the renderer.
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ SendInputEventACK(WebInputEvent::MouseMove,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Moving the mouse more should continue to send the events to the renderer.
+ SimulateMouseMove(5, 10, 0);
+ SendInputEventACK(WebInputEvent::MouseMove,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Now try with gestures.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureScrollUpdateEvent(300, -5, 0);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+ sink_->ClearMessages();
+
+ // Overscroll gesture is in progress. Send a mouse-move now. This should
+ // complete the gesture (because the amount overscrolled is above the
+ // threshold).
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ SendInputEventACK(WebInputEvent::MouseMove,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd,
+ blink::WebGestureDeviceTouchscreen);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode());
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ // Move mouse some more. The mouse-move events should reach the renderer.
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+
+ SendInputEventACK(WebInputEvent::MouseMove,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+}
+
// Tests that if a page scrolled, then the overscroll controller's states are
// reset after the end of the scroll.
TEST_F(RenderWidgetHostViewAuraOverscrollTest,
@@ -3374,11 +3943,14 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
// consumed and have triggered a fling animation (as tracked by the router).
EXPECT_FALSE(parent_host_->input_router()->HasPendingEvents());
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd,
+ blink::WebGestureDeviceTouchscreen);
+
SimulateWheelEvent(-5, 0, 0, true); // sent directly
SimulateWheelEvent(-60, 0, 0, true); // enqueued
SimulateWheelEvent(-100, 0, 0, true); // coalesced into previous event
EXPECT_TRUE(ScrollStateIsUnknown());
- EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
// The first wheel scroll did not scroll content. Overscroll should not start
// yet, since enough hasn't been scrolled.
@@ -3496,7 +4068,7 @@ TEST_F(RenderWidgetHostViewAuraTest, KeyEvent) {
ui::EF_NONE);
view_->OnKeyEvent(&key_event);
- const NativeWebKeyboardEvent* event = delegate_.last_event();
+ const NativeWebKeyboardEvent* event = delegates_.back()->last_event();
EXPECT_NE(nullptr, event);
if (event) {
EXPECT_EQ(key_event.key_code(), event->windowsKeyCode);
@@ -3627,6 +4199,112 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) {
EXPECT_EQ(0.f, overscroll_delta_y());
}
+// Tests that the scroll deltas stored within the overscroll controller get
+// reset at the end of the overscroll gesture even if the overscroll threshold
+// isn't surpassed and the overscroll mode stays OVERSCROLL_NONE.
+// Disabled on MacOS because it doesn't support wheel gestures
+// just yet.
+#if defined(OS_MACOSX)
+#define MAYBE_ScrollDeltasResetOnEndWithWheelGestures \
+ DISABLED_ScrollDeltasResetOnEndWithWheelGestures
+#else
+#define MAYBE_ScrollDeltasResetOnEndWithWheelGestures \
+ ScrollDeltasResetOnEndWithWheelGestures
+#endif
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ MAYBE_ScrollDeltasResetOnEndWithWheelGestures) {
+ SetUpOverscrollEnvironmentWithWheelGestures();
+ // Wheel event scroll ending with mouse move.
+ SimulateWheelEvent(-30, -10, 0, true); // sent directly
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(-30.f, overscroll_delta_x());
+ EXPECT_EQ(-10.f, overscroll_delta_y());
+ SimulateMouseMove(5, 10, 0);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+
+ // Scroll gesture.
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureScrollUpdateEvent(-30, -5, 0);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(-30.f, overscroll_delta_x());
+ EXPECT_EQ(-5.f, overscroll_delta_y());
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd,
+ blink::WebGestureDeviceTouchscreen);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+
+ // Wheel event scroll ending with a fling.
+ SimulateWheelEvent(5, 0, 0, true);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SimulateWheelEvent(10, -5, 0, true);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(15.f, overscroll_delta_x());
+ EXPECT_EQ(-5.f, overscroll_delta_y());
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+ blink::WebGestureDeviceTouchscreen);
+ SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad);
+ EXPECT_EQ(0.f, overscroll_delta_x());
+ EXPECT_EQ(0.f, overscroll_delta_y());
+}
+
+TEST_F(RenderWidgetHostViewAuraTest, ForwardMouseEvent) {
+ aura::Window* root = parent_view_->GetNativeView()->GetRootWindow();
+
+ // Set up test delegate and window hierarchy.
+ aura::test::EventCountDelegate delegate;
+ scoped_ptr<aura::Window> parent(new aura::Window(&delegate));
+ parent->Init(ui::LAYER_TEXTURED);
+ root->AddChild(parent.get());
+ view_->InitAsChild(parent.get());
+
+ // Simulate mouse events, ensure they are forwarded to delegate.
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ 0);
+ view_->OnMouseEvent(&mouse_event);
+ EXPECT_EQ("1 0", delegate.GetMouseButtonCountsAndReset());
+
+ // Simulate mouse events, ensure they are forwarded to delegate.
+ mouse_event = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), 0, 0);
+ view_->OnMouseEvent(&mouse_event);
+ EXPECT_EQ("0 1 0", delegate.GetMouseMotionCountsAndReset());
+
+ // Lock the mouse, simulate, and ensure they are forwarded.
+ view_->LockMouse();
+
+ mouse_event =
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
+ view_->OnMouseEvent(&mouse_event);
+ EXPECT_EQ("1 0", delegate.GetMouseButtonCountsAndReset());
+
+ mouse_event = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), 0, 0);
+ view_->OnMouseEvent(&mouse_event);
+ EXPECT_EQ("0 1 0", delegate.GetMouseMotionCountsAndReset());
+
+ view_->UnlockMouse();
+
+ // view_ will be destroyed when parent is destroyed.
+ view_ = nullptr;
+}
+
// Tests the RenderWidgetHostImpl sends the correct surface ID namespace to
// the renderer process.
TEST_F(RenderWidgetHostViewAuraTest, SurfaceIdNamespaceInitialized) {
@@ -3645,4 +4323,159 @@ TEST_F(RenderWidgetHostViewAuraTest, SurfaceIdNamespaceInitialized) {
EXPECT_EQ(view_->GetSurfaceIdNamespace(), base::get<0>(params));
}
+// This class provides functionality to test a RenderWidgetHostViewAura
+// instance which has been hooked up to a test RenderViewHost instance and
+// a WebContents instance.
+class RenderWidgetHostViewAuraWithViewHarnessTest
+ : public RenderViewHostImplTestHarness {
+ public:
+ RenderWidgetHostViewAuraWithViewHarnessTest()
+ : view_(nullptr) {}
+ ~RenderWidgetHostViewAuraWithViewHarnessTest() override {}
+
+ protected:
+ void SetUp() override {
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
+ RenderViewHostImplTestHarness::SetUp();
+ // Delete the current RenderWidgetHostView instance before setting
+ // the RWHVA as the view.
+ delete contents()->GetRenderViewHost()->GetWidget()->GetView();
+ // This instance is destroyed in the TearDown method below.
+ view_ = new RenderWidgetHostViewAura(
+ contents()->GetRenderViewHost()->GetWidget(),
+ false);
+ }
+
+ void TearDown() override {
+ view_->Destroy();
+ RenderViewHostImplTestHarness::TearDown();
+ ImageTransportFactory::Terminate();
+ }
+
+ RenderWidgetHostViewAura* view() {
+ return view_;
+ }
+
+ private:
+ RenderWidgetHostViewAura* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraWithViewHarnessTest);
+};
+
+// Provides a mock implementation of the WebContentsViewDelegate class.
+// Currently provides functionality to validate the ShowContextMenu
+// callback.
+class MockWebContentsViewDelegate : public WebContentsViewDelegate {
+ public:
+ MockWebContentsViewDelegate()
+ : context_menu_request_received_(false) {}
+
+ ~MockWebContentsViewDelegate() override {}
+
+ bool context_menu_request_received() const {
+ return context_menu_request_received_;
+ }
+
+ ui::MenuSourceType context_menu_source_type() const {
+ return context_menu_params_.source_type;
+ }
+
+ // WebContentsViewDelegate overrides.
+ void ShowContextMenu(RenderFrameHost* render_frame_host,
+ const ContextMenuParams& params) override {
+ context_menu_request_received_ = true;
+ context_menu_params_ = params;
+ }
+
+ void ClearState() {
+ context_menu_request_received_ = false;
+ context_menu_params_.source_type = ui::MENU_SOURCE_NONE;
+ }
+
+ private:
+ bool context_menu_request_received_;
+ ContextMenuParams context_menu_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockWebContentsViewDelegate);
+};
+
+// On Windows we don't want the context menu to be displayed in the context of
+// a long press gesture. It should be displayed when the touch is released.
+// On other platforms we should display the context menu in the long press
+// gesture.
+// This test validates this behavior.
+TEST_F(RenderWidgetHostViewAuraWithViewHarnessTest,
+ ContextMenuTest) {
+ // This instance will be destroyed when the WebContents instance is
+ // destroyed.
+ MockWebContentsViewDelegate* delegate = new MockWebContentsViewDelegate;
+ static_cast<WebContentsViewAura*>(
+ contents()->GetView())->SetDelegateForTesting(delegate);
+
+ RenderViewHostFactory::set_is_real_render_view_host(true);
+
+ // A context menu request with the MENU_SOURCE_MOUSE source type should
+ // result in the MockWebContentsViewDelegate::ShowContextMenu method
+ // getting called. This means that the request worked correctly.
+ ContextMenuParams context_menu_params;
+ context_menu_params.source_type = ui::MENU_SOURCE_MOUSE;
+ contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(),
+ context_menu_params);
+ EXPECT_TRUE(delegate->context_menu_request_received());
+ EXPECT_EQ(delegate->context_menu_source_type(), ui::MENU_SOURCE_MOUSE);
+
+ // A context menu request with the MENU_SOURCE_TOUCH source type should
+ // result in the MockWebContentsViewDelegate::ShowContextMenu method
+ // getting called on all platforms. This means that the request worked
+ // correctly.
+ delegate->ClearState();
+ context_menu_params.source_type = ui::MENU_SOURCE_TOUCH;
+ contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(),
+ context_menu_params);
+ EXPECT_TRUE(delegate->context_menu_request_received());
+
+ // A context menu request with the MENU_SOURCE_LONG_TAP source type should
+ // result in the MockWebContentsViewDelegate::ShowContextMenu method
+ // getting called on all platforms. This means that the request worked
+ // correctly.
+ delegate->ClearState();
+ context_menu_params.source_type = ui::MENU_SOURCE_LONG_TAP;
+ contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(),
+ context_menu_params);
+ EXPECT_TRUE(delegate->context_menu_request_received());
+
+ // A context menu request with the MENU_SOURCE_LONG_PRESS source type should
+ // result in the MockWebContentsViewDelegate::ShowContextMenu method
+ // getting called on non Windows platforms. This means that the request
+ // worked correctly. On Windows this should be blocked.
+ delegate->ClearState();
+ context_menu_params.source_type = ui::MENU_SOURCE_LONG_PRESS;
+ contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(),
+ context_menu_params);
+#if defined(OS_WIN)
+ EXPECT_FALSE(delegate->context_menu_request_received());
+#else
+ EXPECT_TRUE(delegate->context_menu_request_received());
+#endif
+
+#if defined(OS_WIN)
+ // On Windows the context menu request blocked above should be received when
+ // the ET_GESTURE_LONG_TAP gesture is sent to the RenderWidgetHostViewAura
+ // instance. This means that the touch was released.
+ delegate->ClearState();
+
+ ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_TAP);
+ ui::GestureEvent gesture_event(
+ 100, 100, 0, ui::EventTimeForNow(), event_details);
+ view()->OnGestureEvent(&gesture_event);
+
+ EXPECT_TRUE(delegate->context_menu_request_received());
+ EXPECT_EQ(delegate->context_menu_source_type(), ui::MENU_SOURCE_TOUCH);
+#endif
+
+ RenderViewHostFactory::set_is_real_render_view_host(false);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
index a2a0884d005..d7e3d00af10 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -10,354 +10,19 @@
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
#include "content/common/content_switches_internal.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/screen.h"
-#if defined(OS_WIN)
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/win/wrapped_window_proc.h"
-#include "content/browser/plugin_process_host.h"
-#include "content/browser/plugin_service_impl.h"
-#include "content/common/plugin_constants_win.h"
-#include "content/common/webplugin_geometry.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/common/content_switches.h"
-#include "ui/gfx/gdi_util.h"
-#include "ui/gfx/win/dpi.h"
-#include "ui/gfx/win/hwnd_util.h"
-#endif
-
namespace content {
-#if defined(OS_WIN)
-
-namespace {
-
-// |window| is the plugin HWND, created and destroyed in the plugin process.
-// |parent| is the parent HWND, created and destroyed on the browser UI thread.
-void NotifyPluginProcessHostHelper(HWND window, HWND parent, int tries) {
- // How long to wait between each try.
- static const int kTryDelayMs = 200;
-
- DWORD plugin_process_id;
- bool found_starting_plugin_process = false;
- GetWindowThreadProcessId(window, &plugin_process_id);
- for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
- if (!iter.GetData().handle) {
- found_starting_plugin_process = true;
- continue;
- }
- if (base::GetProcId(iter.GetData().handle) == plugin_process_id) {
- iter->AddWindow(parent);
- return;
- }
- }
-
- if (found_starting_plugin_process) {
- // A plugin process has started but we don't have its handle yet. Since
- // it's most likely the one for this plugin, try a few more times after a
- // delay.
- if (tries > 0) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&NotifyPluginProcessHostHelper, window, parent, tries - 1),
- base::TimeDelta::FromMilliseconds(kTryDelayMs));
- return;
- }
- }
-
- // The plugin process might have died in the time to execute the task, don't
- // leak the HWND.
- PostMessage(parent, WM_CLOSE, 0, 0);
-}
-
-// The plugin wrapper window which lives in the browser process has this proc
-// as its window procedure. We only handle the WM_PARENTNOTIFY message sent by
-// windowed plugins for mouse input. This is forwarded off to the wrappers
-// parent which is typically the RVH window which turns on user gesture.
-LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message,
- WPARAM wparam, LPARAM lparam) {
- if (message == WM_PARENTNOTIFY) {
- switch (LOWORD(wparam)) {
- case WM_LBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_MBUTTONDOWN:
- ::SendMessage(GetParent(window), message, wparam, lparam);
- return 0;
- default:
- break;
- }
- }
- return ::DefWindowProc(window, message, wparam, lparam);
-}
-
-bool IsPluginWrapperWindow(HWND window) {
- return gfx::GetClassNameW(window) ==
- base::string16(kWrapperNativeWindowClassName);
-}
-
-// Create an intermediate window between the given HWND and its parent.
-HWND ReparentWindow(HWND window, HWND parent) {
- static ATOM atom = 0;
- static HMODULE instance = NULL;
- if (!atom) {
- WNDCLASSEX window_class;
- base::win::InitializeWindowClass(
- kWrapperNativeWindowClassName,
- &base::win::WrappedWindowProc<PluginWrapperWindowProc>,
- CS_DBLCLKS,
- 0,
- 0,
- NULL,
- // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
- reinterpret_cast<HBRUSH>(COLOR_GRAYTEXT+1),
- NULL,
- NULL,
- NULL,
- &window_class);
- instance = window_class.hInstance;
- atom = RegisterClassEx(&window_class);
- }
- DCHECK(atom);
-
- HWND new_parent = CreateWindowEx(
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
- MAKEINTATOM(atom), 0,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
- 0, 0, 0, 0, parent, 0, instance, 0);
- gfx::CheckWindowCreated(new_parent);
- ::SetParent(window, new_parent);
- // How many times we try to find a PluginProcessHost whose process matches
- // the HWND.
- static const int kMaxTries = 5;
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&NotifyPluginProcessHostHelper, window, new_parent,
- kMaxTries));
- return new_parent;
-}
-
-BOOL CALLBACK PaintEnumChildProc(HWND hwnd, LPARAM lparam) {
- if (!PluginServiceImpl::GetInstance()->IsPluginWindow(hwnd))
- return TRUE;
-
- gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
- gfx::Rect rect_in_pixels = gfx::win::DIPToScreenRect(*rect);
- static UINT msg = RegisterWindowMessage(kPaintMessageName);
- WPARAM wparam = MAKEWPARAM(rect_in_pixels.x(), rect_in_pixels.y());
- lparam = MAKELPARAM(rect_in_pixels.width(), rect_in_pixels.height());
-
- // SendMessage gets the message across much quicker than PostMessage, since it
- // doesn't get queued. When the plugin thread calls PeekMessage or other
- // Win32 APIs, sent messages are dispatched automatically.
- SendNotifyMessage(hwnd, msg, wparam, lparam);
-
- return TRUE;
-}
-
-// Windows callback for OnDestroy to detach the plugin windows.
-BOOL CALLBACK DetachPluginWindowsCallbackInternal(HWND window, LPARAM param) {
- RenderWidgetHostViewBase::DetachPluginWindowsCallback(window);
- return TRUE;
-}
-
-} // namespace
-
-// static
-void RenderWidgetHostViewBase::DetachPluginWindowsCallback(HWND window) {
- if (PluginServiceImpl::GetInstance()->IsPluginWindow(window) &&
- !IsHungAppWindow(window)) {
- ::ShowWindow(window, SW_HIDE);
- SetParent(window, NULL);
- }
-}
-
-// static
-void RenderWidgetHostViewBase::MovePluginWindowsHelper(
- HWND parent,
- const std::vector<WebPluginGeometry>& moves) {
- if (moves.empty())
- return;
-
- bool oop_plugins = !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kSingleProcess);
-
- HDWP defer_window_pos_info =
- ::BeginDeferWindowPos(static_cast<int>(moves.size()));
-
- if (!defer_window_pos_info) {
- NOTREACHED();
- return;
- }
-
-#if defined(USE_AURA)
- std::vector<RECT> invalidate_rects;
-#endif
-
- for (size_t i = 0; i < moves.size(); ++i) {
- unsigned long flags = 0;
- const WebPluginGeometry& move = moves[i];
- HWND window = move.window;
-
- // As the plugin parent window which lives on the browser UI thread is
- // destroyed asynchronously, it is possible that we have a stale window
- // sent in by the renderer for moving around.
- // Note: get the parent before checking if the window is valid, to avoid a
- // race condition where the window is destroyed after the check but before
- // the GetParent call.
- HWND cur_parent = ::GetParent(window);
- if (!::IsWindow(window))
- continue;
-
- if (!PluginServiceImpl::GetInstance()->IsPluginWindow(window)) {
- // The renderer should only be trying to move plugin windows. However,
- // this may happen as a result of a race condition (i.e. even after the
- // check right above), so we ignore it.
- continue;
- }
-
- if (oop_plugins) {
- if (cur_parent == GetDesktopWindow()) {
- // The plugin window hasn't been parented yet, add an intermediate
- // window that lives on this thread to speed up scrolling. Note this
- // only works with out of process plugins since we depend on
- // PluginProcessHost to destroy the intermediate HWNDs.
- cur_parent = ReparentWindow(window, parent);
- ::ShowWindow(window, SW_SHOW); // Window was created hidden.
- } else if (!IsPluginWrapperWindow(cur_parent)) {
- continue; // Race if plugin process is shutting down.
- }
-
- // We move the intermediate parent window which doesn't result in cross-
- // process synchronous Windows messages.
- window = cur_parent;
- } else {
- if (cur_parent == GetDesktopWindow())
- SetParent(window, parent);
- }
-
- if (move.visible)
- flags |= SWP_SHOWWINDOW;
- else
- flags |= SWP_HIDEWINDOW;
-
-#if defined(USE_AURA)
- if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
- // Without this flag, Windows repaints the parent area uncovered by this
- // move. However when software compositing is used the clipping region is
- // ignored. Since in Aura the browser chrome could be under the plugin, if
- // if Windows tries to paint it synchronously inside EndDeferWindowsPos
- // then it won't have the data and it will flash white. So instead we
- // manually redraw the plugin.
- // Why not do this for native Windows? Not sure if there are any
- // performance issues with this.
- flags |= SWP_NOREDRAW;
- }
-#endif
-
- if (move.rects_valid) {
- gfx::Rect clip_rect_in_pixel = gfx::win::DIPToScreenRect(move.clip_rect);
- HRGN hrgn = ::CreateRectRgn(clip_rect_in_pixel.x(),
- clip_rect_in_pixel.y(),
- clip_rect_in_pixel.right(),
- clip_rect_in_pixel.bottom());
- gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects);
-
- // Note: System will own the hrgn after we call SetWindowRgn,
- // so we don't need to call DeleteObject(hrgn)
- ::SetWindowRgn(window, hrgn,
- !move.clip_rect.IsEmpty() && (flags & SWP_NOREDRAW) == 0);
-
-#if defined(USE_AURA)
- // When using the software compositor, if the clipping rectangle is empty
- // then DeferWindowPos won't redraw the newly uncovered area under the
- // plugin.
- if (clip_rect_in_pixel.IsEmpty() &&
- !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
- RECT r;
- GetClientRect(window, &r);
- MapWindowPoints(window, parent, reinterpret_cast<POINT*>(&r), 2);
- invalidate_rects.push_back(r);
- }
-#endif
- } else {
- flags |= SWP_NOMOVE;
- flags |= SWP_NOSIZE;
- }
-
- gfx::Rect window_rect_in_pixel =
- gfx::win::DIPToScreenRect(move.window_rect);
- defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
- window, NULL,
- window_rect_in_pixel.x(),
- window_rect_in_pixel.y(),
- window_rect_in_pixel.width(),
- window_rect_in_pixel.height(),
- flags);
-
- if (!defer_window_pos_info) {
- DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored.";
- return;
- }
- }
-
- ::EndDeferWindowPos(defer_window_pos_info);
-
-#if defined(USE_AURA)
- if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
- for (size_t i = 0; i < moves.size(); ++i) {
- const WebPluginGeometry& move = moves[i];
- RECT r;
- GetWindowRect(move.window, &r);
- gfx::Rect gr(r);
- PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr));
- }
- } else {
- for (size_t i = 0; i < invalidate_rects.size(); ++i) {
- ::RedrawWindow(
- parent, &invalidate_rects[i], NULL,
- // These flags are from WebPluginDelegateImpl::NativeWndProc.
- RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME | RDW_UPDATENOW);
- }
- }
-#endif
-}
-
-// static
-void RenderWidgetHostViewBase::PaintPluginWindowsHelper(
- HWND parent, const gfx::Rect& damaged_screen_rect) {
- LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect);
- EnumChildWindows(parent, PaintEnumChildProc, lparam);
-}
-
-// static
-void RenderWidgetHostViewBase::DetachPluginsHelper(HWND parent) {
- // When a tab is closed all its child plugin windows are destroyed
- // automatically. This happens before plugins get any notification that its
- // instances are tearing down.
- //
- // Plugins like Quicktime assume that their windows will remain valid as long
- // as they have plugin instances active. Quicktime crashes in this case
- // because its windowing code cleans up an internal data structure that the
- // handler for NPP_DestroyStream relies on.
- //
- // The fix is to detach plugin windows from web contents when it is going
- // away. This will prevent the plugin windows from getting destroyed
- // automatically. The detached plugin windows will get cleaned up in proper
- // sequence as part of the usual cleanup when the plugin instance goes away.
- EnumChildWindows(parent, DetachPluginWindowsCallbackInternal, NULL);
-}
-
-#endif // OS_WIN
-
namespace {
// How many microseconds apart input events should be flushed.
@@ -376,11 +41,28 @@ RenderWidgetHostViewBase::RenderWidgetHostViewBase()
current_display_rotation_(gfx::Display::ROTATE_0),
pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
renderer_frame_number_(0),
- weak_factory_(this) {
-}
+ weak_factory_(this) {}
RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
DCHECK(!mouse_locked_);
+ // We call this here to guarantee that observers are notified before we go
+ // away. However, some subclasses may wish to call this earlier in their
+ // shutdown process, e.g. to force removal from
+ // RenderWidgetHostInputEventRouter's surface map before relinquishing a
+ // host pointer, as in RenderWidgetHostViewGuest. There is no harm in calling
+ // NotifyObserversAboutShutdown() twice, as the observers are required to
+ // de-register on the first call, and so the second call does nothing.
+ NotifyObserversAboutShutdown();
+}
+
+void RenderWidgetHostViewBase::NotifyObserversAboutShutdown() {
+ // Note: RenderWidgetHostInputEventRouter is an observer, and uses the
+ // following notification to remove this view from its surface owners map.
+ FOR_EACH_OBSERVER(RenderWidgetHostViewBaseObserver,
+ observers_,
+ OnRenderWidgetHostViewBaseDestroyed(this));
+ // All observers are required to disconnect after they are notified.
+ DCHECK(!observers_.might_have_observers());
}
bool RenderWidgetHostViewBase::OnMessageReceived(const IPC::Message& msg){
@@ -400,9 +82,8 @@ bool RenderWidgetHostViewBase::GetBackgroundOpaque() {
}
gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
- gfx::NativeView view = GetNativeView();
gfx::Display display =
- gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeView());
return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
display.device_scale_factor());
}
@@ -491,7 +172,7 @@ blink::WebPopupType RenderWidgetHostViewBase::GetPopupType() {
BrowserAccessibilityManager*
RenderWidgetHostViewBase::CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) {
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
NOTREACHED();
return NULL;
}
@@ -525,8 +206,8 @@ void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
if (GetRenderWidgetHost())
impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
- if (impl)
- impl->SendScreenRects();
+ if (impl && impl->delegate())
+ impl->delegate()->SendScreenRects();
if (HasDisplayPropertyChanged(view) && impl)
impl->NotifyScreenInfoChanged();
@@ -534,7 +215,7 @@ void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
gfx::Display display =
- gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(view);
if (current_display_area_ == display.work_area() &&
current_device_scale_factor_ == display.device_scale_factor() &&
current_display_rotation_ == display.rotation()) {
@@ -676,16 +357,22 @@ uint32_t RenderWidgetHostViewBase::GetSurfaceIdNamespace() {
}
uint32_t RenderWidgetHostViewBase::SurfaceIdNamespaceAtPoint(
+ cc::SurfaceHittestDelegate* delegate,
const gfx::Point& point,
gfx::Point* transformed_point) {
NOTREACHED();
return 0;
}
-void RenderWidgetHostViewBase::TransformPointToRootCoordSpace(
- const gfx::Point& point,
- gfx::Point* transformed_point) {
- *transformed_point = point;
+gfx::Point RenderWidgetHostViewBase::TransformPointToRootCoordSpace(
+ const gfx::Point& point) {
+ return point;
+}
+
+gfx::PointF RenderWidgetHostViewBase::TransformPointToRootCoordSpaceF(
+ const gfx::PointF& point) {
+ return gfx::PointF(TransformPointToRootCoordSpace(
+ gfx::ToRoundedPoint(point)));
}
void RenderWidgetHostViewBase::TransformPointToLocalCoordSpace(
@@ -695,4 +382,22 @@ void RenderWidgetHostViewBase::TransformPointToLocalCoordSpace(
*transformed_point = point;
}
+void RenderWidgetHostViewBase::AddObserver(
+ RenderWidgetHostViewBaseObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RenderWidgetHostViewBase::RemoveObserver(
+ RenderWidgetHostViewBaseObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool RenderWidgetHostViewBase::IsChildFrameForTesting() const {
+ return false;
+}
+
+cc::SurfaceId RenderWidgetHostViewBase::SurfaceIdForTesting() const {
+ return cc::SurfaceId();
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.h b/chromium/content/browser/renderer_host/render_widget_host_view_base.h
index d714137a2d6..c6d15c1cc0e 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.h
@@ -14,10 +14,12 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
#include "base/process/kill.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "cc/output/compositor_frame.h"
+#include "cc/surfaces/surface_id.h"
#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/common/content_export.h"
#include "content/common/input/input_event_ack_state.h"
@@ -51,6 +53,10 @@ class WebMouseEvent;
class WebMouseWheelEvent;
}
+namespace cc {
+class SurfaceHittestDelegate;
+}
+
namespace ui {
class LatencyInfo;
}
@@ -58,12 +64,12 @@ class LatencyInfo;
namespace content {
class BrowserAccessibilityDelegate;
class BrowserAccessibilityManager;
+class RenderWidgetHostViewBaseObserver;
class SyntheticGesture;
class SyntheticGestureTarget;
class WebCursor;
struct DidOverscrollParams;
struct NativeWebKeyboardEvent;
-struct WebPluginGeometry;
// Basic implementation shared by concrete RenderWidgetHostView subclasses.
class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
@@ -71,6 +77,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
public:
~RenderWidgetHostViewBase() override;
+ float current_device_scale_factor() const {
+ return current_device_scale_factor_;
+ }
+
// RenderWidgetHostView implementation.
void SetBackgroundColor(SkColor color) override;
void SetBackgroundColorToDefault() final;
@@ -88,6 +98,12 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override;
void EndFrameSubscription() override;
+ // This only needs to be overridden by RenderWidgetHostViewBase subclasses
+ // that handle content embedded within other RenderWidgetHostViews.
+ gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point) override;
+ gfx::PointF TransformPointToRootCoordSpaceF(
+ const gfx::PointF& point) override;
+
// IPC::Listener implementation:
bool OnMessageReceived(const IPC::Message& msg) override;
@@ -155,9 +171,12 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// be used to inject synthetic input events.
virtual scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget();
- // Create a BrowserAccessibilityManager for this view.
+ // Create a BrowserAccessibilityManager for a frame in this view.
+ // If |for_root_frame| is true, creates a BrowserAccessibilityManager
+ // suitable for the root frame, which may be linked to its native
+ // window container.
virtual BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate);
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame);
virtual void AccessibilityShowMenu(const gfx::Point& point);
virtual gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds);
@@ -196,22 +215,17 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// methods are invoked on the RenderWidgetHostView that should be able to
// properly handle the event (i.e. it has focus for keyboard events, or has
// been identified by hit testing mouse, touch or gesture events).
- virtual uint32_t SurfaceIdNamespaceAtPoint(const gfx::Point& point,
- gfx::Point* transformed_point);
+ virtual uint32_t SurfaceIdNamespaceAtPoint(
+ cc::SurfaceHittestDelegate* delegate,
+ const gfx::Point& point,
+ gfx::Point* transformed_point);
virtual void ProcessKeyboardEvent(const NativeWebKeyboardEvent& event) {}
virtual void ProcessMouseEvent(const blink::WebMouseEvent& event) {}
virtual void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) {}
virtual void ProcessTouchEvent(const blink::WebTouchEvent& event,
- const ui::LatencyInfo& latency) {}
-
- // If a RenderWidgetHost is dealing with points that are transformed from the
- // root frame for a page (i.e. because its content is contained within
- // that of another RenderWidgetHost), this provides a facility to convert
- // a point from its own coordinate space to that of the root frame.
- // This only needs to be overriden by RenderWidgetHostView subclasses
- // that handle content embedded within other RenderWidgetHostViews.
- virtual void TransformPointToRootCoordSpace(const gfx::Point& point,
- gfx::Point* transformed_point);
+ const ui::LatencyInfo& latency) {}
+ virtual void ProcessGestureEvent(const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) {}
// Transform a point that is in the coordinate space of a Surface that is
// embedded within the RenderWidgetHostViewBase's Surface to the
@@ -243,11 +257,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// helps to position the full screen widget on the correct monitor.
virtual void InitAsFullscreen(RenderWidgetHostView* reference_host_view) = 0;
- // Moves all plugin windows as described in the given list.
- // |scroll_offset| is the scroll offset of the render view.
- virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) = 0;
-
// Sets the cursor to the one associated with the specified cursor_type
virtual void UpdateCursor(const WebCursor& cursor) = 0;
@@ -354,51 +363,26 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void LockCompositingSurface() = 0;
virtual void UnlockCompositingSurface() = 0;
-#if defined(OS_MACOSX)
- // Does any event handling necessary for plugin IME; should be called after
- // the plugin has already had a chance to process the event. If plugin IME is
- // not enabled, this is a no-op, so it is always safe to call.
- // Returns true if the event was handled by IME.
- virtual bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) = 0;
-#endif
-
// Updates the range of the marked text in an IME composition.
virtual void ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) = 0;
-#if defined(OS_WIN)
- virtual void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) = 0;
-
- // Returns an HWND that's given as the parent window for windowless Flash to
- // workaround crbug.com/301548.
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const = 0;
+ // Add and remove observers for lifetime event notifications. The order in
+ // which notifications are sent to observers is undefined. Clients must be
+ // sure to remove the observer before they go away.
+ void AddObserver(RenderWidgetHostViewBaseObserver* observer);
+ void RemoveObserver(RenderWidgetHostViewBaseObserver* observer);
- // The callback that DetachPluginsHelper calls for each child window. Call
- // this directly if you want to do custom filtering on plugin windows first.
- static void DetachPluginWindowsCallback(HWND window);
-#endif
+ // Exposed for testing.
+ virtual bool IsChildFrameForTesting() const;
+ virtual cc::SurfaceId SurfaceIdForTesting() const;
protected:
// Interface class only, do not construct.
RenderWidgetHostViewBase();
-#if defined(OS_WIN)
- // Shared implementation of MovePluginWindows for use by win and aura/wina.
- static void MovePluginWindowsHelper(
- HWND parent,
- const std::vector<WebPluginGeometry>& moves);
-
- static void PaintPluginWindowsHelper(
- HWND parent,
- const gfx::Rect& damaged_screen_rect);
-
- // Needs to be called before the HWND backing the view goes away to avoid
- // crashes in Windowed plugins.
- static void DetachPluginsHelper(HWND parent);
-#endif
+ void NotifyObserversAboutShutdown();
// Whether this view is a popup and what kind of popup it is (select,
// autofill...).
@@ -447,6 +431,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
base::OneShotTimer flush_input_timer_;
+ base::ObserverList<RenderWidgetHostViewBaseObserver> observers_;
+
base::WeakPtrFactory<RenderWidgetHostViewBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewBase);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.cc b/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.cc
new file mode 100644
index 00000000000..92f1247d12f
--- /dev/null
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
+
+namespace content {
+
+RenderWidgetHostViewBaseObserver::~RenderWidgetHostViewBaseObserver() {}
+
+void RenderWidgetHostViewBaseObserver::OnRenderWidgetHostViewBaseDestroyed(
+ RenderWidgetHostViewBase*) {}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.h b/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.h
new file mode 100644
index 00000000000..acd3882fc02
--- /dev/null
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base_observer.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_BASE_OBSERVER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_BASE_OBSERVER_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class RenderWidgetHostViewBase;
+
+class CONTENT_EXPORT RenderWidgetHostViewBaseObserver {
+ public:
+ // All derived classes must de-register as observers when receiving this
+ // notification.
+ virtual void OnRenderWidgetHostViewBaseDestroyed(
+ RenderWidgetHostViewBase* view);
+
+ protected:
+ RenderWidgetHostViewBaseObserver() = default;
+ virtual ~RenderWidgetHostViewBaseObserver();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewBaseObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_BASE_OBSERVER_H_
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index d7f79a0b573..d1f1fbae2d0 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -276,9 +276,8 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
DeliverFrameCallback callback_;
};
-// Disable tests for Android and IOS as these platforms have incomplete
-// implementation.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+// Disable tests for Android as it has an incomplete implementation.
+#if !defined(OS_ANDROID)
// The CopyFromBackingStore() API should work on all platforms when compositing
// is enabled.
@@ -1005,7 +1004,7 @@ INSTANTIATE_TEST_CASE_P(
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
kTestCompositingModes);
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !defined(OS_ANDROID)
} // namespace
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac.h b/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
index 459f16a15bc..0c1b9a9c6e4 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -21,8 +21,9 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
-#include "content/browser/compositor/browser_compositor_view_mac.h"
-#include "content/browser/compositor/delegated_frame_host.h"
+#include "cc/surfaces/surface_id.h"
+#include "content/browser/renderer_host/browser_compositor_view_mac.h"
+#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
@@ -80,8 +81,6 @@ class Layer;
// Is YES if there was a mouse-down as yet unbalanced with a mouse-up.
BOOL hasOpenMouseDown_;
- NSWindow* lastWindow_; // weak
-
// The cursor for the page. This is passed up from the renderer.
base::scoped_nsobject<NSCursor> currentCursor_;
@@ -130,6 +129,9 @@ class Layer;
// Underline information of the |markedText_|.
std::vector<blink::WebCompositionUnderline> underlines_;
+ // Replacement range information received from |setMarkedText:|.
+ gfx::Range setMarkedTextReplacementRange_;
+
// Indicates if doCommandBySelector method receives any edit command when
// handling a key down event.
BOOL hasEditCommands_;
@@ -139,12 +141,6 @@ class Layer;
// etc.
content::EditCommands editCommands_;
- // The plugin that currently has focus (-1 if no plugin has focus).
- int focusedPluginIdentifier_;
-
- // Whether or not plugin IME is currently enabled active.
- BOOL pluginImeActive_;
-
// Whether the previous mouse event was ignored due to hitTest check.
BOOL mouseEventWasIgnored_;
@@ -200,13 +196,6 @@ class Layer;
- (void)cancelComposition;
// Confirm ongoing composition.
- (void)confirmComposition;
-// Enables or disables plugin IME.
-- (void)setPluginImeActive:(BOOL)active;
-// Updates the current plugin focus state.
-- (void)pluginFocusChanged:(BOOL)focused forPlugin:(int)pluginId;
-// Evaluates the event in the context of plugin IME, if plugin IME is enabled.
-// Returns YES if the event was handled.
-- (BOOL)postProcessEventForPluginIme:(NSEvent*)event;
- (void)updateCursor:(NSCursor*)cursor;
- (NSRect)firstViewRectForCharacterRange:(NSRange)theRange
actualRange:(NSRangePointer)actualRange;
@@ -281,8 +270,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
gfx::Rect GetViewBounds() const override;
void SetShowingContextMenu(bool showing) override;
void SetActive(bool active) override;
- void SetWindowVisibility(bool visible) override;
- void WindowFrameChanged() override;
void ShowDefinitionForSelection() override;
bool SupportsSpeech() const override;
void SpeakSelection() override;
@@ -294,7 +281,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void Focus() override;
void UpdateCursor(const WebCursor& cursor) override;
void SetIsLoading(bool is_loading) override;
@@ -329,10 +315,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
scoped_ptr<cc::CompositorFrame> frame) override;
void ClearCompositorFrame() override;
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) override;
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) override;
gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds) override;
- bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) override;
bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
void GetScreenInfo(blink::WebScreenInfo* results) override;
@@ -345,16 +329,23 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void UnlockMouse() override;
void WheelEventAck(const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) override;
+ void GestureEventAck(const blink::WebGestureEvent& event,
+ InputEventAckState ack_result) override;
scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
uint32_t GetSurfaceIdNamespace() override;
- uint32_t SurfaceIdNamespaceAtPoint(const gfx::Point& point,
+ uint32_t SurfaceIdNamespaceAtPoint(cc::SurfaceHittestDelegate* delegate,
+ const gfx::Point& point,
gfx::Point* transformed_point) override;
// Returns true when we can do SurfaceHitTesting for the event type.
bool ShouldRouteEvent(const blink::WebInputEvent& event) const;
void ProcessMouseEvent(const blink::WebMouseEvent& event) override;
void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
+ void ProcessTouchEvent(const blink::WebTouchEvent& event,
+ const ui::LatencyInfo& latency) override;
+ void ProcessGestureEvent(const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) override;
void TransformPointToLocalCoordSpace(const gfx::Point& point,
cc::SurfaceId original_surface,
gfx::Point* transformed_point) override;
@@ -375,9 +366,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void SetTextInputActive(bool active);
- // Sends completed plugin IME notification and text back to the renderer.
- void PluginImeCompositionCompleted(const base::string16& text, int plugin_id);
-
const std::string& selected_text() const { return selected_text_; }
const gfx::Range& composition_range() const { return composition_range_; }
const base::string16& selection_text() const { return selection_text_; }
@@ -525,6 +513,9 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// state, if appropriate (see BrowserCompositorViewState for details).
void DestroySuspendedBrowserCompositorViewIfNeeded();
+ // Exposed for testing.
+ cc::SurfaceId SurfaceIdForTesting() const override;
+
private:
friend class RenderWidgetHostViewMacTest;
@@ -546,8 +537,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void DestroyBrowserCompositorView();
// IPC message handlers.
- void OnPluginFocusChanged(bool focused, int plugin_id);
- void OnStartPluginIme();
void OnGetRenderedTextCompleted(const std::string& text);
// Send updated vsync parameters to the renderer.
@@ -577,6 +566,9 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// RenderWidgetHostViewGuest.
bool is_guest_view_hack_;
+ // True if gestures are generated for mouse wheel events.
+ bool wheel_gestures_enabled_;
+
// selected text on the renderer.
std::string selected_text_;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm b/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
index ef38d30fe02..0581389eeaf 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -21,6 +21,7 @@
#include "base/mac/scoped_cftyperef.h"
#import "base/mac/scoped_nsobject.h"
#include "base/mac/sdk_forward_declarations.h"
+#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
@@ -31,32 +32,32 @@
#include "base/sys_info.h"
#include "base/trace_event/trace_event.h"
#import "content/browser/accessibility/browser_accessibility_cocoa.h"
+#import "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
#include "content/browser/bad_message.h"
#import "content/browser/cocoa/system_hotkey_helper_mac.h"
#import "content/browser/cocoa/system_hotkey_map.h"
-#include "content/browser/compositor/resize_lock.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/gpu/compositor_util.h"
+#import "content/browser/renderer_host/input/synthetic_gesture_target_mac.h"
#include "content/browser/renderer_host/input/web_input_event_builders_mac.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
-#import "content/browser/renderer_host/input/synthetic_gesture_target_mac.h"
#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
#include "content/browser/renderer_host/render_widget_resize_helper_mac.h"
+#include "content/browser/renderer_host/resize_lock.h"
#import "content/browser/renderer_host/text_input_client_mac.h"
#include "content/common/accessibility_messages.h"
#include "content/common/edit_command.h"
-#include "content/common/gpu/gpu_messages.h"
+#include "content/common/input/input_event_utils.h"
#include "content/common/input_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
-#include "content/common/webplugin_geometry.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/browser_thread.h"
@@ -64,12 +65,14 @@
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#import "content/public/browser/render_widget_host_view_mac_delegate.h"
#include "content/public/browser/web_contents.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_mac.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#import "third_party/mozilla/ComplexTextInputPanel.h"
+#import "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/base/cocoa/animation_utils.h"
+#include "ui/base/cocoa/cocoa_base_utils.h"
#import "ui/base/cocoa/fullscreen_window_manager.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
#include "ui/base/layout.h"
@@ -174,11 +177,14 @@ static BOOL SupportsBackingPropertiesChangedNotification() {
- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
- (void)processedWheelEvent:(const blink::WebMouseWheelEvent&)event
consumed:(BOOL)consumed;
+- (void)processedGestureScrollEvent:(const blink::WebGestureEvent&)event
+ consumed:(BOOL)consumed;
- (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv;
- (void)windowDidChangeBackingProperties:(NSNotification*)notification;
- (void)windowChangedGlobalFrame:(NSNotification*)notification;
-- (void)checkForPluginImeCancellation;
+- (void)windowDidBecomeKey:(NSNotification*)notification;
+- (void)windowDidResignKey:(NSNotification*)notification;
- (void)updateScreenProperties;
- (void)setResponderDelegate:
(NSObject<RenderWidgetHostViewMacDelegate>*)delegate;
@@ -396,7 +402,7 @@ NSWindow* ApparentWindowForView(NSView* view) {
blink::WebScreenInfo GetWebScreenInfo(NSView* view) {
gfx::Display display =
- gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(view);
+ gfx::Screen::GetScreen()->GetDisplayNearestWindow(view);
NSScreen* screen = [NSScreen deepestScreen];
@@ -519,6 +525,7 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
is_loading_(false),
allow_pause_for_resize_or_repaint_(true),
is_guest_view_hack_(is_guest_view_hack),
+ wheel_gestures_enabled_(UseGestureBasedWheelScrolling()),
fullscreen_parent_host_view_(NULL),
weak_factory_(this) {
// |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
@@ -539,14 +546,14 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
delegated_frame_host_.reset(new DelegatedFrameHost(this));
- gfx::Screen::GetScreenFor(cocoa_view_)->AddObserver(this);
+ gfx::Screen::GetScreen()->AddObserver(this);
if (!is_guest_view_hack_)
render_widget_host_->SetView(this);
// Let the page-level input event router know about our surface ID
// namespace for surface-based hit testing.
- if (UseSurfacesEnabled() && render_widget_host_->delegate() &&
+ if (render_widget_host_->delegate() &&
render_widget_host_->delegate()->GetInputEventRouter()) {
render_widget_host_->delegate()
->GetInputEventRouter()
@@ -555,7 +562,7 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
}
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
- gfx::Screen::GetScreenFor(cocoa_view_)->RemoveObserver(this);
+ gfx::Screen::GetScreen()->RemoveObserver(this);
// This is being called from |cocoa_view_|'s destructor, so invalidate the
// pointer.
@@ -563,14 +570,6 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
UnlockMouse();
- if (UseSurfacesEnabled() && render_widget_host_ &&
- render_widget_host_->delegate() &&
- render_widget_host_->delegate()->GetInputEventRouter()) {
- render_widget_host_->delegate()
- ->GetInputEventRouter()
- ->RemoveSurfaceIdNamespaceOwner(GetSurfaceIdNamespace());
- }
-
// Ensure that the browser compositor is destroyed in a safe order.
ShutdownBrowserCompositor();
@@ -595,6 +594,10 @@ void RenderWidgetHostViewMac::SetAllowPauseForResizeOrRepaint(bool allow) {
allow_pause_for_resize_or_repaint_ = allow;
}
+cc::SurfaceId RenderWidgetHostViewMac::SurfaceIdForTesting() const {
+ return delegated_frame_host_->SurfaceIdForTesting();
+}
+
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewMac, RenderWidgetHostView implementation:
@@ -681,8 +684,6 @@ void RenderWidgetHostViewMac::DestroySuspendedBrowserCompositorViewIfNeeded() {
bool RenderWidgetHostViewMac::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewMac, message)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged, OnPluginFocusChanged)
- IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme, OnStartPluginIme)
IPC_MESSAGE_HANDLER(ViewMsg_GetRenderedTextCompleted,
OnGetRenderedTextCompleted)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -892,7 +893,7 @@ void RenderWidgetHostViewMac::WasOccluded() {
// occur in this specific order. However, because thumbnail generation is
// asychronous, that operation won't run before SuspendBrowserCompositorView()
// completes. As a result you won't get a thumbnail for the page unless you
- // happen to switch back to it. See http://crbug.com/530707 .
+ // execute these two statements in this specific order.
render_widget_host_->WasHidden();
SuspendBrowserCompositorView();
}
@@ -967,14 +968,6 @@ gfx::NativeViewAccessible RenderWidgetHostViewMac::GetNativeViewAccessible() {
return cocoa_view_;
}
-void RenderWidgetHostViewMac::MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) {
- // Must be overridden, but unused on this platform. Core Animation
- // plugins are drawn by the GPU process (through the compositor),
- // and Core Graphics plugins are drawn by the renderer process.
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
void RenderWidgetHostViewMac::Focus() {
[[cocoa_view_ window] makeFirstResponder:cocoa_view_];
}
@@ -1002,7 +995,7 @@ gfx::Rect RenderWidgetHostViewMac::GetViewBounds() const {
return gfx::Rect(gfx::Size(NSWidth(bounds), NSHeight(bounds)));
bounds = [cocoa_view_ convertRect:bounds toView:nil];
- bounds.origin = [enclosing_window convertBaseToScreen:bounds.origin];
+ bounds = [enclosing_window convertRectToScreen:bounds];
return FlipNSRectToRectScreen(bounds);
}
@@ -1057,6 +1050,9 @@ void RenderWidgetHostViewMac::RenderProcessGone(base::TerminationStatus status,
}
void RenderWidgetHostViewMac::Destroy() {
+ // SurfaceIdNamespaces registered with RenderWidgetHostInputEventRouter
+ // have already been cleared when RenderWidgetHostViewBase notified its
+ // observers of our impending destruction.
[[NSNotificationCenter defaultCenter]
removeObserver:cocoa_view_
name:NSWindowWillCloseNotification
@@ -1079,20 +1075,14 @@ void RenderWidgetHostViewMac::Destroy() {
// object needs to survive until the stack unwinds.
pepper_fullscreen_window_.autorelease();
- // Clear SurfaceID namespace ownership before we shutdown the
- // compositor.
- if (UseSurfacesEnabled() && render_widget_host_ &&
- render_widget_host_->delegate() &&
- render_widget_host_->delegate()->GetInputEventRouter()) {
- render_widget_host_->delegate()
- ->GetInputEventRouter()
- ->RemoveSurfaceIdNamespaceOwner(GetSurfaceIdNamespace());
- }
-
// Delete the delegated frame state, which will reach back into
// render_widget_host_.
ShutdownBrowserCompositor();
+ // Make sure none of our observers send events for us to process after
+ // we release render_widget_host_.
+ NotifyObserversAboutShutdown();
+
// We get this call just before |render_widget_host_| deletes
// itself. But we are owned by |cocoa_view_|, which may be retained
// by some other code. Examples are WebContentsViewMac's
@@ -1277,27 +1267,6 @@ void RenderWidgetHostViewMac::KillSelf() {
}
}
-bool RenderWidgetHostViewMac::PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) {
- // Check WebInputEvent type since multiple types of events can be sent into
- // WebKit for the same OS event (e.g., RawKeyDown and Char), so filtering is
- // necessary to avoid double processing.
- // Also check the native type, since NSFlagsChanged is considered a key event
- // for WebKit purposes, but isn't considered a key event by the OS.
- if (event.type == WebInputEvent::RawKeyDown &&
- [event.os_event type] == NSKeyDown)
- return [cocoa_view_ postProcessEventForPluginIme:event.os_event];
- return false;
-}
-
-void RenderWidgetHostViewMac::PluginImeCompositionCompleted(
- const base::string16& text, int plugin_id) {
- if (render_widget_host_) {
- render_widget_host_->Send(new ViewMsg_PluginImeCompositionCompleted(
- render_widget_host_->GetRoutingID(), text, plugin_id));
- }
-}
-
bool RenderWidgetHostViewMac::GetLineBreakIndex(
const std::vector<gfx::Rect>& bounds,
const gfx::Range& range,
@@ -1312,7 +1281,8 @@ bool RenderWidgetHostViewMac::GetLineBreakIndex(
// 75% of maximum height.
// TODO(nona): Check the threshold is reliable or not.
// TODO(nona): Bidi support.
- const size_t loop_end_idx = std::min(bounds.size(), range.end());
+ const size_t loop_end_idx =
+ std::min(bounds.size(), static_cast<size_t>(range.end()));
int max_height = 0;
int min_y_offset = std::numeric_limits<int32_t>::max();
for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
@@ -1551,6 +1521,10 @@ void RenderWidgetHostViewMac::UnlockMouse() {
void RenderWidgetHostViewMac::WheelEventAck(
const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) {
+ // TODO(dtapuska): Remove this handling of the wheel event ack
+ // once wheel gestures is enabled for a full release; see crbug.com/598798.
+ if (wheel_gestures_enabled_)
+ return;
bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
// Only record a wheel event as unhandled if JavaScript handlers got a chance
// to see it (no-op wheel events are ignored by the event dispatcher)
@@ -1558,6 +1532,23 @@ void RenderWidgetHostViewMac::WheelEventAck(
[cocoa_view_ processedWheelEvent:event consumed:consumed];
}
+void RenderWidgetHostViewMac::GestureEventAck(
+ const blink::WebGestureEvent& event,
+ InputEventAckState ack_result) {
+ if (!wheel_gestures_enabled_)
+ return;
+ bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
+ switch (event.type) {
+ case blink::WebInputEvent::GestureScrollBegin:
+ case blink::WebInputEvent::GestureScrollUpdate:
+ case blink::WebInputEvent::GestureScrollEnd:
+ [cocoa_view_ processedGestureScrollEvent:event consumed:consumed];
+ return;
+ default:
+ break;
+ }
+}
+
scoped_ptr<SyntheticGestureTarget>
RenderWidgetHostViewMac::CreateSyntheticGestureTarget() {
RenderWidgetHostImpl* host =
@@ -1572,16 +1563,17 @@ uint32_t RenderWidgetHostViewMac::GetSurfaceIdNamespace() {
}
uint32_t RenderWidgetHostViewMac::SurfaceIdNamespaceAtPoint(
+ cc::SurfaceHittestDelegate* delegate,
const gfx::Point& point,
gfx::Point* transformed_point) {
// The surface hittest happens in device pixels, so we need to convert the
// |point| from DIPs to pixels before hittesting.
- float scale_factor = gfx::Screen::GetScreenFor(cocoa_view_)
+ float scale_factor = gfx::Screen::GetScreen()
->GetDisplayNearestWindow(cocoa_view_)
.device_scale_factor();
gfx::Point point_in_pixels = gfx::ConvertPointToPixel(scale_factor, point);
- cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(point_in_pixels,
- transformed_point);
+ cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(
+ delegate, point_in_pixels, transformed_point);
*transformed_point = gfx::ConvertPointToDIP(scale_factor, *transformed_point);
// It is possible that the renderer has not yet produced a surface, in which
@@ -1612,12 +1604,31 @@ void RenderWidgetHostViewMac::ProcessMouseWheelEvent(
render_widget_host_->ForwardWheelEvent(event);
}
+void RenderWidgetHostViewMac::ProcessTouchEvent(
+ const blink::WebTouchEvent& event,
+ const ui::LatencyInfo& latency) {
+ render_widget_host_->ForwardTouchEventWithLatencyInfo(event, latency);
+}
+
+void RenderWidgetHostViewMac::ProcessGestureEvent(
+ const blink::WebGestureEvent& event,
+ const ui::LatencyInfo& latency) {
+ render_widget_host_->ForwardGestureEventWithLatencyInfo(event, latency);
+}
+
void RenderWidgetHostViewMac::TransformPointToLocalCoordSpace(
const gfx::Point& point,
cc::SurfaceId original_surface,
gfx::Point* transformed_point) {
+ // Transformations use physical pixels rather than DIP, so conversion
+ // is necessary.
+ float scale_factor = gfx::Screen::GetScreen()
+ ->GetDisplayNearestWindow(cocoa_view_)
+ .device_scale_factor();
+ gfx::Point point_in_pixels = gfx::ConvertPointToPixel(scale_factor, point);
delegated_frame_host_->TransformPointToLocalCoordSpace(
- point, original_surface, transformed_point);
+ point_in_pixels, original_surface, transformed_point);
+ *transformed_point = gfx::ConvertPointToDIP(scale_factor, *transformed_point);
}
bool RenderWidgetHostViewMac::Send(IPC::Message* message) {
@@ -1652,25 +1663,8 @@ void RenderWidgetHostViewMac::SetActive(bool active) {
}
if (HasFocus())
SetTextInputActive(active);
- if (!active) {
- [cocoa_view_ setPluginImeActive:NO];
+ if (!active)
UnlockMouse();
- }
-}
-
-void RenderWidgetHostViewMac::SetWindowVisibility(bool visible) {
- if (render_widget_host_) {
- render_widget_host_->Send(new ViewMsg_SetWindowVisibility(
- render_widget_host_->GetRoutingID(), visible));
- }
-}
-
-void RenderWidgetHostViewMac::WindowFrameChanged() {
- if (render_widget_host_) {
- render_widget_host_->Send(new ViewMsg_WindowFrameChanged(
- render_widget_host_->GetRoutingID(), GetBoundsInRootWindow(),
- GetViewBounds()));
- }
}
void RenderWidgetHostViewMac::ShowDefinitionForSelection() {
@@ -1679,6 +1673,9 @@ void RenderWidgetHostViewMac::ShowDefinitionForSelection() {
}
void RenderWidgetHostViewMac::SetBackgroundColor(SkColor color) {
+ if (color == background_color_)
+ return;
+
RenderWidgetHostViewBase::SetBackgroundColor(color);
bool opaque = GetBackgroundOpaque();
@@ -1688,11 +1685,16 @@ void RenderWidgetHostViewMac::SetBackgroundColor(SkColor color) {
[cocoa_view_ setOpaque:opaque];
if (browser_compositor_state_ != BrowserCompositorDestroyed)
browser_compositor_->compositor()->SetHostHasTransparentBackground(!opaque);
+
+ ScopedCAActionDisabler disabler;
+ base::ScopedCFTypeRef<CGColorRef> cg_color(
+ skia::CGColorCreateFromSkColor(color));
+ [background_layer_ setBackgroundColor:cg_color];
}
BrowserAccessibilityManager*
RenderWidgetHostViewMac::CreateBrowserAccessibilityManager(
- BrowserAccessibilityDelegate* delegate) {
+ BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
return new BrowserAccessibilityManagerMac(
cocoa_view_,
BrowserAccessibilityManagerMac::GetEmptyDocument(),
@@ -1706,7 +1708,7 @@ gfx::Point RenderWidgetHostViewMac::AccessibilityOriginInScreen(
origin.y = NSHeight([cocoa_view_ bounds]) - origin.y;
NSPoint originInWindow = [cocoa_view_ convertPoint:origin toView:nil];
NSPoint originInScreen =
- [[cocoa_view_ window] convertBaseToScreen:originInWindow];
+ ui::ConvertPointFromWindowToScreen([cocoa_view_ window], originInWindow);
originInScreen.y = originInScreen.y - size.height;
return gfx::Point(originInScreen.x, originInScreen.y);
}
@@ -1723,15 +1725,6 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
}
}
-void RenderWidgetHostViewMac::OnPluginFocusChanged(bool focused,
- int plugin_id) {
- [cocoa_view_ pluginFocusChanged:(focused ? YES : NO) forPlugin:plugin_id];
-}
-
-void RenderWidgetHostViewMac::OnStartPluginIme() {
- [cocoa_view_ setPluginImeActive:YES];
-}
-
void RenderWidgetHostViewMac::OnGetRenderedTextCompleted(
const std::string& text) {
SpeakText(text);
@@ -1761,7 +1754,7 @@ void RenderWidgetHostViewMac::OnDisplayRemoved(const gfx::Display& display) {
void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
const gfx::Display& display, uint32_t metrics) {
- gfx::Screen* screen = gfx::Screen::GetScreenFor(cocoa_view_);
+ gfx::Screen* screen = gfx::Screen::GetScreen();
if (display.id() != screen->GetDisplayNearestWindow(cocoa_view_).id())
return;
@@ -1787,7 +1780,6 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
renderWidgetHostView_.reset(r);
canBeKeyView_ = YES;
opaque_ = YES;
- focusedPluginIdentifier_ = -1;
pinchHasReachedZoomThreshold_ = false;
// OpenGL support:
@@ -1837,6 +1829,12 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
[responderDelegate_ rendererHandledWheelEvent:event consumed:consumed];
}
+- (void)processedGestureScrollEvent:(const blink::WebGestureEvent&)event
+ consumed:(BOOL)consumed {
+ [responderDelegate_ rendererHandledGestureScrollEvent:event
+ consumed:consumed];
+}
+
- (BOOL)respondsToSelector:(SEL)selector {
// Trickiness: this doesn't mean "does this object's superclass respond to
// this selector" but rather "does the -respondsToSelector impl from the
@@ -2152,22 +2150,14 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
markedText_.clear();
markedTextSelectedRange_ = NSMakeRange(NSNotFound, 0);
underlines_.clear();
+ setMarkedTextReplacementRange_ = gfx::Range::InvalidRange();
unmarkTextCalled_ = NO;
hasEditCommands_ = NO;
editCommands_.clear();
- // Before doing anything with a key down, check to see if plugin IME has been
- // cancelled, since the plugin host needs to be informed of that before
- // receiving the keydown.
- if ([theEvent type] == NSKeyDown)
- [self checkForPluginImeCancellation];
-
// Sends key down events to input method first, then we can decide what should
// be done according to input method's feedback.
- // If a plugin is active, bypass this step since events are forwarded directly
- // to the plugin IME.
- if (focusedPluginIdentifier_ == -1)
- [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
handlingKeyDown_ = NO;
@@ -2237,6 +2227,7 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
// When marked text is available, |markedTextSelectedRange_| will be the
// range being selected inside the marked text.
widgetHost->ImeSetComposition(markedText_, underlines_,
+ setMarkedTextReplacementRange_,
markedTextSelectedRange_.location,
NSMaxRange(markedTextSelectedRange_));
} else if (oldHasMarkedText && !hasMarkedText_ && !textInserted) {
@@ -2248,6 +2239,9 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
}
}
+ // Clear information from |interpretKeyEvents:|
+ setMarkedTextReplacementRange_ = gfx::Range::InvalidRange();
+
// If the key event was handled by the input method but it also generated some
// edit commands, then we need to send the real key event and corresponding
// edit commands here. This usually occurs when the input method wants to
@@ -2402,11 +2396,11 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
renderWidgetHostView_->selected_text());
if ([text length] == 0)
return;
- NSPasteboard* pasteboard = [NSPasteboard pasteboardWithUniqueName];
+ scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard;
NSArray* types = [NSArray arrayWithObject:NSStringPboardType];
- [pasteboard declareTypes:types owner:nil];
- if ([pasteboard setString:text forType:NSStringPboardType])
- NSPerformService(@"Look Up in Dictionary", pasteboard);
+ [pasteboard->get() declareTypes:types owner:nil];
+ if ([pasteboard->get() setString:text forType:NSStringPboardType])
+ NSPerformService(@"Look Up in Dictionary", pasteboard->get());
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
@@ -2564,6 +2558,14 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
removeObserver:self
name:NSWindowDidEndLiveResizeNotification
object:oldWindow];
+ [notificationCenter
+ removeObserver:self
+ name:NSWindowDidBecomeKeyNotification
+ object:oldWindow];
+ [notificationCenter
+ removeObserver:self
+ name:NSWindowDidResignKeyNotification
+ object:oldWindow];
}
if (newWindow) {
if (supportsBackingPropertiesNotification) {
@@ -2583,6 +2585,14 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
selector:@selector(windowChangedGlobalFrame:)
name:NSWindowDidEndLiveResizeNotification
object:newWindow];
+ [notificationCenter addObserver:self
+ selector:@selector(windowDidBecomeKey:)
+ name:NSWindowDidBecomeKeyNotification
+ object:newWindow];
+ [notificationCenter addObserver:self
+ selector:@selector(windowDidResignKey:)
+ name:NSWindowDidResignKeyNotification
+ object:newWindow];
}
}
@@ -2620,7 +2630,10 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
if (!renderWidgetHostView_->render_widget_host_)
return;
- renderWidgetHostView_->render_widget_host_->SendScreenRects();
+ if (renderWidgetHostView_->render_widget_host_->delegate())
+ renderWidgetHostView_->render_widget_host_->delegate()->SendScreenRects();
+ else
+ renderWidgetHostView_->render_widget_host_->SendScreenRects();
renderWidgetHostView_->render_widget_host_->WasResized();
if (renderWidgetHostView_->delegated_frame_host_)
renderWidgetHostView_->delegated_frame_host_->WasResized();
@@ -2646,6 +2659,28 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
return canBeKeyView_;
}
+- (void)windowDidBecomeKey:(NSNotification*)notification {
+ DCHECK([self window]);
+ DCHECK_EQ([self window], [notification object]);
+ if ([[self window] firstResponder] == self)
+ renderWidgetHostView_->SetActive(true);
+}
+
+- (void)windowDidResignKey:(NSNotification*)notification {
+ DCHECK([self window]);
+ DCHECK_EQ([self window], [notification object]);
+
+ // If our app is still active and we're still the key window, ignore this
+ // message, since it just means that a menu extra (on the "system status bar")
+ // was activated; we'll get another |-windowDidResignKey| if we ever really
+ // lose key window status.
+ if ([NSApp isActive] && ([NSApp keyWindow] == [self window]))
+ return;
+
+ if ([[self window] firstResponder] == self)
+ renderWidgetHostView_->SetActive(false);
+}
+
- (BOOL)becomeFirstResponder {
if (!renderWidgetHostView_->render_widget_host_)
return NO;
@@ -2768,8 +2803,8 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
if (([attribute isEqualToString:NSAccessibilityChildrenAttribute] ||
[attribute isEqualToString:NSAccessibilityContentsAttribute]) &&
manager) {
- return [NSArray arrayWithObjects:manager->
- GetRoot()->ToBrowserAccessibilityCocoa(), nil];
+ return [NSArray arrayWithObjects:ToBrowserAccessibilityCocoa(
+ manager->GetRoot()), nil];
} else if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
return NSAccessibilityScrollAreaRole;
}
@@ -2790,11 +2825,12 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
->GetRootBrowserAccessibilityManager();
if (!manager)
return self;
- NSPoint pointInWindow = [[self window] convertScreenToBase:point];
+ NSPoint pointInWindow =
+ ui::ConvertPointFromScreenToWindow([self window], point);
NSPoint localPoint = [self convertPoint:pointInWindow fromView:nil];
localPoint.y = NSHeight([self bounds]) - localPoint.y;
BrowserAccessibilityCocoa* root =
- manager->GetRoot()->ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(manager->GetRoot());
id obj = [root accessibilityHitTest:localPoint];
return obj;
}
@@ -2812,7 +2848,7 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
->GetRootBrowserAccessibilityManager();
// Only child is root.
if (manager &&
- manager->GetRoot()->ToBrowserAccessibilityCocoa() == child) {
+ ToBrowserAccessibilityCocoa(manager->GetRoot()) == child) {
return 0;
} else {
return NSNotFound;
@@ -2824,11 +2860,11 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
renderWidgetHostView_->render_widget_host_
->GetRootBrowserAccessibilityManager();
if (manager) {
- BrowserAccessibility* focused_item = manager->GetFocus(NULL);
+ BrowserAccessibility* focused_item = manager->GetFocus();
DCHECK(focused_item);
if (focused_item) {
BrowserAccessibilityCocoa* focused_item_cocoa =
- focused_item->ToBrowserAccessibilityCocoa();
+ ToBrowserAccessibilityCocoa(focused_item);
DCHECK(focused_item_cocoa);
if (focused_item_cocoa)
return focused_item_cocoa;
@@ -2914,7 +2950,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// |thePoint| is in screen coordinates, but needs to be converted to WebKit
// coordinates (upper left origin). Scroll offsets will be taken care of in
// the renderer.
- thePoint = [[self window] convertScreenToBase:thePoint];
+ thePoint = ui::ConvertPointFromScreenToWindow([self window], thePoint);
thePoint = [self convertPoint:thePoint fromView:nil];
thePoint.y = NSHeight([self frame]) - thePoint.y;
@@ -2961,7 +2997,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// Convert into screen coordinates for return.
rect = [self convertRect:rect toView:nil];
- rect.origin = [[self window] convertBaseToScreen:rect.origin];
+ rect = [[self window] convertRectToScreen:rect];
return rect;
}
@@ -3024,9 +3060,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// nil when the caret is in non-editable content or password box to avoid
// making input methods do their work.
- (NSTextInputContext *)inputContext {
- if (focusedPluginIdentifier_ != -1)
- return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext];
-
switch(renderWidgetHostView_->text_input_type_) {
case ui::TEXT_INPUT_TYPE_NONE:
case ui::TEXT_INPUT_TYPE_PASSWORD:
@@ -3099,9 +3132,11 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// is empty to update the input method state. (Our input method backend can
// automatically cancels an ongoing composition when we send an empty text.
// So, it is OK to send an empty text to the renderer.)
- if (!handlingKeyDown_) {
+ if (handlingKeyDown_) {
+ setMarkedTextReplacementRange_ = gfx::Range(replacementRange);
+ } else {
renderWidgetHostView_->render_widget_host_->ImeSetComposition(
- markedText_, underlines_,
+ markedText_, underlines_, gfx::Range(replacementRange),
newSelRange.location, NSMaxRange(newSelRange));
}
}
@@ -3177,22 +3212,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
renderWidgetHostView_->DestroySuspendedBrowserCompositorViewIfNeeded();
}
- if (canBeKeyView_) {
- NSWindow* newWindow = [self window];
- // Pointer comparison only, since we don't know if lastWindow_ is still
- // valid.
- if (newWindow) {
- // If we move into a new window, refresh the frame information. We
- // don't need to do it if it was the same window as it used to be in,
- // since that case is covered by WasShown(). We only want to do this for
- // real browser views, not popups.
- if (newWindow != lastWindow_) {
- lastWindow_ = newWindow;
- renderWidgetHostView_->WindowFrameChanged();
- }
- }
- }
-
// If we switch windows (or are removed from the view hierarchy), cancel any
// open mouse-downs.
if (hasOpenMouseDown_) {
@@ -3304,54 +3323,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
[self cancelComposition];
}
-- (void)setPluginImeActive:(BOOL)active {
- if (active == pluginImeActive_)
- return;
-
- pluginImeActive_ = active;
- if (!active) {
- [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelComposition];
- renderWidgetHostView_->PluginImeCompositionCompleted(
- base::string16(), focusedPluginIdentifier_);
- }
-}
-
-- (void)pluginFocusChanged:(BOOL)focused forPlugin:(int)pluginId {
- if (focused)
- focusedPluginIdentifier_ = pluginId;
- else if (focusedPluginIdentifier_ == pluginId)
- focusedPluginIdentifier_ = -1;
-
- // Whenever plugin focus changes, plugin IME resets.
- [self setPluginImeActive:NO];
-}
-
-- (BOOL)postProcessEventForPluginIme:(NSEvent*)event {
- if (!pluginImeActive_)
- return false;
-
- ComplexTextInputPanel* inputPanel =
- [ComplexTextInputPanel sharedComplexTextInputPanel];
- NSString* composited_string = nil;
- BOOL handled = [inputPanel interpretKeyEvent:event
- string:&composited_string];
- if (composited_string) {
- renderWidgetHostView_->PluginImeCompositionCompleted(
- base::SysNSStringToUTF16(composited_string), focusedPluginIdentifier_);
- pluginImeActive_ = NO;
- }
- return handled;
-}
-
-- (void)checkForPluginImeCancellation {
- if (pluginImeActive_ &&
- ![[ComplexTextInputPanel sharedComplexTextInputPanel] inComposition]) {
- renderWidgetHostView_->PluginImeCompositionCompleted(
- base::string16(), focusedPluginIdentifier_);
- pluginImeActive_ = NO;
- }
-}
-
// Overriding a NSResponder method to support application services.
- (id)validRequestorForSendType:(NSString*)sendType
@@ -3376,20 +3347,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
return requestor;
}
-- (void)viewWillStartLiveResize {
- [super viewWillStartLiveResize];
- RenderWidgetHostImpl* widget = renderWidgetHostView_->render_widget_host_;
- if (widget)
- widget->Send(new ViewMsg_SetInLiveResize(widget->GetRoutingID(), true));
-}
-
-- (void)viewDidEndLiveResize {
- [super viewDidEndLiveResize];
- RenderWidgetHostImpl* widget = renderWidgetHostView_->render_widget_host_;
- if (widget)
- widget->Send(new ViewMsg_SetInLiveResize(widget->GetRoutingID(), false));
-}
-
- (void)updateCursor:(NSCursor*)cursor {
if (currentCursor_ == cursor)
return;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index ac3cb9467f2..5cc1841dbd6 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/command_line.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/mac/sdk_forward_declarations.h"
@@ -18,15 +19,16 @@
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_view_mac_delegate.h"
+#include "content/public/common/content_switches.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_utils.h"
#include "content/test/test_render_view_host.h"
+#include "gpu/ipc/common/gpu_messages.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
@@ -77,6 +79,11 @@
if (!consumed)
unhandledWheelEventReceived_ = true;
}
+- (void)rendererHandledGestureScrollEvent:(const blink::WebGestureEvent&)event
+ consumed:(BOOL)consumed {
+ if (!consumed && event.type == blink::WebInputEvent::GestureScrollUpdate)
+ unhandledWheelEventReceived_ = true;
+}
- (void)touchesBeganWithEvent:(NSEvent*)event {}
- (void)touchesMovedWithEvent:(NSEvent*)event {}
- (void)touchesCancelledWithEvent:(NSEvent*)event {}
@@ -150,7 +157,9 @@ class MockRenderWidgetHostImpl : public RenderWidgetHostImpl {
MockRenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
RenderProcessHost* process,
int32_t routing_id)
- : RenderWidgetHostImpl(delegate, process, routing_id, false) {}
+ : RenderWidgetHostImpl(delegate, process, routing_id, false) {
+ set_renderer_initialized(true);
+ }
MOCK_METHOD0(Focus, void());
MOCK_METHOD0(Blur, void());
@@ -244,6 +253,19 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
RenderViewHostImplTestHarness::TearDown();
}
+ void SetupForWheelGestures(bool enable_wheel_gestures) {
+ CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWheelGestures));
+ CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableWheelGestures));
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ enable_wheel_gestures ? switches::kEnableWheelGestures
+ : switches::kDisableWheelGestures);
+ // Owned by its |cocoa_view()|, i.e. |rwhv_cocoa_|.
+ rwhv_mac_ = new RenderWidgetHostViewMac(rvh()->GetWidget(), false);
+ rwhv_cocoa_.reset([rwhv_mac_->cocoa_view() retain]);
+ }
+
void RecycleAndWait() {
pool_.Recycle();
base::MessageLoop::current()->RunUntilIdle();
@@ -726,17 +748,22 @@ TEST_F(RenderWidgetHostViewMacTest, UpdateCompositionMultilineCase) {
// firstRectForCharacterRange:actualRange] are handled in a sane manner if they
// arrive after the C++ RenderWidgetHostView is destroyed.
TEST_F(RenderWidgetHostViewMacTest, CompositionEventAfterDestroy) {
- // The test view isn't in an NSWindow to perform the final coordinate
- // conversion, so use an origin of 0,0, but verify the size.
const gfx::Rect composition_bounds(0, 0, 30, 40);
const gfx::Range range(0, 1);
rwhv_mac_->ImeCompositionRangeChanged(
range, std::vector<gfx::Rect>(1, composition_bounds));
NSRange actual_range = NSMakeRange(0, 0);
+
+ base::scoped_nsobject<CocoaTestHelperWindow> window(
+ [[CocoaTestHelperWindow alloc] init]);
+ [[window contentView] addSubview:rwhv_cocoa_];
+ [rwhv_cocoa_ setFrame:NSMakeRect(0, 0, 400, 400)];
+
NSRect rect = [rwhv_cocoa_ firstRectForCharacterRange:range.ToNSRange()
actualRange:&actual_range];
- EXPECT_NSEQ(NSMakeRect(0, 0, 30, 40), rect);
+ EXPECT_EQ(30, rect.size.width);
+ EXPECT_EQ(40, rect.size.height);
EXPECT_EQ(range, gfx::Range(actual_range));
DestroyHostViewRetainCocoaView();
@@ -754,6 +781,7 @@ TEST_F(RenderWidgetHostViewMacTest, BlurAndFocusOnSetActive) {
TestBrowserContext browser_context;
MockRenderProcessHost* process_host =
new MockRenderProcessHost(&browser_context);
+ process_host->Init();
// Owned by its |cocoa_view()|.
int32_t routing_id = process_host->GetNextRoutingID();
@@ -808,6 +836,7 @@ TEST_F(RenderWidgetHostViewMacTest, ScrollWheelEndEventDelivery) {
MockRenderWidgetHostImpl* host =
new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+ process_host->sink().ClearMessages();
// Send an initial wheel event with NSEventPhaseBegan to the view.
NSEvent* event1 = MockScrollWheelEventWithPhase(@selector(phaseBegan), 0);
@@ -837,6 +866,8 @@ TEST_F(RenderWidgetHostViewMacTest, IgnoreEmptyUnhandledWheelEvent) {
if (!base::mac::IsOSLionOrLater())
return;
+ SetupForWheelGestures(false);
+
// Initialize the view associated with a MockRenderWidgetHostImpl, rather than
// the MockRenderProcessHost that is set up by the test harness which mocks
// out |OnMessageReceived()|.
@@ -849,6 +880,7 @@ TEST_F(RenderWidgetHostViewMacTest, IgnoreEmptyUnhandledWheelEvent) {
MockRenderWidgetHostImpl* host =
new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+ process_host->sink().ClearMessages();
// Add a delegate to the view.
base::scoped_nsobject<MockRenderWidgetHostViewMacDelegate> view_delegate(
@@ -889,6 +921,75 @@ TEST_F(RenderWidgetHostViewMacTest, IgnoreEmptyUnhandledWheelEvent) {
host->ShutdownAndDestroyWidget(true);
}
+TEST_F(RenderWidgetHostViewMacTest,
+ IgnoreEmptyUnhandledWheelEventWithWheelGestures) {
+ // This tests Lion+ functionality, so don't run the test pre-Lion.
+ if (!base::mac::IsOSLionOrLater())
+ return;
+
+ SetupForWheelGestures(true);
+
+ // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
+ // the MockRenderProcessHost that is set up by the test harness which mocks
+ // out |OnMessageReceived()|.
+ TestBrowserContext browser_context;
+ MockRenderProcessHost* process_host =
+ new MockRenderProcessHost(&browser_context);
+ process_host->Init();
+ MockRenderWidgetHostDelegate delegate;
+ int32_t routing_id = process_host->GetNextRoutingID();
+ MockRenderWidgetHostImpl* host =
+ new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+ process_host->sink().ClearMessages();
+
+ // Add a delegate to the view.
+ base::scoped_nsobject<MockRenderWidgetHostViewMacDelegate> view_delegate(
+ [[MockRenderWidgetHostViewMacDelegate alloc] init]);
+ view->SetDelegate(view_delegate.get());
+
+ // Send an initial wheel event for scrolling by 3 lines.
+ NSEvent* event1 = MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
+ [view->cocoa_view() scrollWheel:event1];
+ ASSERT_EQ(1U, process_host->sink().message_count());
+ process_host->sink().ClearMessages();
+
+ // Indicate that the wheel event was unhandled.
+ InputEventAck unhandled_ack(blink::WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ scoped_ptr<IPC::Message> response1(
+ new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
+ host->OnMessageReceived(*response1);
+ ASSERT_EQ(2U, process_host->sink().message_count());
+ process_host->sink().ClearMessages();
+
+ InputEventAck unhandled_scroll_ack(blink::WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ scoped_ptr<IPC::Message> scroll_response1(
+ new InputHostMsg_HandleInputEvent_ACK(0, unhandled_scroll_ack));
+ host->OnMessageReceived(*scroll_response1);
+
+ // Check that the view delegate got an unhandled wheel event.
+ ASSERT_EQ(YES, view_delegate.get().unhandledWheelEventReceived);
+ view_delegate.get().unhandledWheelEventReceived = NO;
+
+ // Send another wheel event, this time for scrolling by 0 lines (empty event).
+ NSEvent* event2 = MockScrollWheelEventWithPhase(@selector(phaseChanged), 0);
+ [view->cocoa_view() scrollWheel:event2];
+ ASSERT_EQ(2U, process_host->sink().message_count());
+
+ // Indicate that the wheel event was also unhandled.
+ scoped_ptr<IPC::Message> response2(
+ new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
+ host->OnMessageReceived(*response2);
+
+ // Check that the view delegate ignored the empty unhandled wheel event.
+ ASSERT_EQ(NO, view_delegate.get().unhandledWheelEventReceived);
+
+ // Clean up.
+ host->ShutdownAndDestroyWidget(true);
+}
+
// Tests that when view initiated shutdown happens (i.e. RWHView is deleted
// before RWH), we clean up properly and don't leak the RWHVGuest.
TEST_F(RenderWidgetHostViewMacTest, GuestViewDoesNotLeak) {
@@ -896,6 +997,7 @@ TEST_F(RenderWidgetHostViewMacTest, GuestViewDoesNotLeak) {
TestBrowserContext browser_context;
MockRenderProcessHost* process_host =
new MockRenderProcessHost(&browser_context);
+ process_host->Init();
int32_t routing_id = process_host->GetNextRoutingID();
// Owned by its |cocoa_view()|.
@@ -938,6 +1040,7 @@ TEST_F(RenderWidgetHostViewMacTest, Background) {
TestBrowserContext browser_context;
MockRenderProcessHost* process_host =
new MockRenderProcessHost(&browser_context);
+ process_host->Init();
MockRenderWidgetHostDelegate delegate;
int32_t routing_id = process_host->GetNextRoutingID();
MockRenderWidgetHostImpl* host =
@@ -993,7 +1096,9 @@ class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
break;
}
DCHECK(message);
- base::Tuple<IPC::WebInputEventPointer, ui::LatencyInfo> data;
+ base::Tuple<IPC::WebInputEventPointer, ui::LatencyInfo,
+ InputEventDispatchType>
+ data;
InputMsg_HandleInputEvent::Read(message, &data);
IPC::WebInputEventPointer ipc_event = base::get<0>(data);
const blink::WebGestureEvent* gesture_event =
@@ -1020,6 +1125,7 @@ TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
MockRenderWidgetHostImpl* host =
new MockRenderWidgetHostImpl(&delegate, process_host_, routing_id);
RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
+ process_host_->sink().ClearMessages();
// We'll use this IPC message to ack events.
InputEventAck ack(blink::WebInputEvent::GesturePinchUpdate,
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mus.cc b/chromium/content/browser/renderer_host/render_widget_host_view_mus.cc
index 3cfdacf4c85..eb29bde8f99 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mus.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mus.cc
@@ -9,12 +9,12 @@
#include "build/build_config.h"
#include "components/mus/public/cpp/window.h"
#include "components/mus/public/cpp/window_tree_connection.h"
-#include "content/browser/mojo/mojo_shell_client_host.h"
+#include "content/browser/mojo/mojo_child_connection.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/render_widget_window_tree_client_factory.mojom.h"
#include "content/public/common/mojo_shell_connection.h"
-#include "mojo/shell/public/cpp/application_impl.h"
+#include "mojo/shell/public/cpp/connector.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
@@ -38,9 +38,8 @@ RenderWidgetHostViewMus::RenderWidgetHostViewMus(mus::Window* parent_window,
// Connect to the renderer, pass it a WindowTreeClient interface request
// and embed that client inside our mus window.
- std::string url = GetMojoApplicationInstanceURL(host_->GetProcess());
mojom::RenderWidgetWindowTreeClientFactoryPtr factory;
- MojoShellConnection::Get()->GetApplication()->ConnectToService(url, &factory);
+ GetMojoConnection(host_->GetProcess())->GetInterface(&factory);
mus::mojom::WindowTreeClientPtr window_tree_client;
factory->CreateWindowTreeClientForRenderWidget(
@@ -180,10 +179,6 @@ gfx::NativeViewAccessible RenderWidgetHostViewMus::GetNativeViewAccessible() {
return gfx::NativeViewAccessible();
}
-void RenderWidgetHostViewMus::MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) {
-}
-
void RenderWidgetHostViewMus::UpdateCursor(const WebCursor& cursor) {
// TODO(fsamuel): Implement cursors in Mus.
NOTIMPLEMENTED();
@@ -277,13 +272,6 @@ gfx::Rect RenderWidgetHostViewMus::GetBoundsInRootWindow() {
void RenderWidgetHostViewMus::SetActive(bool active) {
}
-void RenderWidgetHostViewMus::SetWindowVisibility(bool visible) {
- // TODO(fsamuel): Propagate visibility to Mus?
-}
-
-void RenderWidgetHostViewMus::WindowFrameChanged() {
-}
-
void RenderWidgetHostViewMus::ShowDefinitionForSelection() {
// TODO(fsamuel): Implement this on Mac.
}
@@ -305,12 +293,6 @@ bool RenderWidgetHostViewMus::IsSpeaking() const {
void RenderWidgetHostViewMus::StopSpeaking() {
// TODO(fsamuel): Implement this on Mac.
}
-
-bool RenderWidgetHostViewMus::PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) {
- return false;
-}
-
#endif // defined(OS_MACOSX)
void RenderWidgetHostViewMus::LockCompositingSurface() {
@@ -321,14 +303,4 @@ void RenderWidgetHostViewMus::UnlockCompositingSurface() {
NOTIMPLEMENTED();
}
-#if defined(OS_WIN)
-void RenderWidgetHostViewMus::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {}
-
-gfx::NativeViewId RenderWidgetHostViewMus::GetParentForWindowlessPlugin()
- const {
- return gfx::NativeViewId();
-}
-#endif
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mus.h b/chromium/content/browser/renderer_host/render_widget_host_view_mus.h
index 0db6d732fba..3a96b9f9b5b 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mus.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mus.h
@@ -65,7 +65,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMus : public RenderWidgetHostViewBase {
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
- void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
void UpdateCursor(const WebCursor& cursor) override;
void SetIsLoading(bool is_loading) override;
void TextInputStateChanged(
@@ -106,28 +105,16 @@ class CONTENT_EXPORT RenderWidgetHostViewMus : public RenderWidgetHostViewBase {
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
void SetActive(bool active) override;
- void SetWindowVisibility(bool visible) override;
- void WindowFrameChanged() override;
void ShowDefinitionForSelection() override;
bool SupportsSpeech() const override;
void SpeakSelection() override;
bool IsSpeaking() const override;
void StopSpeaking() override;
-
- // RenderWidgetHostViewBase implementation.
- bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) override;
#endif // defined(OS_MACOSX)
void LockCompositingSurface() override;
void UnlockCompositingSurface() override;
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) override;
- gfx::NativeViewId GetParentForWindowlessPlugin() const override;
-#endif
-
RenderWidgetHostImpl* host_;
aura::Window* aura_window_;
diff --git a/chromium/content/browser/compositor/resize_lock.cc b/chromium/content/browser/renderer_host/resize_lock.cc
index ddbc4437872..dca36fa8a07 100644
--- a/chromium/content/browser/compositor/resize_lock.cc
+++ b/chromium/content/browser/renderer_host/resize_lock.cc
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/renderer_host/resize_lock.h"
namespace content {
ResizeLock::ResizeLock(const gfx::Size new_size, bool defer_compositor_lock)
- : new_size_(new_size),
- defer_compositor_lock_(defer_compositor_lock) {
+ : new_size_(new_size), defer_compositor_lock_(defer_compositor_lock) {
if (!defer_compositor_lock_)
LockCompositor();
}
diff --git a/chromium/content/browser/compositor/resize_lock.h b/chromium/content/browser/renderer_host/resize_lock.h
index 8b4829785eb..fa8d963ccae 100644
--- a/chromium/content/browser/compositor/resize_lock.h
+++ b/chromium/content/browser/renderer_host/resize_lock.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_COMPOSITOR_RESIZE_LOCK_H_
-#define CONTENT_BROWSER_COMPOSITOR_RESIZE_LOCK_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_RESIZE_LOCK_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RESIZE_LOCK_H_
#include "base/macros.h"
#include "content/common/content_export.h"
@@ -34,4 +34,4 @@ class CONTENT_EXPORT ResizeLock {
} // namespace content
-#endif // CONTENT_BROWSER_COMPOSITOR_RESIZE_LOCK_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_RESIZE_LOCK_H_
diff --git a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
index 465ddbdc285..94a34b58d1b 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -27,18 +27,11 @@
#include "content/common/set_process_title.h"
#include "content/public/common/content_switches.h"
#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
-#include "third_party/WebKit/public/platform/linux/WebFontInfo.h"
-#include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/font_fallback_linux.h"
#include "ui/gfx/font_render_params.h"
-using blink::WebCString;
-using blink::WebFontInfo;
-using blink::WebUChar;
-using blink::WebUChar32;
-
namespace content {
namespace {
@@ -167,12 +160,12 @@ void SandboxIPCHandler::HandleRequestFromRenderer(int fd) {
}
int SandboxIPCHandler::FindOrAddPath(const SkString& path) {
- int count = paths_.count();
+ int count = paths_.size();
for (int i = 0; i < count; ++i) {
- if (path == *paths_[i])
+ if (path == paths_[i])
return i;
}
- *paths_.append() = new SkString(path);
+ paths_.emplace_back(path);
return count;
}
@@ -221,9 +214,9 @@ void SandboxIPCHandler::HandleFontOpenRequest(
uint32_t index;
if (!iter.ReadUInt32(&index))
return;
- if (index >= static_cast<uint32_t>(paths_.count()))
+ if (index >= static_cast<uint32_t>(paths_.size()))
return;
- const int result_fd = open(paths_[index]->c_str(), O_RDONLY);
+ const int result_fd = open(paths_[index].c_str(), O_RDONLY);
base::Pickle reply;
if (result_fd == -1) {
@@ -249,8 +242,7 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
// The other side of this call is
// content/common/child_process_sandbox_support_impl_linux.cc
- EnsureWebKitInitialized();
- WebUChar32 c;
+ UChar32 c;
if (!iter.ReadInt(&c))
return;
@@ -258,27 +250,17 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
if (!iter.ReadString(&preferred_locale))
return;
- blink::WebFallbackFont fallbackFont;
- WebFontInfo::fallbackFontForChar(c, preferred_locale.c_str(), &fallbackFont);
-
- int pathIndex = FindOrAddPath(SkString(fallbackFont.filename.data()));
- fallbackFont.fontconfigInterfaceId = pathIndex;
+ auto fallback_font = gfx::GetFallbackFontForChar(c, preferred_locale);
+ int fontconfig_interface_id =
+ FindOrAddPath(SkString(fallback_font.filename.data()));
base::Pickle reply;
- if (fallbackFont.name.data()) {
- reply.WriteString(fallbackFont.name.data());
- } else {
- reply.WriteString(std::string());
- }
- if (fallbackFont.filename.data()) {
- reply.WriteString(fallbackFont.filename.data());
- } else {
- reply.WriteString(std::string());
- }
- reply.WriteInt(fallbackFont.fontconfigInterfaceId);
- reply.WriteInt(fallbackFont.ttcIndex);
- reply.WriteBool(fallbackFont.isBold);
- reply.WriteBool(fallbackFont.isItalic);
+ reply.WriteString(fallback_font.name);
+ reply.WriteString(fallback_font.filename);
+ reply.WriteInt(fontconfig_interface_id);
+ reply.WriteInt(fallback_font.ttc_index);
+ reply.WriteBool(fallback_font.is_bold);
+ reply.WriteBool(fallback_font.is_italic);
SendRendererReply(fds, reply, -1);
}
@@ -297,8 +279,6 @@ void SandboxIPCHandler::HandleGetStyleForStrike(
return;
}
- EnsureWebKitInitialized();
-
gfx::FontRenderParamsQuery query;
query.families.push_back(family);
query.pixel_size = pixel_size;
@@ -434,21 +414,10 @@ void SandboxIPCHandler::SendRendererReply(
}
SandboxIPCHandler::~SandboxIPCHandler() {
- paths_.deleteAll();
- if (blink_platform_impl_)
- blink::shutdownWithoutV8();
-
if (IGNORE_EINTR(close(lifeline_fd_)) < 0)
PLOG(ERROR) << "close";
if (IGNORE_EINTR(close(browser_socket_)) < 0)
PLOG(ERROR) << "close";
}
-void SandboxIPCHandler::EnsureWebKitInitialized() {
- if (blink_platform_impl_)
- return;
- blink_platform_impl_.reset(new BlinkPlatformImpl);
- blink::initializeWithoutV8(blink_platform_impl_.get());
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/sandbox_ipc_linux.h b/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
index a11a8787237..f1a6bd5ea3a 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
+// https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md
#ifndef CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_LINUX_H_
#define CONTENT_BROWSER_RENDERER_HOST_SANDBOX_IPC_LINUX_H_
@@ -14,7 +14,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
#include "base/threading/simple_thread.h"
-#include "content/child/blink_platform_impl.h"
#include "skia/ext/skia_utils_base.h"
namespace content {
@@ -30,8 +29,6 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
void Run() override;
private:
- void EnsureWebKitInitialized();
-
int FindOrAddPath(const SkString& path);
void HandleRequestFromRenderer(int fd);
@@ -70,8 +67,7 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
const int lifeline_fd_;
const int browser_socket_;
- scoped_ptr<BlinkPlatformImpl> blink_platform_impl_;
- SkTDArray<SkString*> paths_;
+ std::vector<SkString> paths_;
DISALLOW_COPY_AND_ASSIGN(SandboxIPCHandler);
};
diff --git a/chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm b/chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm
index aa265fca27c..51cb7893d91 100644
--- a/chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm
+++ b/chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm
@@ -148,7 +148,6 @@ TEST_F(TextInputClientMacTest, TimeoutCharacterIndex) {
TEST_F(TextInputClientMacTest, NotFoundCharacterIndex) {
ScopedTestingThread thread(this);
const NSUInteger kPreviousValue = 42;
- const size_t kNotFoundValue = static_cast<size_t>(-1);
// Set an arbitrary value to ensure the index is not |NSNotFound|.
PostTask(FROM_HERE,
@@ -159,7 +158,7 @@ TEST_F(TextInputClientMacTest, NotFoundCharacterIndex) {
new TextInputClientMessageFilter(widget()->GetProcess()->GetID()));
scoped_ptr<IPC::Message> message(
new TextInputClientReplyMsg_GotCharacterIndexForPoint(
- widget()->GetRoutingID(), kNotFoundValue));
+ widget()->GetRoutingID(), UINT32_MAX));
// Set |WTF::notFound| to the index |kTaskDelayMs| after the previous
// setting.
PostTask(FROM_HERE,
diff --git a/chromium/content/browser/renderer_host/text_input_client_message_filter.h b/chromium/content/browser/renderer_host/text_input_client_message_filter.h
index 94000653867..95780b055d8 100644
--- a/chromium/content/browser/renderer_host/text_input_client_message_filter.h
+++ b/chromium/content/browser/renderer_host/text_input_client_message_filter.h
@@ -38,7 +38,7 @@ class CONTENT_EXPORT TextInputClientMessageFilter
void OnGotStringAtPoint(
const mac::AttributedStringCoder::EncodedString& encoded_string,
const gfx::Point& point);
- void OnGotCharacterIndexForPoint(size_t index);
+ void OnGotCharacterIndexForPoint(uint32_t index);
void OnGotFirstRectForRange(const gfx::Rect& rect);
void OnGotStringFromRange(
const mac::AttributedStringCoder::EncodedString& string,
diff --git a/chromium/content/browser/renderer_host/text_input_client_message_filter.mm b/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
index 34e9467826d..56dba28480d 100644
--- a/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
+++ b/chromium/content/browser/renderer_host/text_input_client_message_filter.mm
@@ -48,14 +48,17 @@ void TextInputClientMessageFilter::OnGotStringAtPoint(
service->GetStringAtPointReply(string, NSPointFromCGPoint(point.ToCGPoint()));
}
-void TextInputClientMessageFilter::OnGotCharacterIndexForPoint(size_t index) {
+void TextInputClientMessageFilter::OnGotCharacterIndexForPoint(uint32_t index) {
TextInputClientMac* service = TextInputClientMac::GetInstance();
// |index| could be WTF::notFound (-1) and its value is different from
// NSNotFound so we need to convert it.
- if (index == static_cast<size_t>(-1)) {
- index = NSNotFound;
+ size_t char_index;
+ if (index == UINT32_MAX) {
+ char_index = NSNotFound;
+ } else {
+ char_index = index;
}
- service->SetCharacterIndexAndSignal(index);
+ service->SetCharacterIndexAndSignal(char_index);
}
void TextInputClientMessageFilter::OnGotFirstRectForRange(
diff --git a/chromium/content/browser/renderer_host/web_input_event_aura.cc b/chromium/content/browser/renderer_host/web_input_event_aura.cc
index c4ed46155bd..59bc129469d 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura.cc
+++ b/chromium/content/browser/renderer_host/web_input_event_aura.cc
@@ -399,11 +399,11 @@ blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(
break;
}
- webkit_event.tiltX = roundf(event.pointer_details().tilt_x());
- webkit_event.tiltY = roundf(event.pointer_details().tilt_y());
- webkit_event.force = event.pointer_details().force();
+ webkit_event.tiltX = roundf(event.pointer_details().tilt_x);
+ webkit_event.tiltY = roundf(event.pointer_details().tilt_y);
+ webkit_event.force = event.pointer_details().force;
webkit_event.pointerType =
- EventPointerTypeToWebPointerType(event.pointer_details().pointer_type());
+ EventPointerTypeToWebPointerType(event.pointer_details().pointer_type);
return webkit_event;
}
@@ -428,11 +428,11 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;
- webkit_event.tiltX = roundf(event.pointer_details().tilt_x());
- webkit_event.tiltY = roundf(event.pointer_details().tilt_y());
- webkit_event.force = event.pointer_details().force();
+ webkit_event.tiltX = roundf(event.pointer_details().tilt_x);
+ webkit_event.tiltY = roundf(event.pointer_details().tilt_y);
+ webkit_event.force = event.pointer_details().force;
webkit_event.pointerType =
- EventPointerTypeToWebPointerType(event.pointer_details().pointer_type());
+ EventPointerTypeToWebPointerType(event.pointer_details().pointer_type);
return webkit_event;
}
diff --git a/chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc b/chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc
index 2d46dfb2e40..412c607eeeb 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc
+++ b/chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc
@@ -21,7 +21,7 @@
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/x11_types.h" // nogncheck
#endif
namespace content {
@@ -425,7 +425,7 @@ TEST(WebInputEventAuraTest, TestMakeWebMouseEvent) {
webkit_event.pointerType);
EXPECT_EQ(0, webkit_event.tiltX);
EXPECT_EQ(0, webkit_event.tiltY);
- EXPECT_FLOAT_EQ(0.0f, webkit_event.force);
+ EXPECT_TRUE(std::isnan(webkit_event.force));
EXPECT_EQ(123, webkit_event.x);
EXPECT_EQ(123, webkit_event.windowX);
EXPECT_EQ(321, webkit_event.y);
@@ -478,7 +478,7 @@ TEST(WebInputEventAuraTest, TestMakeWebMouseWheelEvent) {
webkit_event.pointerType);
EXPECT_EQ(0, webkit_event.tiltX);
EXPECT_EQ(0, webkit_event.tiltY);
- EXPECT_FLOAT_EQ(0.0f, webkit_event.force);
+ EXPECT_TRUE(std::isnan(webkit_event.force));
EXPECT_EQ(123, webkit_event.x);
EXPECT_EQ(123, webkit_event.windowX);
EXPECT_EQ(321, webkit_event.y);
@@ -503,7 +503,7 @@ TEST(WebInputEventAuraTest, TestMakeWebMouseWheelEvent) {
webkit_event.pointerType);
EXPECT_EQ(0, webkit_event.tiltX);
EXPECT_EQ(0, webkit_event.tiltY);
- EXPECT_FLOAT_EQ(0.0f, webkit_event.force);
+ EXPECT_TRUE(std::isnan(webkit_event.force));
EXPECT_EQ(123, webkit_event.x);
EXPECT_EQ(123, webkit_event.windowX);
EXPECT_EQ(321, webkit_event.y);
diff --git a/chromium/content/browser/renderer_host/websocket_blob_sender.cc b/chromium/content/browser/renderer_host/websocket_blob_sender.cc
new file mode 100644
index 00000000000..8fe56fd4deb
--- /dev/null
+++ b/chromium/content/browser/renderer_host/websocket_blob_sender.cc
@@ -0,0 +1,284 @@
+// 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 "content/browser/renderer_host/websocket_blob_sender.h"
+
+#include <algorithm>
+#include <ostream>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "content/browser/renderer_host/websocket_dispatcher_host.h"
+#include "content/browser/renderer_host/websocket_host.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/websockets/websocket_channel.h"
+#include "net/websockets/websocket_frame.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_reader.h"
+#include "storage/browser/blob/blob_storage_context.h"
+
+namespace content {
+
+namespace {
+
+using storage::BlobReader;
+using storage::BlobDataHandle;
+using storage::BlobStorageContext;
+
+// This must be smaller than the send quota high water mark or this class will
+// never send anything.
+const int kMinimumNonFinalFrameSize = 8 * 1024;
+
+// The IOBuffer has a fixed size for simplicity.
+const size_t kBufferSize = 128 * 1024;
+
+} // namespace
+
+// This is needed to make DCHECK_EQ(), etc. compile.
+std::ostream& operator<<(std::ostream& os, WebSocketBlobSender::State state) {
+ static const char* const kStateStrings[] = {
+ "NONE",
+ "READ_SIZE",
+ "READ_SIZE_COMPLETE",
+ "WAIT_FOR_QUOTA",
+ "WAIT_FOR_QUOTA_COMPLETE",
+ "READ",
+ "READ_COMPLETE",
+ };
+ if (state < WebSocketBlobSender::State::NONE ||
+ state > WebSocketBlobSender::State::READ_COMPLETE) {
+ return os << "Bad State (" << static_cast<int>(state) << ")";
+ }
+ return os << kStateStrings[static_cast<int>(state)];
+}
+
+WebSocketBlobSender::WebSocketBlobSender(scoped_ptr<Channel> channel)
+ : channel_(std::move(channel)) {}
+
+WebSocketBlobSender::~WebSocketBlobSender() {}
+
+int WebSocketBlobSender::Start(
+ const std::string& uuid,
+ uint64_t expected_size,
+ BlobStorageContext* context,
+ storage::FileSystemContext* file_system_context,
+ base::SingleThreadTaskRunner* file_task_runner,
+ net::WebSocketEventInterface::ChannelState* channel_state,
+ const net::CompletionCallback& callback) {
+ DCHECK(context);
+ DCHECK(channel_state);
+ DCHECK(!reader_);
+ scoped_ptr<storage::BlobDataHandle> data_handle(
+ context->GetBlobDataFromUUID(uuid));
+ if (!data_handle)
+ return net::ERR_INVALID_HANDLE;
+ reader_ = data_handle->CreateReader(file_system_context, file_task_runner);
+ expected_size_ = expected_size;
+ next_state_ = State::READ_SIZE;
+ int rv = DoLoop(net::OK, channel_state);
+ if (*channel_state == net::WebSocketEventInterface::CHANNEL_ALIVE &&
+ rv == net::ERR_IO_PENDING) {
+ callback_ = callback;
+ }
+ return rv;
+}
+
+void WebSocketBlobSender::OnNewSendQuota() {
+ if (next_state_ == State::WAIT_FOR_QUOTA)
+ DoLoopAsync(net::OK);
+ // |this| may be deleted.
+}
+
+uint64_t WebSocketBlobSender::ActualSize() const {
+ return reader_->total_size();
+}
+
+void WebSocketBlobSender::OnReadComplete(int rv) {
+ DCHECK_EQ(State::READ_COMPLETE, next_state_);
+ DoLoopAsync(rv);
+ // |this| may be deleted.
+}
+
+void WebSocketBlobSender::OnSizeCalculated(int rv) {
+ DCHECK_EQ(State::READ_SIZE_COMPLETE, next_state_);
+ DoLoopAsync(rv);
+ // |this| may be deleted.
+}
+
+int WebSocketBlobSender::DoLoop(int result,
+ Channel::ChannelState* channel_state) {
+ DCHECK_NE(State::NONE, next_state_);
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = State::NONE;
+ switch (state) {
+ case State::READ_SIZE:
+ DCHECK_EQ(net::OK, rv);
+ rv = DoReadSize();
+ break;
+
+ case State::READ_SIZE_COMPLETE:
+ rv = DoReadSizeComplete(rv);
+ break;
+
+ case State::WAIT_FOR_QUOTA:
+ DCHECK_EQ(net::OK, rv);
+ rv = DoWaitForQuota();
+ break;
+
+ case State::WAIT_FOR_QUOTA_COMPLETE:
+ DCHECK_EQ(net::OK, rv);
+ rv = DoWaitForQuotaComplete();
+ break;
+
+ case State::READ:
+ DCHECK_EQ(net::OK, rv);
+ rv = DoRead();
+ break;
+
+ case State::READ_COMPLETE:
+ rv = DoReadComplete(rv, channel_state);
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+ } while (*channel_state != net::WebSocketEventInterface::CHANNEL_DELETED &&
+ rv != net::ERR_IO_PENDING && next_state_ != State::NONE);
+ return rv;
+}
+
+void WebSocketBlobSender::DoLoopAsync(int result) {
+ Channel::ChannelState channel_state =
+ net::WebSocketEventInterface::CHANNEL_ALIVE;
+ int rv = DoLoop(result, &channel_state);
+ if (channel_state == net::WebSocketEventInterface::CHANNEL_ALIVE &&
+ rv != net::ERR_IO_PENDING) {
+ ResetAndReturn(&callback_).Run(rv);
+ }
+ // |this| may be deleted.
+}
+
+int WebSocketBlobSender::DoReadSize() {
+ next_state_ = State::READ_SIZE_COMPLETE;
+ // This use of base::Unretained() is safe because BlobReader cannot call the
+ // callback after it has been destroyed, and it is owned by this object.
+ BlobReader::Status status = reader_->CalculateSize(base::Bind(
+ &WebSocketBlobSender::OnSizeCalculated, base::Unretained(this)));
+ switch (status) {
+ case BlobReader::Status::NET_ERROR:
+ return reader_->net_error();
+
+ case BlobReader::Status::IO_PENDING:
+ return net::ERR_IO_PENDING;
+
+ case BlobReader::Status::DONE:
+ return net::OK;
+ }
+ NOTREACHED();
+ return net::ERR_UNEXPECTED;
+}
+
+int WebSocketBlobSender::DoReadSizeComplete(int result) {
+ if (result < 0)
+ return result;
+ if (reader_->total_size() != expected_size_)
+ return net::ERR_UPLOAD_FILE_CHANGED;
+ bytes_left_ = expected_size_;
+ // The result of the call to std::min() must fit inside a size_t because
+ // kBufferSize is type size_t.
+ size_t buffer_size = static_cast<size_t>(
+ std::min(bytes_left_, base::strict_cast<uint64_t>(kBufferSize)));
+ buffer_ = new net::IOBuffer(buffer_size);
+ next_state_ = State::WAIT_FOR_QUOTA;
+ return net::OK;
+}
+
+// The WAIT_FOR_QUOTA state has a self-edge; it will wait in this state until
+// there is enough quota to send some data.
+int WebSocketBlobSender::DoWaitForQuota() {
+ size_t quota = channel_->GetSendQuota();
+ if (kMinimumNonFinalFrameSize <= quota || bytes_left_ <= quota) {
+ next_state_ = State::WAIT_FOR_QUOTA_COMPLETE;
+ return net::OK;
+ }
+ next_state_ = State::WAIT_FOR_QUOTA;
+ return net::ERR_IO_PENDING;
+}
+
+// State::WAIT_FOR_QUOTA_COMPLETE exists just to give the state machine the
+// expected shape. It should be mostly optimised out.
+int WebSocketBlobSender::DoWaitForQuotaComplete() {
+ next_state_ = State::READ;
+ return net::OK;
+}
+
+int WebSocketBlobSender::DoRead() {
+ next_state_ = State::READ_COMPLETE;
+ size_t quota = channel_->GetSendQuota();
+ // |desired_bytes| must fit in a size_t because |quota| is of type
+ // size_t and so cannot be larger than its maximum value.
+ size_t desired_bytes =
+ static_cast<size_t>(std::min(bytes_left_, static_cast<uint64_t>(quota)));
+
+ // For simplicity this method only reads as many bytes as are currently
+ // needed.
+ size_t bytes_to_read = std::min(desired_bytes, kBufferSize);
+ int bytes_read = 0;
+ DCHECK(reader_);
+ DCHECK(buffer_);
+
+ // This use of base::Unretained is safe because the BlobReader object won't
+ // call the callback after it has been destroyed, and it belongs to this
+ // object.
+ BlobReader::Status status = reader_->Read(
+ buffer_.get(), bytes_to_read, &bytes_read,
+ base::Bind(&WebSocketBlobSender::OnReadComplete, base::Unretained(this)));
+
+ switch (status) {
+ case BlobReader::Status::NET_ERROR:
+ return reader_->net_error();
+
+ case BlobReader::Status::IO_PENDING:
+ return net::ERR_IO_PENDING;
+
+ case BlobReader::Status::DONE:
+ return bytes_read;
+ }
+ NOTREACHED();
+ return net::ERR_UNEXPECTED;
+}
+
+int WebSocketBlobSender::DoReadComplete(int result,
+ Channel::ChannelState* channel_state) {
+ if (result < 0)
+ return result;
+ DCHECK_GE(channel_->GetSendQuota(), static_cast<size_t>(result));
+ uint64_t bytes_read = static_cast<uint64_t>(result);
+ DCHECK_GE(bytes_left_, bytes_read);
+ bytes_left_ -= bytes_read;
+ bool fin = bytes_left_ == 0;
+ std::vector<char> data(buffer_->data(), buffer_->data() + bytes_read);
+ DCHECK(fin || data.size() > 0u) << "Non-final frames should be non-empty";
+ *channel_state = channel_->SendFrame(fin, data);
+ if (*channel_state == net::WebSocketEventInterface::CHANNEL_DELETED) {
+ // |this| is deleted.
+ return net::ERR_CONNECTION_RESET;
+ }
+
+ // It is important not to set next_state_ until after the call to SendFrame()
+ // because SendFrame() will sometimes call OnNewSendQuota() synchronously.
+ if (!fin)
+ next_state_ = State::WAIT_FOR_QUOTA;
+ return net::OK;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_blob_sender.h b/chromium/content/browser/renderer_host/websocket_blob_sender.h
new file mode 100644
index 00000000000..6dcfe7328a6
--- /dev/null
+++ b/chromium/content/browser/renderer_host/websocket_blob_sender.h
@@ -0,0 +1,139 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_WEBSOCKET_BLOB_SENDER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_WEBSOCKET_BLOB_SENDER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
+#include "net/websockets/websocket_event_interface.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace net {
+class IOBuffer;
+}
+
+namespace storage {
+class BlobReader;
+class BlobStorageContext;
+class FileSystemContext;
+}
+
+namespace content {
+
+class WebSocketHost;
+
+// Read the contents of a Blob and write it to a WebSocket. Single-use: a new
+// object must be created each time a Blob is sent. Destroying the object
+// cancels all pending operations.
+class CONTENT_EXPORT WebSocketBlobSender final {
+ public:
+ // An abstraction of the WebSocketChannel this object will send frames to.
+ class Channel {
+ public:
+ using ChannelState = net::WebSocketEventInterface::ChannelState;
+
+ Channel() {}
+ virtual ~Channel() {}
+
+ // The currently available quota for sending. It must not decrease without
+ // SendFrame() being called.
+ virtual size_t GetSendQuota() const = 0;
+
+ // Send a binary frame. |fin| is true for the final frame of the message.
+ // |data| is the contents of the frame. data.size() must be less than
+ // GetSendQuota(). If this call returns CHANNEL_DELETED, WebSocketBlobSender
+ // will assume that it has been deleted and return without calling any
+ // callbacks or accessing any other member data.
+ virtual ChannelState SendFrame(bool fin, const std::vector<char>& data) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Channel);
+ };
+
+ // |channel| will be destroyed when this object is.
+ explicit WebSocketBlobSender(scoped_ptr<Channel> channel);
+ ~WebSocketBlobSender();
+
+ // Checks that the blob identified by |uuid| exists, has the size
+ // |expected_size| and then starts sending it via |channel_|. Returns
+ // ERR_IO_PENDING to indicate that |callback| will be called later with the
+ // result. net::OK indicates synchronous success. Any other net error code
+ // indicates synchronous failure. This method may result in the destruction of
+ // the channel, in which case |*channel_state| will be set to CHANNEL_DELETED.
+ int Start(const std::string& uuid,
+ uint64_t expected_size,
+ storage::BlobStorageContext* context,
+ storage::FileSystemContext* file_system_context,
+ base::SingleThreadTaskRunner* file_task_runner,
+ net::WebSocketEventInterface::ChannelState* channel_state,
+ const net::CompletionCallback& callback);
+
+ // Sends more data if the object was waiting for quota and the new value of
+ // GetSendQuota() is large enough.
+ void OnNewSendQuota();
+
+ uint64_t expected_size() const { return expected_size_; }
+
+ // ActualSize() should only be called after completion: ie. Start() returned a
+ // value other than ERR_IO_PENDING or |callback_| has been called.
+ uint64_t ActualSize() const;
+
+ private:
+ // State proceeds through READ_SIZE and READ_SIZE_COMPLETE, then
+ // loops WAIT_FOR_QUOTA -> WAIT_FOR_QUOTA_COMPLETE -> READ
+ // -> READ_COMPLETE -> WAIT_FOR_QUOTA until the Blob is completely
+ // sent.
+ enum class State {
+ NONE = 0,
+ READ_SIZE,
+ READ_SIZE_COMPLETE,
+ WAIT_FOR_QUOTA,
+ WAIT_FOR_QUOTA_COMPLETE,
+ READ,
+ READ_COMPLETE,
+ };
+
+ // This is needed to make DCHECK_EQ(), etc. compile.
+ friend std::ostream& operator<<(std::ostream& os, State state);
+
+ void OnReadComplete(int rv);
+ void OnSizeCalculated(int rv);
+ // |channel_state| should point to CHANNEL_ALIVE when called. If it is
+ // CHANNEL_DELETED on return, the object has been deleted.
+ int DoLoop(int result, Channel::ChannelState* channel_state);
+ void DoLoopAsync(int result);
+ int DoReadSize();
+ int DoReadSizeComplete(int result);
+ int DoWaitForQuota();
+ int DoWaitForQuotaComplete();
+ int DoRead();
+ int DoReadComplete(int result, Channel::ChannelState* channel_state);
+
+ State next_state_ = State::NONE;
+ uint64_t expected_size_ = 0;
+ uint64_t bytes_left_ = 0;
+ net::CompletionCallback callback_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ scoped_ptr<storage::BlobReader> reader_;
+ const scoped_ptr<Channel> channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebSocketBlobSender);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_WEBSOCKET_BLOB_SENDER_H_
diff --git a/chromium/content/browser/renderer_host/websocket_blob_sender_unittest.cc b/chromium/content/browser/renderer_host/websocket_blob_sender_unittest.cc
new file mode 100644
index 00000000000..fe2f936d123
--- /dev/null
+++ b/chromium/content/browser/renderer_host/websocket_blob_sender_unittest.cc
@@ -0,0 +1,446 @@
+// 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 "content/browser/renderer_host/websocket_blob_sender.h"
+
+#include <string.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/task_runner.h"
+#include "base/time/time.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/public/browser/blob_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+const char kDummyUrl[] = "http://www.example.com/";
+const char kBanana[] = "banana";
+
+// This is small so that the tests do not waste too much time just copying bytes
+// around. But it has to be larger than kMinimumNonFinalFrameSize defined in
+// websocket_blob_sender.cc.
+const size_t kInitialQuota = 16 * 1024;
+
+using net::TestCompletionCallback;
+
+// A fake channel for testing. Records the contents of the message that was sent
+// through it. Quota is restricted, and is refreshed asynchronously in response
+// to calls to SendFrame().
+class FakeChannel : public WebSocketBlobSender::Channel {
+ public:
+ // |notify_new_quota| will be run asynchronously on the current MessageLoop
+ // every time GetSendQuota() increases.
+ FakeChannel() : weak_factory_(this) {}
+
+ // This method must be called before SendFrame() is.
+ void set_notify_new_quota(const base::Closure& notify_new_quota) {
+ notify_new_quota_ = notify_new_quota;
+ }
+
+ size_t GetSendQuota() const override { return current_send_quota_; }
+
+ ChannelState SendFrame(bool fin, const std::vector<char>& data) override {
+ ++frames_sent_;
+ EXPECT_FALSE(got_fin_);
+ if (fin)
+ got_fin_ = true;
+ EXPECT_LE(data.size(), current_send_quota_);
+ message_.insert(message_.end(), data.begin(), data.end());
+ current_send_quota_ -= data.size();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeChannel::RefreshQuota, weak_factory_.GetWeakPtr()));
+ return net::WebSocketEventInterface::CHANNEL_ALIVE;
+ }
+
+ bool got_fin() const { return got_fin_; }
+
+ int frames_sent() const { return frames_sent_; }
+
+ const std::vector<char>& message() const { return message_; }
+
+ private:
+ void RefreshQuota() {
+ if (current_send_quota_ == kInitialQuota)
+ return;
+ current_send_quota_ = kInitialQuota;
+ DCHECK(!notify_new_quota_.is_null());
+ notify_new_quota_.Run();
+ }
+
+ base::Closure notify_new_quota_;
+ size_t current_send_quota_ = kInitialQuota;
+ int frames_sent_ = 0;
+ bool got_fin_ = false;
+ std::vector<char> message_;
+ base::WeakPtrFactory<FakeChannel> weak_factory_;
+};
+
+class WebSocketBlobSenderTest : public ::testing::Test {
+ protected:
+ // The Windows implementation of net::FileStream::Context requires a real IO
+ // MessageLoop.
+ WebSocketBlobSenderTest()
+ : threads_(TestBrowserThreadBundle::IO_MAINLOOP),
+ chrome_blob_storage_context_(
+ ChromeBlobStorageContext::GetFor(&browser_context_)),
+ fake_channel_(nullptr),
+ sender_() {}
+ ~WebSocketBlobSenderTest() override {}
+
+ void SetUp() override {
+ // ChromeBlobStorageContext::GetFor() does some work asynchronously.
+ base::RunLoop().RunUntilIdle();
+ SetUpSender();
+ }
+
+ // This method can be overriden to use a different channel implementation.
+ virtual void SetUpSender() {
+ fake_channel_ = new FakeChannel;
+ sender_.reset(new WebSocketBlobSender(make_scoped_ptr(fake_channel_)));
+ fake_channel_->set_notify_new_quota(base::Bind(
+ &WebSocketBlobSender::OnNewSendQuota, base::Unretained(sender_.get())));
+ }
+
+ storage::BlobStorageContext* context() {
+ return chrome_blob_storage_context_->context();
+ }
+
+ storage::FileSystemContext* GetFileSystemContext() {
+ StoragePartition* partition = BrowserContext::GetStoragePartitionForSite(
+ &browser_context_, GURL(kDummyUrl));
+ return partition->GetFileSystemContext();
+ }
+
+ // |string| is copied.
+ scoped_ptr<BlobHandle> CreateMemoryBackedBlob(const char* string) {
+ scoped_ptr<BlobHandle> handle =
+ chrome_blob_storage_context_->CreateMemoryBackedBlob(string,
+ strlen(string));
+ EXPECT_TRUE(handle);
+ return handle;
+ }
+
+ // Call sender_.Start() with the other parameters filled in appropriately for
+ // this test fixture.
+ int Start(const std::string& uuid,
+ uint64_t expected_size,
+ const net::CompletionCallback& callback) {
+ net::WebSocketEventInterface::ChannelState channel_state =
+ net::WebSocketEventInterface::CHANNEL_ALIVE;
+ return sender_->Start(
+ uuid, expected_size, context(), GetFileSystemContext(),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+ &channel_state, callback);
+ }
+
+ void NotCalledCallbackImpl(int rv) {
+ ADD_FAILURE()
+ << "Callback that should not be called was called with argument " << rv;
+ }
+
+ net::CompletionCallback NotCalled() {
+ return base::Bind(&WebSocketBlobSenderTest::NotCalledCallbackImpl,
+ base::Unretained(this));
+ }
+
+ void ExpectOkAndQuit(base::RunLoop* run_loop, int result) {
+ EXPECT_EQ(net::OK, result);
+ run_loop->Quit();
+ }
+
+ net::CompletionCallback ExpectOkAndQuitCallback(base::RunLoop* run_loop) {
+ return base::Bind(&WebSocketBlobSenderTest::ExpectOkAndQuit,
+ base::Unretained(this), run_loop);
+ }
+
+ TestBrowserThreadBundle threads_;
+ TestBrowserContext browser_context_;
+ scoped_refptr<ChromeBlobStorageContext> chrome_blob_storage_context_;
+ // |fake_channel_| is owned by |sender_|.
+ FakeChannel* fake_channel_;
+ scoped_ptr<WebSocketBlobSender> sender_;
+};
+
+TEST_F(WebSocketBlobSenderTest, Construction) {}
+
+TEST_F(WebSocketBlobSenderTest, EmptyBlob) {
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob("");
+
+ // The APIs allow for this to be asynchronous but that is unlikely in
+ // practice.
+ int result = Start(handle->GetUUID(), UINT64_C(0), NotCalled());
+ // If this fails with result == -1, someone has changed the code to be
+ // asynchronous and this test should be adapted to match.
+ EXPECT_EQ(net::OK, result);
+ EXPECT_TRUE(fake_channel_->got_fin());
+ EXPECT_EQ(0U, fake_channel_->message().size());
+}
+
+TEST_F(WebSocketBlobSenderTest, SmallBlob) {
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(kBanana);
+
+ EXPECT_EQ(net::OK, Start(handle->GetUUID(), UINT64_C(6), NotCalled()));
+ EXPECT_TRUE(fake_channel_->got_fin());
+ EXPECT_EQ(1, fake_channel_->frames_sent());
+ EXPECT_EQ(std::vector<char>(kBanana, kBanana + 6), fake_channel_->message());
+}
+
+TEST_F(WebSocketBlobSenderTest, SizeMismatch) {
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(kBanana);
+
+ EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED,
+ Start(handle->GetUUID(), UINT64_C(5), NotCalled()));
+ EXPECT_EQ(0, fake_channel_->frames_sent());
+}
+
+TEST_F(WebSocketBlobSenderTest, InvalidUUID) {
+ EXPECT_EQ(net::ERR_INVALID_HANDLE,
+ Start("sandwich", UINT64_C(0), NotCalled()));
+}
+
+TEST_F(WebSocketBlobSenderTest, LargeMessage) {
+ std::string message(kInitialQuota + 10, 'a');
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(message.c_str());
+
+ base::RunLoop run_loop;
+ int rv = Start(handle->GetUUID(), message.size(),
+ ExpectOkAndQuitCallback(&run_loop));
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+ EXPECT_EQ(1, fake_channel_->frames_sent());
+ run_loop.Run();
+ EXPECT_EQ(2, fake_channel_->frames_sent());
+ EXPECT_TRUE(fake_channel_->got_fin());
+ std::vector<char> expected_message(message.begin(), message.end());
+ EXPECT_EQ(expected_message, fake_channel_->message());
+}
+
+// A message exactly equal to the available quota should be sent in one frame.
+TEST_F(WebSocketBlobSenderTest, ExactSizeMessage) {
+ std::string message(kInitialQuota, 'a');
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(message.c_str());
+
+ EXPECT_EQ(net::OK, Start(handle->GetUUID(), message.size(), NotCalled()));
+ EXPECT_EQ(1, fake_channel_->frames_sent());
+ EXPECT_TRUE(fake_channel_->got_fin());
+ std::vector<char> expected_message(message.begin(), message.end());
+ EXPECT_EQ(expected_message, fake_channel_->message());
+}
+
+// If the connection is closed while sending a message, the WebSocketBlobSender
+// object will be destroyed. It needs to handle this case without error.
+TEST_F(WebSocketBlobSenderTest, AbortedSend) {
+ std::string message(kInitialQuota + 10, 'a');
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(message.c_str());
+
+ int rv = Start(handle->GetUUID(), message.size(), NotCalled());
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+ sender_.reset();
+}
+
+// Invalid file-backed blob.
+TEST_F(WebSocketBlobSenderTest, InvalidFileBackedBlob) {
+ base::FilePath path(FILE_PATH_LITERAL(
+ "WebSocketBlobSentTest.InvalidFileBackedBlob.NonExistentFile"));
+ scoped_ptr<BlobHandle> handle =
+ chrome_blob_storage_context_->CreateFileBackedBlob(path, 0u, 32u,
+ base::Time::Now());
+ EXPECT_TRUE(handle);
+
+ TestCompletionCallback callback;
+ int rv =
+ callback.GetResult(Start(handle->GetUUID(), 5u, callback.callback()));
+ EXPECT_EQ(net::ERR_FILE_NOT_FOUND, rv);
+}
+
+// A test fixture that does the additional work necessary to create working
+// file-backed blobs.
+class WebSocketFileBackedBlobSenderTest : public WebSocketBlobSenderTest {
+ protected:
+ void SetUp() override {
+ WebSocketBlobSenderTest::SetUp();
+ // temp_dir_ is recursively deleted on destruction.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ }
+
+ void CreateFile(const std::string& contents,
+ const base::FilePath& path,
+ base::File::Info* info) {
+ ASSERT_EQ(contents.size(), static_cast<size_t>(base::WriteFile(
+ path, contents.data(), contents.size())));
+ ASSERT_TRUE(base::GetFileInfo(path, info));
+ }
+
+ scoped_ptr<BlobHandle> CreateFileBackedBlob(const std::string& contents) {
+ base::FilePath path = temp_dir_.path().AppendASCII("blob.dat");
+ base::File::Info info;
+ CreateFile(contents, path, &info);
+ if (HasFatalFailure())
+ return nullptr;
+ return chrome_blob_storage_context_->CreateFileBackedBlob(
+ path, 0u, contents.size(), info.last_modified);
+ }
+
+ base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(WebSocketFileBackedBlobSenderTest, EmptyBlob) {
+ scoped_ptr<BlobHandle> handle = CreateFileBackedBlob("");
+ ASSERT_TRUE(handle);
+
+ TestCompletionCallback callback;
+ int result = callback.GetResult(
+ Start(handle->GetUUID(), UINT64_C(0), callback.callback()));
+ EXPECT_EQ(net::OK, result);
+ EXPECT_TRUE(fake_channel_->got_fin());
+ EXPECT_EQ(0U, fake_channel_->message().size());
+}
+
+TEST_F(WebSocketFileBackedBlobSenderTest, SizeMismatch) {
+ scoped_ptr<BlobHandle> handle = CreateFileBackedBlob(kBanana);
+ ASSERT_TRUE(handle);
+
+ TestCompletionCallback callback;
+ int result = Start(handle->GetUUID(), UINT64_C(8), callback.callback());
+ // This test explicitly aims to test the asynchronous code path, otherwise it
+ // would be identical to the other SizeMismatch test above.
+ EXPECT_EQ(net::ERR_IO_PENDING, result);
+ EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, callback.WaitForResult());
+ EXPECT_EQ(0, fake_channel_->frames_sent());
+}
+
+TEST_F(WebSocketFileBackedBlobSenderTest, LargeMessage) {
+ std::string message = "the green potato had lunch with the angry cat. ";
+ while (message.size() <= kInitialQuota) {
+ message = message + message;
+ }
+ scoped_ptr<BlobHandle> handle = CreateFileBackedBlob(message);
+ ASSERT_TRUE(handle);
+
+ TestCompletionCallback callback;
+ int result = Start(handle->GetUUID(), message.size(), callback.callback());
+ EXPECT_EQ(net::OK, callback.GetResult(result));
+ std::vector<char> expected_message(message.begin(), message.end());
+ EXPECT_EQ(expected_message, fake_channel_->message());
+}
+
+// The WebSocketBlobSender needs to handle a connection close while doing file
+// IO cleanly.
+TEST_F(WebSocketFileBackedBlobSenderTest, Aborted) {
+ scoped_ptr<BlobHandle> handle = CreateFileBackedBlob(kBanana);
+
+ int rv = Start(handle->GetUUID(), UINT64_C(6), NotCalled());
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+ sender_.reset();
+}
+
+class DeletingFakeChannel : public WebSocketBlobSender::Channel {
+ public:
+ explicit DeletingFakeChannel(
+ scoped_ptr<WebSocketBlobSender>* sender_to_delete)
+ : sender_(sender_to_delete) {}
+
+ size_t GetSendQuota() const override { return kInitialQuota; }
+
+ ChannelState SendFrame(bool fin, const std::vector<char>& data) override {
+ sender_->reset();
+ // |this| is deleted here.
+ return net::WebSocketEventInterface::CHANNEL_DELETED;
+ }
+
+ private:
+ scoped_ptr<WebSocketBlobSender>* sender_;
+};
+
+class WebSocketBlobSenderDeletingTest : public WebSocketBlobSenderTest {
+ protected:
+ void SetUpSender() override {
+ sender_.reset(new WebSocketBlobSender(
+ make_scoped_ptr(new DeletingFakeChannel(&sender_))));
+ }
+};
+
+// This test only does something useful when run under AddressSanitizer or a
+// similar tool that can detect use-after-free bugs.
+TEST_F(WebSocketBlobSenderDeletingTest, SenderDeleted) {
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(kBanana);
+
+ EXPECT_EQ(net::ERR_CONNECTION_RESET,
+ Start(handle->GetUUID(), UINT64_C(6), NotCalled()));
+ EXPECT_FALSE(sender_);
+}
+
+// SendFrame() calls OnSendNewQuota() synchronously while filling the operating
+// system's socket write buffer. The purpose of this Channel implementation is
+// to verify that the synchronous case works correctly.
+class SynchronousFakeChannel : public WebSocketBlobSender::Channel {
+ public:
+ // This method must be called before SendFrame() is.
+ void set_notify_new_quota(const base::Closure& notify_new_quota) {
+ notify_new_quota_ = notify_new_quota;
+ }
+
+ size_t GetSendQuota() const override { return kInitialQuota; }
+
+ ChannelState SendFrame(bool fin, const std::vector<char>& data) override {
+ message_.insert(message_.end(), data.begin(), data.end());
+ notify_new_quota_.Run();
+ return net::WebSocketEventInterface::CHANNEL_ALIVE;
+ }
+
+ const std::vector<char>& message() const { return message_; }
+
+ private:
+ base::Closure notify_new_quota_;
+ std::vector<char> message_;
+};
+
+class WebSocketBlobSenderSynchronousTest : public WebSocketBlobSenderTest {
+ protected:
+ void SetUpSender() override {
+ synchronous_fake_channel_ = new SynchronousFakeChannel;
+ sender_.reset(
+ new WebSocketBlobSender(make_scoped_ptr(synchronous_fake_channel_)));
+ synchronous_fake_channel_->set_notify_new_quota(base::Bind(
+ &WebSocketBlobSender::OnNewSendQuota, base::Unretained(sender_.get())));
+ }
+
+ SynchronousFakeChannel* synchronous_fake_channel_ = nullptr;
+};
+
+TEST_F(WebSocketBlobSenderSynchronousTest, LargeMessage) {
+ std::string message(kInitialQuota + 10, 'a');
+ scoped_ptr<BlobHandle> handle = CreateMemoryBackedBlob(message.c_str());
+
+ int rv = Start(handle->GetUUID(), message.size(), NotCalled());
+ EXPECT_EQ(net::OK, rv);
+ std::vector<char> expected_message(message.begin(), message.end());
+ EXPECT_EQ(expected_message, synchronous_fake_channel_->message());
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc b/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
index 0cdf66383a5..e7049004b32 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <algorithm>
#include <string>
#include <vector>
@@ -15,6 +16,7 @@
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/renderer_host/websocket_host.h"
#include "content/common/websocket_messages.h"
@@ -35,7 +37,9 @@ const int kMaxPendingWebSocketConnections = 255;
WebSocketDispatcherHost::WebSocketDispatcherHost(
int process_id,
- const GetRequestContextCallback& get_context_callback)
+ const GetRequestContextCallback& get_context_callback,
+ ChromeBlobStorageContext* blob_storage_context,
+ StoragePartition* storage_partition)
: BrowserMessageFilter(WebSocketMsgStart),
process_id_(process_id),
get_context_callback_(get_context_callback),
@@ -46,7 +50,9 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
num_current_succeeded_connections_(0),
num_previous_succeeded_connections_(0),
num_current_failed_connections_(0),
- num_previous_failed_connections_(0) {}
+ num_previous_failed_connections_(0),
+ blob_storage_context_(blob_storage_context),
+ storage_partition_(storage_partition) {}
WebSocketDispatcherHost::WebSocketDispatcherHost(
int process_id,
@@ -60,7 +66,8 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
num_current_succeeded_connections_(0),
num_previous_succeeded_connections_(0),
num_current_failed_connections_(0),
- num_previous_failed_connections_(0) {}
+ num_previous_failed_connections_(0),
+ storage_partition_(nullptr) {}
WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(
int routing_id,
@@ -72,6 +79,7 @@ WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(
bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
switch (message.type()) {
case WebSocketHostMsg_AddChannelRequest::ID:
+ case WebSocketHostMsg_SendBlob::ID:
case WebSocketMsg_SendFrame::ID:
case WebSocketMsg_FlowControl::ID:
case WebSocketMsg_DropChannel::ID:
@@ -95,9 +103,10 @@ bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
return true; // We handled the message (by ignoring it).
}
if (num_pending_connections_ >= kMaxPendingWebSocketConnections) {
- if(!Send(new WebSocketMsg_NotifyFailure(routing_id,
- "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES"
- ))) {
+ if (!Send(new WebSocketMsg_NotifyFailure(
+ routing_id,
+ "Error in connection establishment: "
+ "net::ERR_INSUFFICIENT_RESOURCES"))) {
DVLOG(1) << "Sending of message type "
<< "WebSocketMsg_NotifyFailure failed.";
}
@@ -127,6 +136,12 @@ bool WebSocketDispatcherHost::CanReadRawCookies() const {
return policy->CanReadRawCookies(process_id_);
}
+storage::BlobStorageContext* WebSocketDispatcherHost::blob_storage_context()
+ const {
+ DCHECK(blob_storage_context_);
+ return blob_storage_context_->context();
+}
+
WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const {
WebSocketHostTable::const_iterator it = hosts_.find(routing_id);
return it == hosts_.end() ? NULL : it->second;
@@ -202,6 +217,10 @@ WebSocketHostState WebSocketDispatcherHost::NotifyFailure(
return WEBSOCKET_HOST_DELETED;
}
+WebSocketHostState WebSocketDispatcherHost::BlobSendComplete(int routing_id) {
+ return SendOrDrop(new WebSocketMsg_BlobSendComplete(routing_id));
+}
+
WebSocketHostState WebSocketDispatcherHost::DoDropChannel(
int routing_id,
bool was_clean,
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
index 56c5f3aaa5d..5d5c804ddf3 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
@@ -13,6 +13,7 @@
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "content/common/content_export.h"
@@ -23,8 +24,14 @@ namespace net {
class URLRequestContext;
} // namespace net
+namespace storage {
+class BlobStorageContext;
+}
+
namespace content {
+class ChromeBlobStorageContext;
+class StoragePartition;
struct WebSocketHandshakeRequest;
struct WebSocketHandshakeResponse;
class WebSocketHost;
@@ -49,9 +56,10 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
WEBSOCKET_HOST_DELETED
};
- WebSocketDispatcherHost(
- int process_id,
- const GetRequestContextCallback& get_context_callback);
+ WebSocketDispatcherHost(int process_id,
+ const GetRequestContextCallback& get_context_callback,
+ ChromeBlobStorageContext* blob_storage_context,
+ StoragePartition* storage_partition);
// BrowserMessageFilter:
bool OnMessageReceived(const IPC::Message& message) override;
@@ -96,6 +104,8 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
int routing_id,
const std::string& message) WARN_UNUSED_RESULT;
+ WebSocketHostState BlobSendComplete(int routing_id);
+
// Sends a WebSocketMsg_DropChannel IPC and deletes and unregisters the
// channel.
WebSocketHostState DoDropChannel(int routing_id,
@@ -109,6 +119,13 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
int render_process_id() const { return process_id_; }
+ // Returns a BlobStorageContext associated with this object's render process.
+ // The pointer will be valid for as long this object is.
+ storage::BlobStorageContext* blob_storage_context() const;
+
+ // Returns the StoragePartition associated with this render process.
+ StoragePartition* storage_partition() const { return storage_partition_; }
+
protected:
// For testing. Specify a factory method that creates mock version of
// WebSocketHost.
@@ -181,6 +198,12 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
int64_t num_current_failed_connections_;
int64_t num_previous_failed_connections_;
+ // Needed to read from blobs for browser-side blob sending.
+ const scoped_refptr<const ChromeBlobStorageContext> blob_storage_context_;
+
+ // Needed to access to the StoragePartition for browser-side blob sending.
+ StoragePartition* const storage_partition_;
+
DISALLOW_COPY_AND_ASSIGN(WebSocketDispatcherHost);
};
diff --git a/chromium/content/browser/renderer_host/websocket_host.cc b/chromium/content/browser/renderer_host/websocket_host.cc
index 5551e9643bf..88c333a77e9 100644
--- a/chromium/content/browser/renderer_host/websocket_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_host.cc
@@ -4,20 +4,29 @@
#include "content/browser/renderer_host/websocket_host.h"
+#include <inttypes.h>
#include <utility>
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/renderer_host/websocket_blob_sender.h"
#include "content/browser/renderer_host/websocket_dispatcher_host.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/common/websocket_messages.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/storage_partition.h"
#include "ipc/ipc_message_macros.h"
+#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -86,12 +95,41 @@ ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) {
return static_cast<ChannelState>(host_state);
}
+// Implementation of WebSocketBlobSender::Channel
+class SendChannelImpl final : public WebSocketBlobSender::Channel {
+ public:
+ explicit SendChannelImpl(net::WebSocketChannel* channel)
+ : channel_(channel) {}
+
+ // Implementation of WebSocketBlobSender::Channel
+ size_t GetSendQuota() const override {
+ return static_cast<size_t>(channel_->current_send_quota());
+ }
+
+ ChannelState SendFrame(bool fin, const std::vector<char>& data) override {
+ int opcode = first_frame_ ? net::WebSocketFrameHeader::kOpCodeBinary
+ : net::WebSocketFrameHeader::kOpCodeContinuation;
+ first_frame_ = false;
+ return channel_->SendFrame(fin, opcode, data);
+ }
+
+ private:
+ net::WebSocketChannel* channel_;
+ bool first_frame_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(SendChannelImpl);
+};
+
+} // namespace
+
// Implementation of net::WebSocketEventInterface. Receives events from our
// WebSocketChannel object. Each event is translated to an IPC and sent to the
// renderer or child process via WebSocketDispatcherHost.
-class WebSocketEventHandler : public net::WebSocketEventInterface {
+class WebSocketHost::WebSocketEventHandler final
+ : public net::WebSocketEventInterface {
public:
WebSocketEventHandler(WebSocketDispatcherHost* dispatcher,
+ WebSocketHost* host,
int routing_id,
int render_frame_id);
~WebSocketEventHandler() override;
@@ -120,7 +158,7 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
bool fatal) override;
private:
- class SSLErrorHandlerDelegate : public SSLErrorHandler::Delegate {
+ class SSLErrorHandlerDelegate final : public SSLErrorHandler::Delegate {
public:
SSLErrorHandlerDelegate(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks);
@@ -140,6 +178,7 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
};
WebSocketDispatcherHost* const dispatcher_;
+ WebSocketHost* const host_;
const int routing_id_;
const int render_frame_id_;
scoped_ptr<SSLErrorHandlerDelegate> ssl_error_handler_delegate_;
@@ -147,20 +186,21 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler);
};
-WebSocketEventHandler::WebSocketEventHandler(
+WebSocketHost::WebSocketEventHandler::WebSocketEventHandler(
WebSocketDispatcherHost* dispatcher,
+ WebSocketHost* host,
int routing_id,
int render_frame_id)
: dispatcher_(dispatcher),
+ host_(host),
routing_id_(routing_id),
- render_frame_id_(render_frame_id) {
-}
+ render_frame_id_(render_frame_id) {}
-WebSocketEventHandler::~WebSocketEventHandler() {
+WebSocketHost::WebSocketEventHandler::~WebSocketEventHandler() {
DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_;
}
-ChannelState WebSocketEventHandler::OnAddChannelResponse(
+ChannelState WebSocketHost::WebSocketEventHandler::OnAddChannelResponse(
const std::string& selected_protocol,
const std::string& extensions) {
DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse"
@@ -172,7 +212,7 @@ ChannelState WebSocketEventHandler::OnAddChannelResponse(
routing_id_, selected_protocol, extensions));
}
-ChannelState WebSocketEventHandler::OnDataFrame(
+ChannelState WebSocketHost::WebSocketEventHandler::OnDataFrame(
bool fin,
net::WebSocketFrameHeader::OpCode type,
const std::vector<char>& data) {
@@ -180,27 +220,31 @@ ChannelState WebSocketEventHandler::OnDataFrame(
<< " routing_id=" << routing_id_ << " fin=" << fin
<< " type=" << type << " data is " << data.size() << " bytes";
- return StateCast(dispatcher_->SendFrame(
- routing_id_, fin, OpCodeToMessageType(type), data));
+ return StateCast(dispatcher_->SendFrame(routing_id_, fin,
+ OpCodeToMessageType(type), data));
}
-ChannelState WebSocketEventHandler::OnClosingHandshake() {
+ChannelState WebSocketHost::WebSocketEventHandler::OnClosingHandshake() {
DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake"
<< " routing_id=" << routing_id_;
return StateCast(dispatcher_->NotifyClosingHandshake(routing_id_));
}
-ChannelState WebSocketEventHandler::OnFlowControl(int64_t quota) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnFlowControl(
+ int64_t quota) {
DVLOG(3) << "WebSocketEventHandler::OnFlowControl"
<< " routing_id=" << routing_id_ << " quota=" << quota;
+ if (host_->blob_sender_)
+ host_->blob_sender_->OnNewSendQuota();
return StateCast(dispatcher_->SendFlowControl(routing_id_, quota));
}
-ChannelState WebSocketEventHandler::OnDropChannel(bool was_clean,
- uint16_t code,
- const std::string& reason) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnDropChannel(
+ bool was_clean,
+ uint16_t code,
+ const std::string& reason) {
DVLOG(3) << "WebSocketEventHandler::OnDropChannel"
<< " routing_id=" << routing_id_ << " was_clean=" << was_clean
<< " code=" << code << " reason=\"" << reason << "\"";
@@ -209,15 +253,15 @@ ChannelState WebSocketEventHandler::OnDropChannel(bool was_clean,
dispatcher_->DoDropChannel(routing_id_, was_clean, code, reason));
}
-ChannelState WebSocketEventHandler::OnFailChannel(const std::string& message) {
+ChannelState WebSocketHost::WebSocketEventHandler::OnFailChannel(
+ const std::string& message) {
DVLOG(3) << "WebSocketEventHandler::OnFailChannel"
- << " routing_id=" << routing_id_
- << " message=\"" << message << "\"";
+ << " routing_id=" << routing_id_ << " message=\"" << message << "\"";
return StateCast(dispatcher_->NotifyFailure(routing_id_, message));
}
-ChannelState WebSocketEventHandler::OnStartOpeningHandshake(
+ChannelState WebSocketHost::WebSocketEventHandler::OnStartOpeningHandshake(
scoped_ptr<net::WebSocketHandshakeRequestInfo> request) {
bool should_send = dispatcher_->CanReadRawCookies();
DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake "
@@ -237,11 +281,11 @@ ChannelState WebSocketEventHandler::OnStartOpeningHandshake(
request->headers.ToString();
request_to_pass.request_time = request->request_time;
- return StateCast(dispatcher_->NotifyStartOpeningHandshake(routing_id_,
- request_to_pass));
+ return StateCast(
+ dispatcher_->NotifyStartOpeningHandshake(routing_id_, request_to_pass));
}
-ChannelState WebSocketEventHandler::OnFinishOpeningHandshake(
+ChannelState WebSocketHost::WebSocketEventHandler::OnFinishOpeningHandshake(
scoped_ptr<net::WebSocketHandshakeResponseInfo> response) {
bool should_send = dispatcher_->CanReadRawCookies();
DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
@@ -254,7 +298,7 @@ ChannelState WebSocketEventHandler::OnFinishOpeningHandshake(
response_to_pass.url.Swap(&response->url);
response_to_pass.status_code = response->status_code;
response_to_pass.status_text.swap(response->status_text);
- void* iter = NULL;
+ size_t iter = 0;
std::string name, value;
while (response->headers->EnumerateHeaderLines(&iter, &name, &value))
response_to_pass.headers.push_back(std::make_pair(name, value));
@@ -263,11 +307,11 @@ ChannelState WebSocketEventHandler::OnFinishOpeningHandshake(
response->headers->raw_headers());
response_to_pass.response_time = response->response_time;
- return StateCast(dispatcher_->NotifyFinishOpeningHandshake(routing_id_,
- response_to_pass));
+ return StateCast(
+ dispatcher_->NotifyFinishOpeningHandshake(routing_id_, response_to_pass));
}
-ChannelState WebSocketEventHandler::OnSSLCertificateError(
+ChannelState WebSocketHost::WebSocketEventHandler::OnSSLCertificateError(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
const GURL& url,
const net::SSLInfo& ssl_info,
@@ -284,20 +328,21 @@ ChannelState WebSocketEventHandler::OnSSLCertificateError(
return WebSocketEventInterface::CHANNEL_ALIVE;
}
-WebSocketEventHandler::SSLErrorHandlerDelegate::SSLErrorHandlerDelegate(
- scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks)
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ SSLErrorHandlerDelegate(
+ scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks)
: callbacks_(std::move(callbacks)), weak_ptr_factory_(this) {}
-WebSocketEventHandler::SSLErrorHandlerDelegate::~SSLErrorHandlerDelegate() {}
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ ~SSLErrorHandlerDelegate() {}
base::WeakPtr<SSLErrorHandler::Delegate>
-WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
+WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
- int error,
- const net::SSLInfo* ssl_info) {
+void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ CancelSSLRequest(int error, const net::SSLInfo* ssl_info) {
DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest"
<< " error=" << error
<< " cert_status=" << (ssl_info ? ssl_info->cert_status
@@ -305,13 +350,12 @@ void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
callbacks_->CancelSSLRequest(error, ssl_info);
}
-void WebSocketEventHandler::SSLErrorHandlerDelegate::ContinueSSLRequest() {
+void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::
+ ContinueSSLRequest() {
DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest";
callbacks_->ContinueSSLRequest();
}
-} // namespace
-
WebSocketHost::WebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
net::URLRequestContext* url_request_context,
@@ -337,6 +381,7 @@ bool WebSocketHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebSocketHost, message)
IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest, OnAddChannelRequest)
+ IPC_MESSAGE_HANDLER(WebSocketHostMsg_SendBlob, OnSendBlob)
IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnSendFrame)
IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnFlowControl)
IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnDropChannel)
@@ -383,7 +428,8 @@ void WebSocketHost::AddChannel(
DCHECK(!channel_);
scoped_ptr<net::WebSocketEventInterface> event_interface(
- new WebSocketEventHandler(dispatcher_, routing_id_, render_frame_id));
+ new WebSocketEventHandler(dispatcher_, this, routing_id_,
+ render_frame_id));
channel_.reset(new net::WebSocketChannel(std::move(event_interface),
url_request_context_));
@@ -404,6 +450,41 @@ void WebSocketHost::AddChannel(
// |this| may have been deleted here.
}
+void WebSocketHost::OnSendBlob(const std::string& uuid,
+ uint64_t expected_size) {
+ DVLOG(3) << "WebSocketHost::OnSendBlob"
+ << " routing_id=" << routing_id_ << " uuid=" << uuid
+ << " expected_size=" << expected_size;
+
+ DCHECK(channel_);
+ if (blob_sender_) {
+ bad_message::ReceivedBadMessage(
+ dispatcher_, bad_message::WSH_SEND_BLOB_DURING_BLOB_SEND);
+ return;
+ }
+ blob_sender_.reset(new WebSocketBlobSender(
+ make_scoped_ptr(new SendChannelImpl(channel_.get()))));
+ StoragePartition* partition = dispatcher_->storage_partition();
+ storage::FileSystemContext* file_system_context =
+ partition->GetFileSystemContext();
+
+ net::WebSocketEventInterface::ChannelState channel_state =
+ net::WebSocketEventInterface::CHANNEL_ALIVE;
+
+ // This use of base::Unretained is safe because the WebSocketBlobSender object
+ // is owned by this object and will not call it back after destruction.
+ int rv = blob_sender_->Start(
+ uuid, expected_size, dispatcher_->blob_storage_context(),
+ file_system_context,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
+ &channel_state,
+ base::Bind(&WebSocketHost::BlobSendComplete, base::Unretained(this)));
+ if (channel_state == net::WebSocketEventInterface::CHANNEL_ALIVE &&
+ rv != net::ERR_IO_PENDING)
+ BlobSendComplete(rv);
+ // |this| may be destroyed here.
+}
+
void WebSocketHost::OnSendFrame(bool fin,
WebSocketMessageType type,
const std::vector<char>& data) {
@@ -412,6 +493,11 @@ void WebSocketHost::OnSendFrame(bool fin,
<< " type=" << type << " data is " << data.size() << " bytes";
DCHECK(channel_);
+ if (blob_sender_) {
+ bad_message::ReceivedBadMessage(
+ dispatcher_, bad_message::WSH_SEND_FRAME_DURING_BLOB_SEND);
+ return;
+ }
channel_->SendFrame(fin, MessageTypeToOpCode(type), data);
}
@@ -441,16 +527,52 @@ void WebSocketHost::OnDropChannel(bool was_clean,
// WebSocketChannel is not yet created due to the delay introduced by
// per-renderer WebSocket throttling.
WebSocketDispatcherHost::WebSocketHostState result =
- dispatcher_->DoDropChannel(routing_id_,
- false,
- net::kWebSocketErrorAbnormalClosure,
- "");
+ dispatcher_->DoDropChannel(routing_id_, false,
+ net::kWebSocketErrorAbnormalClosure, "");
DCHECK_EQ(WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED, result);
return;
}
+ blob_sender_.reset();
// TODO(yhirano): Handle |was_clean| appropriately.
channel_->StartClosingHandshake(code, reason);
}
+void WebSocketHost::BlobSendComplete(int result) {
+ DVLOG(3) << "WebSocketHost::BlobSendComplete"
+ << " routing_id=" << routing_id_
+ << " result=" << net::ErrorToString(result);
+
+ // All paths through this method must reset blob_sender_, so take ownership
+ // at the beginning.
+ scoped_ptr<WebSocketBlobSender> blob_sender(std::move(blob_sender_));
+ switch (result) {
+ case net::OK:
+ ignore_result(dispatcher_->BlobSendComplete(routing_id_));
+ // |this| may be destroyed here.
+ return;
+
+ case net::ERR_UPLOAD_FILE_CHANGED: {
+ uint64_t expected_size = blob_sender->expected_size();
+ uint64_t actual_size = blob_sender->ActualSize();
+ if (expected_size != actual_size) {
+ ignore_result(dispatcher_->NotifyFailure(
+ routing_id_,
+ base::StringPrintf("Blob size mismatch; renderer size = %" PRIu64
+ ", browser size = %" PRIu64,
+ expected_size, actual_size)));
+ // |this| is destroyed here.
+ return;
+ } // else fallthrough
+ }
+
+ default:
+ ignore_result(dispatcher_->NotifyFailure(
+ routing_id_,
+ "Failed to load Blob: error code = " + net::ErrorToString(result)));
+ // |this| is destroyed here.
+ return;
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_host.h b/chromium/content/browser/renderer_host/websocket_host.h
index efdc9d1bd00..e95f65c31f4 100644
--- a/chromium/content/browser/renderer_host/websocket_host.h
+++ b/chromium/content/browser/renderer_host/websocket_host.h
@@ -34,6 +34,7 @@ class Message;
namespace content {
+class WebSocketBlobSender;
class WebSocketDispatcherHost;
// Host of net::WebSocketChannel. The lifetime of an instance of this class is
@@ -60,6 +61,8 @@ class CONTENT_EXPORT WebSocketHost {
void OnHandshakeSucceeded() { handshake_succeeded_ = true; }
private:
+ class WebSocketEventHandler;
+
// Handlers for each message type, dispatched by OnMessageReceived(), as
// defined in content/common/websocket_messages.h
@@ -73,6 +76,8 @@ class CONTENT_EXPORT WebSocketHost {
const url::Origin& origin,
int render_frame_id);
+ void OnSendBlob(const std::string& uuid, uint64_t expected_size);
+
void OnSendFrame(bool fin,
WebSocketMessageType type,
const std::vector<char>& data);
@@ -81,6 +86,11 @@ class CONTENT_EXPORT WebSocketHost {
void OnDropChannel(bool was_clean, uint16_t code, const std::string& reason);
+ void BlobSendComplete(int result);
+
+ // non-NULL if and only if this object is currently in "blob sending mode".
+ scoped_ptr<WebSocketBlobSender> blob_sender_;
+
// The channel we use to send events to the network.
scoped_ptr<net::WebSocketChannel> channel_;
diff --git a/chromium/content/browser/resolve_proxy_msg_helper.cc b/chromium/content/browser/resolve_proxy_msg_helper.cc
index e189f1c83d3..7b1e04ed0bc 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper.cc
@@ -92,7 +92,7 @@ void ResolveProxyMsgHelper::StartPendingRequest() {
// Start the request.
int result = proxy_service_->ResolveProxy(
- req.url, net::LOAD_NORMAL, &proxy_info_,
+ req.url, std::string(), net::LOAD_NORMAL, &proxy_info_,
base::Bind(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
base::Unretained(this)),
&req.pac_req, NULL, net::BoundNetLog());
diff --git a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
index 5e3dd0de584..bc723fe8796 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
@@ -90,8 +90,7 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
private:
bool OnMessageReceived(const IPC::Message& msg) override {
- base::TupleTypes<ViewHostMsg_ResolveProxy::ReplyParam>::ValueTuple
- reply_data;
+ ViewHostMsg_ResolveProxy::ReplyParam reply_data;
EXPECT_TRUE(ViewHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data));
DCHECK(!pending_result_.get());
pending_result_.reset(
diff --git a/chromium/content/browser/resource_context_impl.cc b/chromium/content/browser/resource_context_impl.cc
index a4f0303e0da..017e08dc3c9 100644
--- a/chromium/content/browser/resource_context_impl.cc
+++ b/chromium/content/browser/resource_context_impl.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
+#include "base/bind.h"
#include "base/logging.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -37,8 +38,13 @@ std::string ReturnEmptySalt() {
ResourceContext::ResourceContext() {
- if (ResourceDispatcherHostImpl::Get())
- ResourceDispatcherHostImpl::Get()->AddResourceContext(this);
+ ResourceDispatcherHostImpl* rdhi = ResourceDispatcherHostImpl::Get();
+ if (rdhi) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ResourceDispatcherHostImpl::AddResourceContext,
+ base::Unretained(rdhi), this));
+ }
}
ResourceContext::~ResourceContext() {
diff --git a/chromium/content/browser/resources/gpu/browser_bridge.js b/chromium/content/browser/resources/gpu/browser_bridge.js
index b835f44207c..c2ad051d09b 100644
--- a/chromium/content/browser/resources/gpu/browser_bridge.js
+++ b/chromium/content/browser/resources/gpu/browser_bridge.js
@@ -36,11 +36,9 @@ cr.define('gpu', function() {
applySimulatedData_: function applySimulatedData(data) {
// set up things according to the simulated data
this.gpuInfo_ = data.gpuInfo;
- this.gpuMemoryBufferInfo_ = data.gpuMemoryBufferInfo;
this.clientInfo_ = data.clientInfo;
this.logMessages_ = data.logMessages;
cr.dispatchSimpleEvent(this, 'gpuInfoUpdate');
- cr.dispatchSimpleEvent(this, 'gpuMemoryBufferInfoUpdate');
cr.dispatchSimpleEvent(this, 'clientInfoChange');
cr.dispatchSimpleEvent(this, 'logMessagesChange');
},
@@ -97,21 +95,6 @@ cr.define('gpu', function() {
},
/**
- * Get gpuMemoryBufferInfo data.
- */
- get gpuMemoryBufferInfo() {
- return this.gpuMemoryBufferInfo_;
- },
-
- /**
- * Called from gpu c++ code when GpuMemoryBuffer Info is updated.
- */
- onGpuMemoryBufferInfoUpdate: function(gpuMemoryBufferInfo) {
- this.gpuMemoryBufferInfo_ = gpuMemoryBufferInfo;
- cr.dispatchSimpleEvent(this, 'gpuMemoryBufferInfoUpdate');
- },
-
- /**
* This function begins a request for the ClientInfo. If it comes back
* as undefined, then we will issue the request again in 250ms.
*/
diff --git a/chromium/content/browser/resources/gpu/info_view.html b/chromium/content/browser/resources/gpu/info_view.html
index da813fc8dba..b1cef9cc2a3 100644
--- a/chromium/content/browser/resources/gpu/info_view.html
+++ b/chromium/content/browser/resources/gpu/info_view.html
@@ -23,11 +23,6 @@ found in the LICENSE file.
</div>
<div>
- <h3>GpuMemoryBuffer Status</h3>
- <div id="gpu-memory-buffer-info"></div>
- </div>
-
- <div>
<h3>Version Information</h3>
<div id="client-info"></div>
</div>
@@ -37,6 +32,16 @@ found in the LICENSE file.
<div id="basic-info"></div>
</div>
+ <div>
+ <h3>Compositor Information</h3>
+ <div id="compositor-info"></div>
+ </div>
+
+ <div>
+ <h3>GpuMemoryBuffers Status</h3>
+ <div id="gpu-memory-buffer-info"></div>
+ </div>
+
<div class="diagnostics">
<h3>Diagnostics</h3>
<div class="diagnostics-loading">... loading ...</div>
diff --git a/chromium/content/browser/resources/gpu/info_view.js b/chromium/content/browser/resources/gpu/info_view.js
index 3566369cd70..8a98725ed4a 100644
--- a/chromium/content/browser/resources/gpu/info_view.js
+++ b/chromium/content/browser/resources/gpu/info_view.js
@@ -23,8 +23,6 @@ cr.define('gpu', function() {
cr.ui.TabPanel.prototype.decorate.apply(this);
browserBridge.addEventListener('gpuInfoUpdate', this.refresh.bind(this));
- browserBridge.addEventListener('gpuMemoryBufferInfoUpdate',
- this.refresh.bind(this));
browserBridge.addEventListener('logMessagesChange',
this.refresh.bind(this));
browserBridge.addEventListener('clientInfoChange',
@@ -96,6 +94,7 @@ cr.define('gpu', function() {
'panel_fitting': 'Panel Fitting',
'rasterization': 'Rasterization',
'multiple_raster_threads': 'Multiple Raster Threads',
+ 'native_gpu_memory_buffers': 'Native GpuMemoryBuffers',
};
var statusMap = {
@@ -154,7 +153,6 @@ cr.define('gpu', function() {
var workaroundsDiv = this.querySelector('.workarounds-div');
var workaroundsList = this.querySelector('.workarounds-list');
var gpuInfo = browserBridge.gpuInfo;
- var gpuMemoryBufferInfo = browserBridge.gpuMemoryBufferInfo;
var i;
if (gpuInfo) {
// Not using jstemplate here for blacklist status because we construct
@@ -219,17 +217,22 @@ cr.define('gpu', function() {
problemsList.hidden = true;
workaroundsList.hidden = true;
}
- if (gpuMemoryBufferInfo.gpu_memory_buffer_info)
- this.setTable_('gpu-memory-buffer-info',
- gpuMemoryBufferInfo.gpu_memory_buffer_info);
- else
- this.setTable_('gpu-memory-buffer-info', []);
if (gpuInfo.basic_info)
this.setTable_('basic-info', gpuInfo.basic_info);
else
this.setTable_('basic-info', []);
+ if (gpuInfo.compositorInfo)
+ this.setTable_('compositor-info', gpuInfo.compositorInfo);
+ else
+ this.setTable_('compositor-info', []);
+
+ if (gpuInfo.gpuMemoryBufferInfo)
+ this.setTable_('gpu-memory-buffer-info', gpuInfo.gpuMemoryBufferInfo);
+ else
+ this.setTable_('gpu-memory-buffer-info', []);
+
if (gpuInfo.diagnostics) {
diagnosticsDiv.hidden = false;
diagnosticsLoadingDiv.hidden = true;
diff --git a/chromium/content/browser/resources/media/OWNERS b/chromium/content/browser/resources/media/OWNERS
index ffdcc7a1cb8..c6ef7b7f49d 100644
--- a/chromium/content/browser/resources/media/OWNERS
+++ b/chromium/content/browser/resources/media/OWNERS
@@ -1,4 +1,2 @@
-dalecurtis@chromium.org
-ddorwin@chromium.org
+file://media/OWNERS
tommi@chromium.org
-xhwang@chromium.org
diff --git a/chromium/content/browser/resources/media/dump_creator.js b/chromium/content/browser/resources/media/dump_creator.js
index 75076493e16..c8f53dfc165 100644
--- a/chromium/content/browser/resources/media/dump_creator.js
+++ b/chromium/content/browser/resources/media/dump_creator.js
@@ -47,12 +47,12 @@ var DumpCreator = (function() {
'<p><div>&lt;base filename&gt;.&lt;render process ID&gt;' +
'.aec_dump.&lt;recording ID&gt;</div>' +
'<div>&lt;base filename&gt;.&lt;render process ID&gt;' +
- '.source_input.&lt;stream ID&gt;.pcm</div></p>' +
+ '.source_input.&lt;stream ID&gt;.wav</div></p>' +
'<p class=audio-recordings-info>If recordings are disabled and then' +
- ' enabled using the same base filename, the files will be appended' +
- ' to and may become invalid. It is recommended to choose a new base' +
- ' filename each time or move the produced files before enabling' +
- ' again.</p>' +
+ ' enabled using the same base filename, the microphone recording file' +
+ ' will be overwritten, and the AEC dump file will be appended to and' +
+ ' may become invalid. It is recommended to choose a new base filename' +
+ ' each time or move the produced files before enabling again.</p>' +
'<p><label><input type=checkbox>' +
'Enable diagnostic packet and event recording</label></p>' +
'<p class=audio-recordings-info>A diagnostic packet and event' +
@@ -62,14 +62,12 @@ var DumpCreator = (function() {
' and RTCP packets are logged. These do not include any audio or' +
' video information, nor any other types of personally identifiable' +
' information (so no IP addresses or URLs). Checking this box will' +
- ' enable the recording for ongoing WebRTC calls and for future' +
- ' WebRTC calls. When the box is unchecked or this page is closed,' +
- ' all ongoing recordings will be stopped and this recording' +
- ' functionality will be disabled for future WebRTC calls. Recording' +
- ' in multiple tabs or multiple recordings in the same tab is' +
- ' currently not supported. When enabling, a filename for the' +
- ' recording can be selected. If an existing file is selected, it' +
- ' will be overwritten. </p>';
+ ' enable the recording for currently ongoing WebRTC calls. When' +
+ ' the box is unchecked or this page is closed, all active recordings' +
+ ' will be stopped. Recording in multiple tabs or multiple recordings' +
+ ' in the same tab is currently not supported. When enabling, a' +
+ ' filename for the recording can be selected. If an existing file is' +
+ ' selected, it will be overwritten. </p>';
content.getElementsByTagName('a')[0].addEventListener(
'click', this.onDownloadData_.bind(this));
content.getElementsByTagName('input')[0].addEventListener(
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.html b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
index 4e81776e760..fcc23b43d1e 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
@@ -49,11 +49,8 @@
<button href="#" class="stop"
jsvalues=".cmdArgs:{partition_id:$partition_id,version_id:version_id}"
jsdisplay="$this.running_status == 'RUNNING'">Stop</button>
- <button href="#" class="push"
- jsvalues=".cmdArgs:{partition_id:$partition_id,version_id:version_id}"
- jsdisplay="$this.running_status == 'RUNNING'">Push</button>
<button href="#" class="inspect"
- jsvalues=".cmdArgs:{process_id:process_id,devtools_agent_route_id:devtools_agent_route_id}"
+ jsvalues=".cmdArgs:{process_host_id:process_host_id,devtools_agent_route_id:devtools_agent_route_id}"
jsdisplay="$this.running_status == 'RUNNING'">Inspect</button>
<span class="operation-status" style="display: none">Running...</span>
</div>
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.js b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
index ff382dd75ad..087c5a65cf7 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.js
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
@@ -42,7 +42,7 @@ cr.define('serviceworker', function() {
}
// All commands are completed with 'onOperationComplete'.
- var COMMANDS = ['stop', 'push', 'inspect', 'unregister', 'start'];
+ var COMMANDS = ['stop', 'inspect', 'unregister', 'start'];
function commandHandler(command) {
return function(event) {
var link = event.target;
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 77675b994cb..efdd4cf81eb 100644
--- a/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -51,7 +51,7 @@ class ScreenOrientationBrowserTest : public ContentBrowserTest {
ASSERT_NE(blink::WebScreenOrientationUndefined, type);
screen_info.orientationType = type;
- ViewMsg_Resize_Params params;
+ ResizeParams params;
params.screen_info = screen_info;
params.new_size = gfx::Size(0, 0);
params.physical_backing_size = gfx::Size(300, 300);
@@ -227,18 +227,22 @@ class ScreenOrientationLockDisabledBrowserTest : public ContentBrowserTest {
// Check that when --disable-screen-orientation-lock is passed to the command
// line, screen.orientation.lock() correctly reports to not be supported.
-// Flaky: https://crbug.com/498236
-IN_PROC_BROWSER_TEST_F(ScreenOrientationLockDisabledBrowserTest,
- DISABLED_NotSupported) {
+IN_PROC_BROWSER_TEST_F(ScreenOrientationLockDisabledBrowserTest, NotSupported) {
GURL test_url = GetTestUrl("screen_orientation",
"screen_orientation_lock_disabled.html");
- TestNavigationObserver navigation_observer(shell()->web_contents(), 2);
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
shell()->LoadURL(test_url);
navigation_observer.Wait();
- EXPECT_EQ("NotSupportedError",
- shell()->web_contents()->GetLastCommittedURL().ref());
+ {
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(), "run();"));
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ navigation_observer.Wait();
+ EXPECT_EQ("NotSupportedError",
+ shell()->web_contents()->GetLastCommittedURL().ref());
+ }
}
#endif // defined(OS_ANDROID)
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.cc b/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.cc
new file mode 100644
index 00000000000..d4bc93f4af7
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.cc
@@ -0,0 +1,133 @@
+// 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 "content/browser/screen_orientation/screen_orientation_delegate_win.h"
+
+#include <windows.h>
+
+#include "content/public/browser/screen_orientation_provider.h"
+
+namespace {
+
+// SetDisplayAutoRotationPreferences is available on Windows 8 and after.
+void SetDisplayAutoRotationPreferencesWrapper(
+ ORIENTATION_PREFERENCE orientation) {
+ using SetDisplayAutoRotationPreferencesPtr =
+ void(WINAPI*)(ORIENTATION_PREFERENCE);
+ static SetDisplayAutoRotationPreferencesPtr
+ set_display_auto_rotation_preferences_func =
+ reinterpret_cast<SetDisplayAutoRotationPreferencesPtr>(
+ GetProcAddress(GetModuleHandleA("user32.dll"),
+ "SetDisplayAutoRotationPreferences"));
+ if (set_display_auto_rotation_preferences_func)
+ set_display_auto_rotation_preferences_func(orientation);
+}
+
+// GetAutoRotationState is available on Windows 8 and after.
+BOOL GetAutoRotationStateWrapper(PAR_STATE state) {
+ using GetAutoRotationStatePtr = BOOL(WINAPI*)(PAR_STATE);
+ static GetAutoRotationStatePtr get_auto_rotation_state_func =
+ reinterpret_cast<GetAutoRotationStatePtr>(GetProcAddress(
+ GetModuleHandleA("user32.dll"), "GetAutoRotationState"));
+ if (get_auto_rotation_state_func)
+ return get_auto_rotation_state_func(state);
+ return FALSE;
+}
+
+bool GetDisplayOrientation(bool* landscape, bool* flipped) {
+ DEVMODE dm = {};
+ dm.dmSize = sizeof(dm);
+ if (!EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &dm))
+ return false;
+ *flipped = (dm.dmDisplayOrientation == DMDO_270 ||
+ dm.dmDisplayOrientation == DMDO_180);
+ *landscape = (dm.dmPelsWidth > dm.dmPelsHeight);
+ return true;
+}
+
+} // namespace
+
+namespace content {
+
+ScreenOrientationDelegateWin::ScreenOrientationDelegateWin() {
+ ScreenOrientationProvider::SetDelegate(this);
+}
+
+ScreenOrientationDelegateWin::~ScreenOrientationDelegateWin() {
+ ScreenOrientationProvider::SetDelegate(nullptr);
+}
+
+bool ScreenOrientationDelegateWin::FullScreenRequired(
+ WebContents* web_contents) {
+ return false;
+}
+
+void ScreenOrientationDelegateWin::Lock(
+ WebContents* web_contents,
+ blink::WebScreenOrientationLockType lock_orientation) {
+ ORIENTATION_PREFERENCE prefs = ORIENTATION_PREFERENCE_NONE;
+ bool landscape = true;
+ bool flipped = false;
+ switch (lock_orientation) {
+ case blink::WebScreenOrientationLockPortraitPrimary:
+ prefs = ORIENTATION_PREFERENCE_PORTRAIT;
+ break;
+ case blink::WebScreenOrientationLockPortraitSecondary:
+ prefs = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
+ break;
+ case blink::WebScreenOrientationLockLandscapePrimary:
+ prefs = ORIENTATION_PREFERENCE_LANDSCAPE;
+ break;
+ case blink::WebScreenOrientationLockLandscapeSecondary:
+ prefs = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
+ break;
+ case blink::WebScreenOrientationLockPortrait:
+ if (!GetDisplayOrientation(&landscape, &flipped))
+ return;
+ prefs = (flipped && !landscape) ? ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED
+ : ORIENTATION_PREFERENCE_PORTRAIT;
+ break;
+ case blink::WebScreenOrientationLockLandscape:
+ if (!GetDisplayOrientation(&landscape, &flipped))
+ return;
+ prefs = (flipped && landscape) ? ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED
+ : ORIENTATION_PREFERENCE_LANDSCAPE;
+ break;
+ case blink::WebScreenOrientationLockNatural:
+ if (!GetDisplayOrientation(&landscape, &flipped))
+ return;
+ prefs = landscape ? ORIENTATION_PREFERENCE_LANDSCAPE
+ : ORIENTATION_PREFERENCE_PORTRAIT;
+ break;
+ case blink::WebScreenOrientationLockAny:
+ if (!GetDisplayOrientation(&landscape, &flipped))
+ return;
+ if (landscape) {
+ prefs = flipped ? ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED
+ : ORIENTATION_PREFERENCE_LANDSCAPE;
+ } else {
+ prefs = flipped ? ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED
+ : ORIENTATION_PREFERENCE_PORTRAIT;
+ }
+ break;
+ case blink::WebScreenOrientationLockDefault:
+ default:
+ break;
+ }
+ SetDisplayAutoRotationPreferencesWrapper(prefs);
+}
+
+bool ScreenOrientationDelegateWin::ScreenOrientationProviderSupported() {
+ AR_STATE auto_rotation_state = {};
+ return (GetAutoRotationStateWrapper(&auto_rotation_state) &&
+ !(auto_rotation_state & AR_NOSENSOR) &&
+ !(auto_rotation_state & AR_NOT_SUPPORTED) &&
+ !(auto_rotation_state & AR_MULTIMON));
+}
+
+void ScreenOrientationDelegateWin::Unlock(WebContents* web_contents) {
+ SetDisplayAutoRotationPreferencesWrapper(ORIENTATION_PREFERENCE_NONE);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.h b/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.h
new file mode 100644
index 00000000000..7651d5a7e65
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_win.h
@@ -0,0 +1,30 @@
+// 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 CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_WIN_H_
+#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_WIN_H_
+
+#include "content/public/browser/screen_orientation_delegate.h"
+
+namespace content {
+
+class ScreenOrientationDelegateWin : public ScreenOrientationDelegate {
+ public:
+ ScreenOrientationDelegateWin();
+ ~ScreenOrientationDelegateWin() override;
+
+ private:
+ // content::ScreenOrientationDelegate:
+ bool FullScreenRequired(WebContents* web_contents) override;
+ void Lock(WebContents* web_contents,
+ blink::WebScreenOrientationLockType lock_orientation) override;
+ bool ScreenOrientationProviderSupported() override;
+ void Unlock(WebContents* web_contents) override;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDelegateWin);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_WIN_H_
diff --git a/chromium/content/browser/security_exploit_browsertest.cc b/chromium/content/browser/security_exploit_browsertest.cc
index c515609c576..45117a39d96 100644
--- a/chromium/content/browser/security_exploit_browsertest.cc
+++ b/chromium/content/browser/security_exploit_browsertest.cc
@@ -23,6 +23,7 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/interstitial_page_delegate.h"
+#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/appcache_info.h"
#include "content/public/common/browser_side_navigation_policy.h"
@@ -33,10 +34,12 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/test_content_browser_client.h"
#include "ipc/ipc_security_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/url_request/url_request_slow_download_job.h"
using IPC::IpcSecurityTestUtil;
@@ -44,6 +47,11 @@ namespace content {
namespace {
+// This request id is used by tests that craft a
+// ResourceHostMsg_RequestResource. The id is sufficiently large that it doesn't
+// collide with ids used by previous navigation requests.
+const int kRequestIdNotPreviouslyUsed = 10000;
+
// This is a helper function for the tests which attempt to create a
// duplicate RenderViewHost or RenderWidgetHost. It tries to create two objects
// with the same process and routing ids, which causes a collision.
@@ -98,13 +106,11 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
return next_rfh->render_view_host();
}
-ResourceHostMsg_Request CreateXHRRequestWithOrigin(const char* origin) {
+ResourceHostMsg_Request CreateXHRRequest(const char* url) {
ResourceHostMsg_Request request;
request.method = "GET";
- request.url = GURL("http://bar.com/simple_page.html");
- request.first_party_for_cookies = GURL(origin);
+ request.url = GURL(url);
request.referrer_policy = blink::WebReferrerPolicyDefault;
- request.headers = base::StringPrintf("Origin: %s\r\n", origin);
request.load_flags = 0;
request.origin_pid = 0;
request.resource_type = RESOURCE_TYPE_XHR;
@@ -120,6 +126,44 @@ ResourceHostMsg_Request CreateXHRRequestWithOrigin(const char* origin) {
return request;
}
+ResourceHostMsg_Request CreateXHRRequestWithOrigin(const char* origin) {
+ ResourceHostMsg_Request request =
+ CreateXHRRequest("http://bar.com/simple_page.html");
+ request.first_party_for_cookies = GURL(origin);
+ request.headers = base::StringPrintf("Origin: %s\r\n", origin);
+ return request;
+}
+
+void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
+ NavigateToURL(shell, GURL("http://foo.com/simple_page.html"));
+ RenderFrameHost* rfh = shell->web_contents()->GetMainFrame();
+
+ if (block_loaders) {
+ // Test the case where loaders are placed into blocked_loaders_map_.
+ ResourceDispatcherHost::BlockRequestsForFrameFromUI(rfh);
+ }
+
+ // URLRequestSlowDownloadJob waits for another request to kFinishDownloadUrl
+ // to finish all pending requests. It is never sent, so the following URL
+ // blocks indefinitely, which is good because the request stays alive and the
+ // test can try to reuse the request id without a race.
+ const char* blocking_url = net::URLRequestSlowDownloadJob::kUnknownSizeUrl;
+ ResourceHostMsg_Request request(CreateXHRRequest(blocking_url));
+
+ // Use the same request id twice.
+ RenderProcessHostWatcher process_killed(
+ rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ IPC::IpcSecurityTestUtil::PwnMessageReceived(
+ rfh->GetProcess()->GetChannel(),
+ ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed, request));
+ IPC::IpcSecurityTestUtil::PwnMessageReceived(
+ rfh->GetProcess()->GetChannel(),
+ ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed, request));
+ process_killed.Wait();
+}
+
} // namespace
@@ -145,6 +189,12 @@ class SecurityExploitBrowserTest : public ContentBrowserTest {
",EXCLUDE localhost");
}
+ void SetUpOnMainThread() override {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&net::URLRequestSlowDownloadJob::AddUrlHandler));
+ }
+
protected:
// Tests that a given file path sent in a ViewHostMsg_RunFileChooser will
// cause renderer to be killed.
@@ -384,7 +434,8 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
IPC::IpcSecurityTestUtil::PwnMessageReceived(
web_rfh->GetProcess()->GetChannel(),
- ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1,
+ ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed,
chrome_origin_msg));
web_process_killed.Wait();
}
@@ -404,7 +455,8 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
IPC::IpcSecurityTestUtil::PwnMessageReceived(
web_rfh->GetProcess()->GetChannel(),
- ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1,
+ ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed,
embedder_isolated_origin_msg));
web_process_killed.Wait();
SetBrowserClientForTesting(old_client);
@@ -418,7 +470,8 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
IPC::IpcSecurityTestUtil::PwnMessageReceived(
web_rfh->GetProcess()->GetChannel(),
- ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1,
+ ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed,
invalid_origin_msg));
web_process_killed.Wait();
}
@@ -431,10 +484,77 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
IPC::IpcSecurityTestUtil::PwnMessageReceived(
web_rfh->GetProcess()->GetChannel(),
- ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(), 1,
+ ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
+ kRequestIdNotPreviouslyUsed,
invalid_scheme_origin_msg));
web_process_killed.Wait();
}
}
+// Renderer process should not be able to create multiple requests with the same
+// id.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidRequestId) {
+ // Existing loader in pending_loaders_.
+ TryCreateDuplicateRequestIds(shell(), false);
+ // Existing loader in blocked_loaders_map_.
+ TryCreateDuplicateRequestIds(shell(), true);
+}
+
+// Test that receiving a commit with incorrect origin properly terminates the
+// renderer process.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, MismatchedOriginOnCommit) {
+ GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Setup an URL which will never commit, allowing this test to send its own,
+ // malformed, commit message.
+ GURL url(embedded_test_server()->GetURL("/title2.html"));
+ NavigationStallDelegate stall_delegate(url);
+ ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
+
+ // Use LoadURL, as the test shouldn't wait for navigation commit.
+ NavigationController& controller = shell()->web_contents()->GetController();
+ controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ EXPECT_NE(nullptr, controller.GetPendingEntry());
+ EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
+
+ RenderProcessHostWatcher exit_observer(
+ root->current_frame_host()->GetProcess(),
+ RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+ // Create commit params with different origins in params.url and
+ // params.origin.
+ FrameHostMsg_DidCommitProvisionalLoad_Params params;
+ params.page_id = 0;
+ params.nav_entry_id = 0;
+ params.did_create_new_entry = false;
+ params.url = url;
+ params.transition = ui::PAGE_TRANSITION_LINK;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureAuto;
+ params.was_within_same_page = false;
+ params.is_post = false;
+ params.page_state = PageState::CreateFromURL(url);
+ params.origin = url::Origin(GURL("http://bar.com/"));
+
+ FrameHostMsg_DidCommitProvisionalLoad msg(
+ root->current_frame_host()->routing_id(), params);
+ IPC::IpcSecurityTestUtil::PwnMessageReceived(
+ root->current_frame_host()->GetProcess()->GetChannel(), msg);
+
+ // When the IPC message is received and validation fails, the process is
+ // terminated. However, the notification for that should be processed in a
+ // separate task of the message loop, so ensure that the process is still
+ // considered alive.
+ EXPECT_TRUE(root->current_frame_host()->GetProcess()->HasConnection());
+
+ exit_observer.Wait();
+ EXPECT_FALSE(exit_observer.did_exit_normally());
+ ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc
index 9d3290b6d63..69b222a37f9 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc
@@ -17,9 +17,11 @@
#include "content/common/content_switches_internal.h"
#include "content/common/mojo/service_registry_impl.h"
#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/embedded_worker_settings.h"
#include "content/common/service_worker/embedded_worker_setup.mojom.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/child_process_host.h"
#include "ipc/ipc_message.h"
@@ -29,6 +31,11 @@ namespace content {
namespace {
+// When a service worker version's failure count exceeds
+// |kMaxSameProcessFailureCount|, the embedded worker is forced to start in a
+// new process.
+const int kMaxSameProcessFailureCount = 2;
+
void NotifyWorkerReadyForInspectionOnUI(int worker_process_id,
int worker_route_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -54,6 +61,7 @@ void RegisterToWorkerDevToolsManagerOnUI(
const base::WeakPtr<ServiceWorkerContextCore>& service_worker_context_weak,
int64_t service_worker_version_id,
const GURL& url,
+ const GURL& scope,
const base::Callback<void(int worker_devtools_agent_route_id,
bool wait_for_debugger)>& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -64,13 +72,10 @@ void RegisterToWorkerDevToolsManagerOnUI(
worker_devtools_agent_route_id = rph->GetNextRoutingID();
wait_for_debugger =
ServiceWorkerDevToolsManager::GetInstance()->WorkerCreated(
- process_id,
- worker_devtools_agent_route_id,
+ process_id, worker_devtools_agent_route_id,
ServiceWorkerDevToolsManager::ServiceWorkerIdentifier(
- service_worker_context,
- service_worker_context_weak,
- service_worker_version_id,
- url));
+ service_worker_context, service_worker_context_weak,
+ service_worker_version_id, url, scope));
}
BrowserThread::PostTask(
BrowserThread::IO,
@@ -81,16 +86,17 @@ void RegisterToWorkerDevToolsManagerOnUI(
void SetupMojoOnUIThread(
int process_id,
int thread_id,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::InterfacePtrInfo<mojo::ServiceProvider> exposed_services) {
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtrInfo exposed_services) {
RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
// |rph| or its ServiceRegistry may be NULL in unit tests.
if (!rph || !rph->GetServiceRegistry())
return;
- EmbeddedWorkerSetupPtr setup;
+ mojom::EmbeddedWorkerSetupPtr setup;
rph->GetServiceRegistry()->ConnectToRemoteService(mojo::GetProxy(&setup));
- setup->ExchangeServiceProviders(thread_id, std::move(services),
- mojo::MakeProxy(std::move(exposed_services)));
+ setup->ExchangeInterfaceProviders(
+ thread_id, std::move(services),
+ mojo::MakeProxy(std::move(exposed_services)));
}
} // namespace
@@ -140,10 +146,12 @@ class EmbeddedWorkerInstance::WorkerProcessHandle {
public:
WorkerProcessHandle(const base::WeakPtr<ServiceWorkerContextCore>& context,
int embedded_worker_id,
- int process_id)
+ int process_id,
+ bool is_new_process)
: context_(context),
embedded_worker_id_(embedded_worker_id),
- process_id_(process_id) {
+ process_id_(process_id),
+ is_new_process_(is_new_process) {
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id_);
}
@@ -153,12 +161,14 @@ class EmbeddedWorkerInstance::WorkerProcessHandle {
}
int process_id() const { return process_id_; }
+ bool is_new_process() const { return is_new_process_; }
private:
base::WeakPtr<ServiceWorkerContextCore> context_;
const int embedded_worker_id_;
const int process_id_;
+ const bool is_new_process_;
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHandle);
};
@@ -172,13 +182,21 @@ class EmbeddedWorkerInstance::StartTask {
public:
enum class ProcessAllocationState { NOT_ALLOCATED, ALLOCATING, ALLOCATED };
- explicit StartTask(EmbeddedWorkerInstance* instance)
+ StartTask(EmbeddedWorkerInstance* instance, const GURL& script_url)
: instance_(instance),
state_(ProcessAllocationState::NOT_ALLOCATED),
- weak_factory_(this) {}
+ is_installed_(false),
+ start_situation_(ServiceWorkerMetrics::StartSituation::UNKNOWN),
+ weak_factory_(this) {
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ this, "Script", script_url.spec());
+ }
~StartTask() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ TRACE_EVENT_ASYNC_END0("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ this);
+
if (!instance_->context_)
return;
@@ -210,17 +228,22 @@ class EmbeddedWorkerInstance::StartTask {
void Start(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
- "EmbeddedWorkerInstance::ProcessAllocate",
- params.get(), "Scope", params->scope.spec(),
- "Script URL", params->script_url.spec());
state_ = ProcessAllocationState::ALLOCATING;
start_callback_ = callback;
+ is_installed_ = params->is_installed;
+
+ if (!GetContentClient()->browser()->IsBrowserStartupComplete())
+ start_situation_ = ServiceWorkerMetrics::StartSituation::DURING_STARTUP;
GURL scope(params->scope);
GURL script_url(params->script_url);
+
+ bool can_use_existing_process =
+ instance_->context_->GetVersionFailureCount(
+ params->service_worker_version_id) < kMaxSameProcessFailureCount;
instance_->context_->process_manager()->AllocateWorkerProcess(
- instance_->embedded_worker_id(), scope, script_url,
+ instance_->embedded_worker_id_, scope, script_url,
+ can_use_existing_process,
base::Bind(&StartTask::OnProcessAllocated, weak_factory_.GetWeakPtr(),
base::Passed(&params)));
}
@@ -234,18 +257,24 @@ class EmbeddedWorkerInstance::StartTask {
// |task| may be destroyed.
}
+ bool is_installed() const { return is_installed_; }
+ ServiceWorkerMetrics::StartSituation start_situation() const {
+ return start_situation_;
+ }
+
private:
void OnProcessAllocated(
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
ServiceWorkerStatusCode status,
int process_id,
- bool is_new_process) {
+ bool is_new_process,
+ const EmbeddedWorkerSettings& settings) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- TRACE_EVENT_ASYNC_END1("ServiceWorker",
- "EmbeddedWorkerInstance::ProcessAllocate",
- params.get(), "Status", status);
if (status != SERVICE_WORKER_OK) {
+ TRACE_EVENT_ASYNC_STEP_PAST1(
+ "ServiceWorker", "EmbeddedWorkerInstance::Start", this,
+ "OnProcessAllocated", "Error", ServiceWorkerStatusToString(status));
DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, process_id);
StatusCallback callback = start_callback_;
start_callback_.Reset();
@@ -254,19 +283,39 @@ class EmbeddedWorkerInstance::StartTask {
return;
}
+ TRACE_EVENT_ASYNC_STEP_PAST1(
+ "ServiceWorker", "EmbeddedWorkerInstance::Start", this,
+ "OnProcessAllocated", "Is New Process", is_new_process);
+ if (is_installed_)
+ ServiceWorkerMetrics::RecordProcessCreated(is_new_process);
+
+ if (start_situation_ == ServiceWorkerMetrics::StartSituation::UNKNOWN) {
+ if (is_new_process)
+ start_situation_ = ServiceWorkerMetrics::StartSituation::NEW_PROCESS;
+ else
+ start_situation_ =
+ ServiceWorkerMetrics::StartSituation::EXISTING_PROCESS;
+ }
+
// Notify the instance that a process is allocated.
state_ = ProcessAllocationState::ALLOCATED;
instance_->OnProcessAllocated(make_scoped_ptr(new WorkerProcessHandle(
- instance_->context_, instance_->embedded_worker_id(), process_id)));
+ instance_->context_, instance_->embedded_worker_id(), process_id,
+ is_new_process)));
+
+ // TODO(bengr): Support changes to this setting while the worker
+ // is running.
+ params->settings.data_saver_enabled = settings.data_saver_enabled;
// Register the instance to DevToolsManager on UI thread.
const int64_t service_worker_version_id = params->service_worker_version_id;
+ const GURL& scope = params->scope;
GURL script_url(params->script_url);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(RegisterToWorkerDevToolsManagerOnUI, process_id,
instance_->context_.get(), instance_->context_,
- service_worker_version_id, script_url,
+ service_worker_version_id, script_url, scope,
base::Bind(&StartTask::OnRegisteredToDevToolsManager,
weak_factory_.GetWeakPtr(), base::Passed(&params),
is_new_process)));
@@ -278,6 +327,9 @@ class EmbeddedWorkerInstance::StartTask {
int worker_devtools_agent_route_id,
bool wait_for_debugger) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ TRACE_EVENT_ASYNC_STEP_PAST0("ServiceWorker",
+ "EmbeddedWorkerInstance::Start", this,
+ "OnRegisteredToDevToolsManager");
// Notify the instance that it is registered to the devtools manager.
instance_->OnRegisteredToDevToolsManager(
@@ -293,6 +345,9 @@ class EmbeddedWorkerInstance::StartTask {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ServiceWorkerStatusCode status = instance_->registry_->SendStartWorker(
std::move(params), instance_->process_id());
+ TRACE_EVENT_ASYNC_STEP_PAST1(
+ "ServiceWorker", "EmbeddedWorkerInstance::Start", this,
+ "SendStartWorker", "Status", ServiceWorkerStatusToString(status));
if (status != SERVICE_WORKER_OK) {
StatusCallback callback = start_callback_;
start_callback_.Reset();
@@ -312,11 +367,20 @@ class EmbeddedWorkerInstance::StartTask {
StatusCallback start_callback_;
ProcessAllocationState state_;
+ // Used for UMA.
+ bool is_installed_;
+ ServiceWorkerMetrics::StartSituation start_situation_;
+
base::WeakPtrFactory<StartTask> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(StartTask);
};
+bool EmbeddedWorkerInstance::Listener::OnMessageReceived(
+ const IPC::Message& message) {
+ return false;
+}
+
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
DCHECK(status_ == STOPPING || status_ == STOPPED) << status_;
devtools_proxy_.reset();
@@ -325,10 +389,9 @@ EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
process_handle_.reset();
}
-void EmbeddedWorkerInstance::Start(int64_t service_worker_version_id,
- const GURL& scope,
- const GURL& script_url,
- const StatusCallback& callback) {
+void EmbeddedWorkerInstance::Start(
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+ const StatusCallback& callback) {
if (!context_) {
callback.Run(SERVICE_WORKER_ERROR_ABORT);
// |this| may be destroyed by the callback.
@@ -336,27 +399,21 @@ void EmbeddedWorkerInstance::Start(int64_t service_worker_version_id,
}
DCHECK(status_ == STOPPED);
- // TODO(horo): If we will see crashes here, we have to find the root cause of
- // the invalid version ID. Otherwise change CHECK to DCHECK.
- CHECK_NE(service_worker_version_id, kInvalidServiceWorkerVersionId);
- start_timing_ = base::TimeTicks::Now();
+ DCHECK(!params->pause_after_download || !params->is_installed);
+ DCHECK_NE(kInvalidServiceWorkerVersionId, params->service_worker_version_id);
+ step_time_ = base::TimeTicks::Now();
status_ = STARTING;
starting_phase_ = ALLOCATING_PROCESS;
network_accessed_for_script_ = false;
service_registry_.reset(new ServiceRegistryImpl());
FOR_EACH_OBSERVER(Listener, listener_list_, OnStarting());
- scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
- new EmbeddedWorkerMsg_StartWorker_Params());
params->embedded_worker_id = embedded_worker_id_;
- params->service_worker_version_id = service_worker_version_id;
- params->scope = scope;
- params->script_url = script_url;
params->worker_devtools_agent_route_id = MSG_ROUTING_NONE;
params->wait_for_debugger = false;
- params->v8_cache_options = GetV8CacheOptions();
+ params->settings.v8_cache_options = GetV8CacheOptions();
- inflight_start_task_.reset(new StartTask(this));
+ inflight_start_task_.reset(new StartTask(this, params->script_url));
inflight_start_task_->Start(std::move(params), callback);
}
@@ -401,6 +458,13 @@ ServiceWorkerStatusCode EmbeddedWorkerInstance::SendMessage(
thread_id_, embedded_worker_id_, message));
}
+void EmbeddedWorkerInstance::ResumeAfterDownload() {
+ if (process_id() == ChildProcessHost::kInvalidUniqueID || status_ != STARTING)
+ return;
+ registry_->Send(process_id(), new EmbeddedWorkerMsg_ResumeAfterDownload(
+ embedded_worker_id_));
+}
+
ServiceRegistry* EmbeddedWorkerInstance::GetServiceRegistry() {
DCHECK(status_ == STARTING || status_ == RUNNING) << status_;
return service_registry_.get();
@@ -439,27 +503,21 @@ void EmbeddedWorkerInstance::OnRegisteredToDevToolsManager(
new DevToolsProxy(process_id(), worker_devtools_agent_route_id));
}
if (wait_for_debugger) {
- // We don't measure the start time when wait_for_debugger flag is set. So we
- // set the NULL time here.
- start_timing_ = base::TimeTicks();
- } else {
- DCHECK(!start_timing_.is_null());
- if (is_new_process) {
- UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.NewProcessAllocation",
- base::TimeTicks::Now() - start_timing_);
- } else {
- UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ExistingProcessAllocation",
- base::TimeTicks::Now() - start_timing_);
- }
- UMA_HISTOGRAM_BOOLEAN("EmbeddedWorkerInstance.ProcessCreated",
- is_new_process);
- // Reset |start_timing_| to measure the time excluding the process
- // allocation time.
- start_timing_ = base::TimeTicks::Now();
+ // We don't measure the start time when wait_for_debugger flag is set. So
+ // we set the NULL time here.
+ step_time_ = base::TimeTicks();
}
}
void EmbeddedWorkerInstance::OnStartWorkerMessageSent() {
+ if (!step_time_.is_null()) {
+ base::TimeDelta duration = UpdateStepTime();
+ if (inflight_start_task_->is_installed()) {
+ ServiceWorkerMetrics::RecordTimeToSendStartWorker(
+ duration, inflight_start_task_->start_situation());
+ }
+ }
+
starting_phase_ = SENT_START_WORKER;
FOR_EACH_OBSERVER(Listener, listener_list_, OnStartWorkerMessageSent());
}
@@ -478,32 +536,69 @@ void EmbeddedWorkerInstance::OnScriptReadFinished() {
}
void EmbeddedWorkerInstance::OnScriptLoaded() {
- FOR_EACH_OBSERVER(Listener, listener_list_, OnScriptLoaded());
+ using LoadSource = ServiceWorkerMetrics::LoadSource;
+
+ if (!inflight_start_task_)
+ return;
+ LoadSource source;
+ if (network_accessed_for_script_) {
+ DCHECK(!inflight_start_task_->is_installed());
+ source = LoadSource::NETWORK;
+ } else if (inflight_start_task_->is_installed()) {
+ source = LoadSource::SERVICE_WORKER_STORAGE;
+ } else {
+ source = LoadSource::HTTP_CACHE;
+ }
+ TRACE_EVENT_ASYNC_STEP_PAST1(
+ "ServiceWorker", "EmbeddedWorkerInstance::Start",
+ inflight_start_task_.get(), "OnScriptLoaded", "Source",
+ ServiceWorkerMetrics::LoadSourceToString(source));
+
+ if (!step_time_.is_null()) {
+ base::TimeDelta duration = UpdateStepTime();
+ ServiceWorkerMetrics::RecordTimeToLoad(
+ duration, source, inflight_start_task_->start_situation());
+ }
+
starting_phase_ = SCRIPT_LOADED;
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnScriptLoaded());
+ // |this| may be destroyed by the callback.
+}
+
+void EmbeddedWorkerInstance::OnURLJobCreatedForMainScript() {
+ if (!inflight_start_task_)
+ return;
+ TRACE_EVENT_ASYNC_STEP_PAST0("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ inflight_start_task_.get(), "OnURLJobCreated");
+ if (!step_time_.is_null()) {
+ base::TimeDelta duration = UpdateStepTime();
+ if (inflight_start_task_->is_installed())
+ ServiceWorkerMetrics::RecordTimeToURLJob(
+ duration, inflight_start_task_->start_situation());
+ }
}
void EmbeddedWorkerInstance::OnThreadStarted(int thread_id) {
+ if (!inflight_start_task_)
+ return;
+ TRACE_EVENT_ASYNC_STEP_PAST0("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ inflight_start_task_.get(), "OnThreadStarted");
+
starting_phase_ = THREAD_STARTED;
- if (!start_timing_.is_null()) {
- if (network_accessed_for_script_) {
- UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ScriptLoadWithNetworkAccess",
- base::TimeTicks::Now() - start_timing_);
- } else {
- UMA_HISTOGRAM_TIMES(
- "EmbeddedWorkerInstance.ScriptLoadWithoutNetworkAccess",
- base::TimeTicks::Now() - start_timing_);
- }
- // Reset |start_timing_| to measure the time excluding the process
- // allocation time and the script loading time.
- start_timing_ = base::TimeTicks::Now();
+ if (!step_time_.is_null()) {
+ base::TimeDelta duration = UpdateStepTime();
+ if (inflight_start_task_->is_installed())
+ ServiceWorkerMetrics::RecordTimeToStartThread(
+ duration, inflight_start_task_->start_situation());
}
+
thread_id_ = thread_id;
FOR_EACH_OBSERVER(Listener, listener_list_, OnThreadStarted());
- mojo::ServiceProviderPtr exposed_services;
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services;
service_registry_->Bind(GetProxy(&exposed_services));
- mojo::ServiceProviderPtr services;
- mojo::InterfaceRequest<mojo::ServiceProvider> services_request =
+ mojo::shell::mojom::InterfaceProviderPtr services;
+ mojo::shell::mojom::InterfaceProviderRequest services_request =
GetProxy(&services);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -514,6 +609,11 @@ void EmbeddedWorkerInstance::OnThreadStarted(int thread_id) {
}
void EmbeddedWorkerInstance::OnScriptLoadFailed() {
+ if (!inflight_start_task_)
+ return;
+ TRACE_EVENT_ASYNC_STEP_PAST0("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ inflight_start_task_.get(),
+ "OnScriptLoadFailed");
FOR_EACH_OBSERVER(Listener, listener_list_, OnScriptLoadFailed());
}
@@ -522,10 +622,15 @@ void EmbeddedWorkerInstance::OnScriptEvaluated(bool success) {
return;
DCHECK_EQ(STARTING, status_);
+ TRACE_EVENT_ASYNC_STEP_PAST1("ServiceWorker", "EmbeddedWorkerInstance::Start",
+ inflight_start_task_.get(), "OnScriptEvaluated",
+ "Success", success);
starting_phase_ = SCRIPT_EVALUATED;
- if (success && !start_timing_.is_null()) {
- UMA_HISTOGRAM_TIMES("EmbeddedWorkerInstance.ScriptEvaluate",
- base::TimeTicks::Now() - start_timing_);
+ if (!step_time_.is_null()) {
+ base::TimeDelta duration = UpdateStepTime();
+ if (success && inflight_start_task_->is_installed())
+ ServiceWorkerMetrics::RecordTimeToEvaluateScript(
+ duration, inflight_start_task_->start_situation());
}
base::WeakPtr<EmbeddedWorkerInstance> weak_this = weak_factory_.GetWeakPtr();
@@ -563,6 +668,10 @@ void EmbeddedWorkerInstance::Detach() {
OnDetached();
}
+base::WeakPtr<EmbeddedWorkerInstance> EmbeddedWorkerInstance::AsWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
bool EmbeddedWorkerInstance::OnMessageReceived(const IPC::Message& message) {
ListenerList::Iterator it(&listener_list_);
while (Listener* listener = it.GetNext()) {
@@ -602,6 +711,11 @@ int EmbeddedWorkerInstance::process_id() const {
return ChildProcessHost::kInvalidUniqueID;
}
+bool EmbeddedWorkerInstance::is_new_process() const {
+ DCHECK(process_handle_);
+ return process_handle_->is_new_process();
+}
+
int EmbeddedWorkerInstance::worker_devtools_agent_route_id() const {
if (devtools_proxy_)
return devtools_proxy_->agent_route_id();
@@ -648,6 +762,15 @@ void EmbeddedWorkerInstance::OnStartFailed(const StatusCallback& callback,
OnStopped(old_status));
}
+base::TimeDelta EmbeddedWorkerInstance::UpdateStepTime() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!step_time_.is_null());
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta duration = now - step_time_;
+ step_time_ = now;
+ return duration;
+}
+
// static
std::string EmbeddedWorkerInstance::StatusToString(Status status) {
switch (status) {
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.h b/chromium/content/browser/service_worker/embedded_worker_instance.h
index a4ed91ca8a4..0c9b67ee5d6 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.h
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.h
@@ -15,10 +15,12 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
@@ -100,7 +102,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
int line_number,
const GURL& source_url) {}
// Returns false if the message is not handled by this listener.
- virtual bool OnMessageReceived(const IPC::Message& message) = 0;
+ CONTENT_EXPORT virtual bool OnMessageReceived(const IPC::Message& message);
};
~EmbeddedWorkerInstance();
@@ -108,9 +110,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
// Starts the worker. It is invalid to call this when the worker is not in
// STOPPED status. |callback| is invoked after the worker script has been
// started and evaluated, or when an error occurs.
- void Start(int64_t service_worker_version_id,
- const GURL& scope,
- const GURL& script_url,
+ // |params| should be populated with service worker version info needed
+ // to start the worker.
+ void Start(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
const StatusCallback& callback);
// Stops the worker. It is invalid to call this when the worker is
@@ -129,6 +131,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
// status.
ServiceWorkerStatusCode SendMessage(const IPC::Message& message);
+ // Resumes the worker if it paused after download.
+ void ResumeAfterDownload();
+
// Returns the ServiceRegistry for this worker. It is invalid to call this
// when the worker is not in STARTING or RUNNING status.
ServiceRegistry* GetServiceRegistry();
@@ -141,6 +146,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
}
int process_id() const;
int thread_id() const { return thread_id_; }
+ // This should be called only when the worker instance has a valid process,
+ // that is, when |process_id()| returns a valid process id.
+ bool is_new_process() const;
int worker_devtools_agent_route_id() const;
MessagePortMessageFilter* message_port_message_filter() const;
@@ -150,7 +158,11 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void set_devtools_attached(bool attached) { devtools_attached_ = attached; }
bool devtools_attached() const { return devtools_attached_; }
- // Called when the script load request accessed the network.
+ bool network_accessed_for_script() const {
+ return network_accessed_for_script_;
+ }
+
+ // Called when the main script load accessed the network.
void OnNetworkAccessedForScriptLoad();
// Called when reading the main script from the service worker script cache
@@ -158,11 +170,17 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void OnScriptReadStarted();
void OnScriptReadFinished();
+ // Called when the net::URLRequestJob to load the service worker script
+ // created. Not called for import scripts.
+ void OnURLJobCreatedForMainScript();
+
static std::string StatusToString(Status status);
static std::string StartingPhaseToString(StartingPhase phase);
void Detach();
+ base::WeakPtr<EmbeddedWorkerInstance> AsWeakPtr();
+
private:
typedef base::ObserverList<Listener> ListenerList;
class DevToolsProxy;
@@ -253,6 +271,10 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void OnStartFailed(const StatusCallback& callback,
ServiceWorkerStatusCode status);
+ // Returns the time elapsed since |step_time_| and updates |step_time_|
+ // to the current time.
+ base::TimeDelta UpdateStepTime();
+
base::WeakPtr<ServiceWorkerContextCore> context_;
scoped_refptr<EmbeddedWorkerRegistry> registry_;
const int embedded_worker_id_;
@@ -275,7 +297,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
scoped_ptr<DevToolsProxy> devtools_proxy_;
scoped_ptr<StartTask> inflight_start_task_;
- base::TimeTicks start_timing_;
+
+ // Used for UMA. The start time of the current start sequence step.
+ base::TimeTicks step_time_;
base::WeakPtrFactory<EmbeddedWorkerInstance> weak_factory_;
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
index dcbb856d9d7..1db995ab1e6 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -32,6 +32,17 @@ void SaveStatusAndCall(ServiceWorkerStatusCode* out,
callback.Run();
}
+scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params>
+CreateStartParams(int version_id, const GURL& scope, const GURL& script_url) {
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ new EmbeddedWorkerMsg_StartWorker_Params);
+ params->service_worker_version_id = version_id;
+ params->scope = scope;
+ params->script_url = script_url;
+ params->pause_after_download = false;
+ return params;
+}
+
} // namespace
class EmbeddedWorkerInstanceTest : public testing::Test,
@@ -85,8 +96,10 @@ class EmbeddedWorkerInstanceTest : public testing::Test,
const GURL& url) {
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
- worker->Start(id, pattern, url, base::Bind(&SaveStatusAndCall, &status,
- run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params =
+ CreateStartParams(id, pattern, url);
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
run_loop.Run();
return status;
}
@@ -118,13 +131,15 @@ class StalledInStartWorkerHelper : public EmbeddedWorkerTestHelper {
void OnStartWorker(int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
- const GURL& script_url) override {
+ const GURL& script_url,
+ bool pause_after_download) override {
if (force_stall_in_start_) {
// Do nothing to simulate a stall in the worker process.
return;
}
- EmbeddedWorkerTestHelper::OnStartWorker(
- embedded_worker_id, service_worker_version_id, scope, script_url);
+ EmbeddedWorkerTestHelper::OnStartWorker(embedded_worker_id,
+ service_worker_version_id, scope,
+ script_url, pause_after_download);
}
void set_force_stall_in_start(bool force_stall_in_start) {
@@ -162,11 +177,10 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
// Start should succeed.
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
- worker->Start(
- service_worker_version_id,
- pattern,
- url,
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params =
+ CreateStartParams(service_worker_version_id, pattern, url);
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
run_loop.Run();
EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -192,6 +206,72 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
EmbeddedWorkerMsg_StopWorker::ID));
}
+// Test that a worker that failed twice will use a new render process
+// on the next attempt.
+TEST_F(EmbeddedWorkerInstanceTest, ForceNewProcess) {
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ const int64_t service_worker_version_id = 55L;
+ const GURL pattern("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ // Simulate adding one process to the pattern.
+ helper_->SimulateAddProcessToPattern(pattern,
+ helper_->mock_render_process_id());
+
+ // Also simulate adding a "newly created" process to the pattern because
+ // unittests can't actually create a new process itself.
+ // ServiceWorkerProcessManager only chooses this process id in unittests if
+ // can_use_existing_process is false.
+ helper_->SimulateAddProcessToPattern(pattern,
+ helper_->new_render_process_id());
+
+ {
+ // Start once normally.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ base::RunLoop run_loop;
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(service_worker_version_id, pattern, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
+ run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+ // The worker should be using the default render process.
+ EXPECT_EQ(helper_->mock_render_process_id(), worker->process_id());
+
+ EXPECT_EQ(SERVICE_WORKER_OK, worker->Stop());
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Fail twice.
+ context()->UpdateVersionFailureCount(service_worker_version_id,
+ SERVICE_WORKER_ERROR_FAILED);
+ context()->UpdateVersionFailureCount(service_worker_version_id,
+ SERVICE_WORKER_ERROR_FAILED);
+
+ {
+ // Start again.
+ ServiceWorkerStatusCode status;
+ base::RunLoop run_loop;
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(service_worker_version_id, pattern, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
+ run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+ // The worker should be using the new render process.
+ EXPECT_EQ(helper_->new_render_process_id(), worker->process_id());
+ EXPECT_EQ(SERVICE_WORKER_OK, worker->Stop());
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
TEST_F(EmbeddedWorkerInstanceTest, StopWhenDevToolsAttached) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
@@ -256,9 +336,10 @@ TEST_F(EmbeddedWorkerInstanceTest, RemoveWorkerInSharedProcess) {
// Start worker1.
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
- worker1->Start(
- version_id1, pattern, url,
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id1, pattern, url));
+ worker1->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
run_loop.Run();
EXPECT_EQ(SERVICE_WORKER_OK, status);
}
@@ -267,9 +348,10 @@ TEST_F(EmbeddedWorkerInstanceTest, RemoveWorkerInSharedProcess) {
// Start worker2.
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
- worker2->Start(
- version_id2, pattern, url,
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id2, pattern, url));
+ worker2->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
run_loop.Run();
EXPECT_EQ(SERVICE_WORKER_OK, status);
}
@@ -303,9 +385,10 @@ TEST_F(EmbeddedWorkerInstanceTest, DetachDuringProcessAllocation) {
// Run the start worker sequence and detach during process allocation.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
- worker->Start(
- version_id, scope, url,
- base::Bind(&SaveStatusAndCall, &status, base::Bind(&base::DoNothing)));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, scope, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ base::Bind(&base::DoNothing)));
worker->Detach();
base::RunLoop().RunUntilIdle();
@@ -334,9 +417,10 @@ TEST_F(EmbeddedWorkerInstanceTest, DetachAfterSendingStartWorkerMessage) {
// Run the start worker sequence until a start worker message is sent.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
- worker->Start(
- version_id, scope, url,
- base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, scope, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ base::Bind(&base::DoNothing)));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, events_.size());
@@ -371,9 +455,11 @@ TEST_F(EmbeddedWorkerInstanceTest, StopDuringProcessAllocation) {
// Stop the start worker sequence before a process is allocated.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
- worker->Start(
- version_id, scope, url,
- base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
+
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, scope, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ base::Bind(&base::DoNothing)));
worker->Stop();
base::RunLoop().RunUntilIdle();
@@ -393,8 +479,9 @@ TEST_F(EmbeddedWorkerInstanceTest, StopDuringProcessAllocation) {
// Restart the worker.
status = SERVICE_WORKER_ERROR_MAX_VALUE;
scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
- worker->Start(version_id, scope, url, base::Bind(&SaveStatusAndCall, &status,
- run_loop->QuitClosure()));
+ params = CreateStartParams(version_id, scope, url);
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop->QuitClosure()));
run_loop->Run();
EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -407,6 +494,37 @@ TEST_F(EmbeddedWorkerInstanceTest, StopDuringProcessAllocation) {
worker->Stop();
}
+TEST_F(EmbeddedWorkerInstanceTest, StopDuringPausedAfterDownload) {
+ const int64_t version_id = 55L;
+ const GURL scope("http://example.com/");
+ const GURL url("http://example.com/worker.js");
+
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ worker->AddListener(this);
+
+ // Run the start worker sequence until pause after download.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, scope, url));
+ params->pause_after_download = true;
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ base::Bind(&base::DoNothing)));
+ base::RunLoop().RunUntilIdle();
+
+ // Make the worker stopping and attempt to send a resume after download
+ // message.
+ worker->Stop();
+ worker->ResumeAfterDownload();
+ base::RunLoop().RunUntilIdle();
+
+ // The resume after download message should not have been sent.
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+ EXPECT_FALSE(ipc_sink()->GetFirstMessageMatching(
+ EmbeddedWorkerMsg_ResumeAfterDownload::ID));
+}
+
TEST_F(EmbeddedWorkerInstanceTest, StopAfterSendingStartWorkerMessage) {
const int64_t version_id = 55L;
const GURL scope("http://example.com/");
@@ -419,9 +537,10 @@ TEST_F(EmbeddedWorkerInstanceTest, StopAfterSendingStartWorkerMessage) {
// Run the start worker sequence until a start worker message is sent.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
- worker->Start(
- version_id, scope, url,
- base::Bind(&SaveStatusAndCall, &status, base::Bind(base::DoNothing)));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, scope, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ base::Bind(&base::DoNothing)));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u, events_.size());
@@ -450,8 +569,10 @@ TEST_F(EmbeddedWorkerInstanceTest, StopAfterSendingStartWorkerMessage) {
->set_force_stall_in_start(false);
status = SERVICE_WORKER_ERROR_MAX_VALUE;
scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
- worker->Start(version_id, scope, url, base::Bind(&SaveStatusAndCall, &status,
- run_loop->QuitClosure()));
+
+ params = CreateStartParams(version_id, scope, url);
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop->QuitClosure()));
run_loop->Run();
// The worker should be started.
@@ -478,9 +599,10 @@ TEST_F(EmbeddedWorkerInstanceTest, Detach) {
// Start the worker.
base::RunLoop run_loop;
- worker->Start(
- version_id, pattern, url,
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, pattern, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
run_loop.Run();
// Detach.
@@ -512,9 +634,10 @@ TEST_F(EmbeddedWorkerInstanceTest, FailToSendStartIPC) {
// Attempt to start the worker.
base::RunLoop run_loop;
- worker->Start(
- version_id, pattern, url,
- base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ CreateStartParams(version_id, pattern, url));
+ worker->Start(std::move(params), base::Bind(&SaveStatusAndCall, &status,
+ run_loop.QuitClosure()));
run_loop.Run();
// The callback should have run, and we should have got an OnStopped message.
diff --git a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
index 3f572923391..25fcbd5561f 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -20,6 +20,7 @@
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/embedded_worker_setup.mojom.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/common/push_event_payload.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
@@ -50,17 +51,18 @@ class MockMessagePortMessageFilter : public MessagePortMessageFilter {
} // namespace
class EmbeddedWorkerTestHelper::MockEmbeddedWorkerSetup
- : public EmbeddedWorkerSetup {
+ : public mojom::EmbeddedWorkerSetup {
public:
- static void Create(const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
- mojo::InterfaceRequest<EmbeddedWorkerSetup> request) {
+ static void Create(
+ const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
+ mojo::InterfaceRequest<mojom::EmbeddedWorkerSetup> request) {
new MockEmbeddedWorkerSetup(helper, std::move(request));
}
- void ExchangeServiceProviders(
+ void ExchangeInterfaceProviders(
int32_t thread_id,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr exposed_services) override {
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services) override {
if (!helper_)
return;
helper_->OnSetupMojoStub(thread_id, std::move(services),
@@ -68,12 +70,13 @@ class EmbeddedWorkerTestHelper::MockEmbeddedWorkerSetup
}
private:
- MockEmbeddedWorkerSetup(const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
- mojo::InterfaceRequest<EmbeddedWorkerSetup> request)
+ MockEmbeddedWorkerSetup(
+ const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
+ mojo::InterfaceRequest<mojom::EmbeddedWorkerSetup> request)
: helper_(helper), binding_(this, std::move(request)) {}
base::WeakPtr<EmbeddedWorkerTestHelper> helper_;
- mojo::StrongBinding<EmbeddedWorkerSetup> binding_;
+ mojo::StrongBinding<mojom::EmbeddedWorkerSetup> binding_;
};
EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
@@ -89,7 +92,8 @@ EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
base::ThreadTaskRunnerHandle::Get()));
wrapper_->InitInternal(user_data_directory, std::move(database_task_manager),
base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr);
- wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id_);
+ wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id());
+ wrapper_->process_manager()->SetNewProcessIdForTest(new_render_process_id());
registry()->AddChildProcessSender(mock_render_process_id_, this,
NewMessagePortMessageFilter());
@@ -98,7 +102,7 @@ EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
new ServiceRegistryImpl);
render_process_service_registry_.ServiceRegistry::AddService(
base::Bind(&MockEmbeddedWorkerSetup::Create, weak_factory_.GetWeakPtr()));
- mojo::ServiceProviderPtr services;
+ mojo::shell::mojom::InterfaceProviderPtr services;
render_process_service_registry_.Bind(mojo::GetProxy(&services));
host_service_registry->BindRemoteServiceProvider(std::move(services));
render_process_host_->SetServiceRegistry(std::move(host_service_registry));
@@ -128,6 +132,8 @@ bool EmbeddedWorkerTestHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerTestHelper, message)
IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_StartWorker, OnStartWorkerStub)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_ResumeAfterDownload,
+ OnResumeAfterDownloadStub)
IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_StopWorker, OnStopWorkerStub)
IPC_MESSAGE_HANDLER(EmbeddedWorkerContextMsg_MessageToWorker,
OnMessageToWorkerStub)
@@ -153,14 +159,20 @@ void EmbeddedWorkerTestHelper::ShutdownContext() {
void EmbeddedWorkerTestHelper::OnStartWorker(int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
- const GURL& script_url) {
+ const GURL& script_url,
+ bool pause_after_download) {
embedded_worker_id_service_worker_version_id_map_[embedded_worker_id] =
service_worker_version_id;
SimulateWorkerReadyForInspection(embedded_worker_id);
SimulateWorkerScriptCached(embedded_worker_id);
SimulateWorkerScriptLoaded(embedded_worker_id);
- SimulateWorkerThreadStarted(next_thread_id_++, embedded_worker_id);
- SimulateWorkerScriptEvaluated(embedded_worker_id);
+ if (!pause_after_download)
+ OnResumeAfterDownload(embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::OnResumeAfterDownload(int embedded_worker_id) {
+ SimulateWorkerThreadStarted(GetNextThreadId(), embedded_worker_id);
+ SimulateWorkerScriptEvaluated(embedded_worker_id, true /* success */);
SimulateWorkerStarted(embedded_worker_id);
}
@@ -177,6 +189,8 @@ bool EmbeddedWorkerTestHelper::OnMessageToWorker(
current_embedded_worker_id_ = embedded_worker_id;
IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerTestHelper, message)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent, OnActivateEventStub)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ExtendableMessageEvent,
+ OnExtendableMessageEventStub)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEventStub)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEventStub)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEventStub)
@@ -197,6 +211,13 @@ void EmbeddedWorkerTestHelper::OnActivateEvent(int embedded_worker_id,
blink::WebServiceWorkerEventResultCompleted));
}
+void EmbeddedWorkerTestHelper::OnExtendableMessageEvent(int embedded_worker_id,
+ int request_id) {
+ SimulateSend(new ServiceWorkerHostMsg_ExtendableMessageEventFinished(
+ embedded_worker_id, request_id,
+ blink::WebServiceWorkerEventResultCompleted));
+}
+
void EmbeddedWorkerTestHelper::OnInstallEvent(int embedded_worker_id,
int request_id) {
// The installing worker may have been doomed and terminated.
@@ -218,12 +239,14 @@ void EmbeddedWorkerTestHelper::OnFetchEvent(
ServiceWorkerResponse(GURL(), 200, "OK",
blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(), std::string(), 0, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown)));
+ blink::WebServiceWorkerResponseErrorUnknown,
+ base::Time(), false /* is_in_cache_storage */,
+ std::string() /* cache_storage_cache_name */)));
}
void EmbeddedWorkerTestHelper::OnPushEvent(int embedded_worker_id,
int request_id,
- const std::string& data) {
+ const PushEventPayload& payload) {
SimulateSend(new ServiceWorkerHostMsg_PushEventFinished(
embedded_worker_id, request_id,
blink::WebServiceWorkerEventResultCompleted));
@@ -270,11 +293,12 @@ void EmbeddedWorkerTestHelper::SimulateWorkerThreadStarted(
}
void EmbeddedWorkerTestHelper::SimulateWorkerScriptEvaluated(
- int embedded_worker_id) {
+ int embedded_worker_id,
+ bool success) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
ASSERT_TRUE(worker != NULL);
- registry()->OnWorkerScriptEvaluated(
- worker->process_id(), embedded_worker_id, true /* success */);
+ registry()->OnWorkerScriptEvaluated(worker->process_id(), embedded_worker_id,
+ success);
}
void EmbeddedWorkerTestHelper::SimulateWorkerStarted(
@@ -310,7 +334,16 @@ void EmbeddedWorkerTestHelper::OnStartWorkerStub(
base::Bind(&EmbeddedWorkerTestHelper::OnStartWorker,
weak_factory_.GetWeakPtr(), params.embedded_worker_id,
params.service_worker_version_id, params.scope,
- params.script_url));
+ params.script_url, params.pause_after_download));
+}
+
+void EmbeddedWorkerTestHelper::OnResumeAfterDownloadStub(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnResumeAfterDownload,
+ weak_factory_.GetWeakPtr(), embedded_worker_id));
}
void EmbeddedWorkerTestHelper::OnStopWorkerStub(int embedded_worker_id) {
@@ -342,11 +375,18 @@ void EmbeddedWorkerTestHelper::OnMessageToWorkerStub(
void EmbeddedWorkerTestHelper::OnActivateEventStub(int request_id) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&EmbeddedWorkerTestHelper::OnActivateEvent,
- weak_factory_.GetWeakPtr(),
- current_embedded_worker_id_,
- request_id));
+ FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnActivateEvent,
+ weak_factory_.GetWeakPtr(),
+ current_embedded_worker_id_, request_id));
+}
+
+void EmbeddedWorkerTestHelper::OnExtendableMessageEventStub(
+ int request_id,
+ const ServiceWorkerMsg_ExtendableMessageEvent_Params& params) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnExtendableMessageEvent,
+ weak_factory_.GetWeakPtr(),
+ current_embedded_worker_id_, request_id));
}
void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id) {
@@ -370,18 +410,19 @@ void EmbeddedWorkerTestHelper::OnFetchEventStub(
request));
}
-void EmbeddedWorkerTestHelper::OnPushEventStub(int request_id,
- const std::string& data) {
+void EmbeddedWorkerTestHelper::OnPushEventStub(
+ int request_id,
+ const PushEventPayload& payload) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnPushEvent,
weak_factory_.GetWeakPtr(),
- current_embedded_worker_id_, request_id, data));
+ current_embedded_worker_id_, request_id, payload));
}
void EmbeddedWorkerTestHelper::OnSetupMojoStub(
int thread_id,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr exposed_services) {
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services) {
scoped_ptr<ServiceRegistryImpl> new_registry(new ServiceRegistryImpl);
new_registry->Bind(std::move(services));
new_registry->BindRemoteServiceProvider(std::move(exposed_services));
diff --git a/chromium/content/browser/service_worker/embedded_worker_test_helper.h b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
index a95454a9490..a9d34b511ad 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
@@ -21,8 +21,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-struct EmbeddedWorkerMsg_StartWorker_Params;
class GURL;
+struct EmbeddedWorkerMsg_StartWorker_Params;
+struct ServiceWorkerMsg_ExtendableMessageEvent_Params;
namespace content {
@@ -32,8 +33,9 @@ class MessagePortMessageFilter;
class MockRenderProcessHost;
class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper;
-struct ServiceWorkerFetchRequest;
class TestBrowserContext;
+struct PushEventPayload;
+struct ServiceWorkerFetchRequest;
// In-Process EmbeddedWorker test helper.
//
@@ -77,12 +79,21 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); }
void ShutdownContext();
- int mock_render_process_id() const { return mock_render_process_id_;}
- // Mock render process. Only set if the one-parameter constructor was used.
+ int GetNextThreadId() { return next_thread_id_++; }
+
+ int mock_render_process_id() const { return mock_render_process_id_; }
MockRenderProcessHost* mock_render_process_host() {
return render_process_host_.get();
}
+ std::map<int, int64_t> embedded_worker_id_service_worker_version_id_map() {
+ return embedded_worker_id_service_worker_version_id_map_;
+ }
+
+ // Only used for tests that force creating a new render process. There is no
+ // corresponding MockRenderProcessHost.
+ int new_render_process_id() const { return mock_render_process_id_ + 1; }
+
TestBrowserContext* browser_context() { return browser_context_.get(); }
protected:
@@ -95,7 +106,9 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
virtual void OnStartWorker(int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
- const GURL& script_url);
+ const GURL& script_url,
+ bool pause_after_download);
+ virtual void OnResumeAfterDownload(int embedded_worker_id);
virtual void OnStopWorker(int embedded_worker_id);
virtual bool OnMessageToWorker(int thread_id,
int embedded_worker_id,
@@ -110,13 +123,14 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
// worker. By default they just return success via
// SimulateSendReplyToBrowser.
virtual void OnActivateEvent(int embedded_worker_id, int request_id);
+ virtual void OnExtendableMessageEvent(int embedded_worker_id, int request_id);
virtual void OnInstallEvent(int embedded_worker_id, int request_id);
virtual void OnFetchEvent(int embedded_worker_id,
int request_id,
const ServiceWorkerFetchRequest& request);
virtual void OnPushEvent(int embedded_worker_id,
int request_id,
- const std::string& data);
+ const PushEventPayload& payload);
// These functions simulate sending an EmbeddedHostMsg message to the
// browser.
@@ -124,7 +138,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
void SimulateWorkerScriptCached(int embedded_worker_id);
void SimulateWorkerScriptLoaded(int embedded_worker_id);
void SimulateWorkerThreadStarted(int thread_id, int embedded_worker_id);
- void SimulateWorkerScriptEvaluated(int embedded_worker_id);
+ void SimulateWorkerScriptEvaluated(int embedded_worker_id, bool success);
void SimulateWorkerStarted(int embedded_worker_id);
void SimulateWorkerStopped(int embedded_worker_id);
void SimulateSend(IPC::Message* message);
@@ -135,18 +149,23 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
class MockEmbeddedWorkerSetup;
void OnStartWorkerStub(const EmbeddedWorkerMsg_StartWorker_Params& params);
+ void OnResumeAfterDownloadStub(int embedded_worker_id);
void OnStopWorkerStub(int embedded_worker_id);
void OnMessageToWorkerStub(int thread_id,
int embedded_worker_id,
const IPC::Message& message);
void OnActivateEventStub(int request_id);
+ void OnExtendableMessageEventStub(
+ int request_id,
+ const ServiceWorkerMsg_ExtendableMessageEvent_Params& params);
void OnInstallEventStub(int request_id);
void OnFetchEventStub(int request_id,
const ServiceWorkerFetchRequest& request);
- void OnPushEventStub(int request_id, const std::string& data);
- void OnSetupMojoStub(int thread_id,
- mojo::InterfaceRequest<mojo::ServiceProvider> services,
- mojo::ServiceProviderPtr exposed_services);
+ void OnPushEventStub(int request_id, const PushEventPayload& payload);
+ void OnSetupMojoStub(
+ int thread_id,
+ mojo::shell::mojom::InterfaceProviderRequest services,
+ mojo::shell::mojom::InterfaceProviderPtr exposed_services);
MessagePortMessageFilter* NewMessagePortMessageFilter();
diff --git a/chromium/content/browser/service_worker/foreign_fetch_request_handler.cc b/chromium/content/browser/service_worker/foreign_fetch_request_handler.cc
index e86e6ecabf8..ec4d5cdb6b8 100644
--- a/chromium/content/browser/service_worker/foreign_fetch_request_handler.cc
+++ b/chromium/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -4,6 +4,8 @@
#include "content/browser/service_worker/foreign_fetch_request_handler.h"
+#include <string>
+
#include "base/macros.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_url_request_job.h"
@@ -120,8 +122,9 @@ net::URLRequestJob* ForeignFetchRequestHandler::MaybeCreateJob(
ServiceWorkerURLRequestJob* job = new ServiceWorkerURLRequestJob(
request, network_delegate, std::string(), blob_storage_context_,
- resource_context, request_mode_, credentials_mode_, redirect_mode_, false,
- request_context_type_, frame_type_, body_, this);
+ resource_context, request_mode_, credentials_mode_, redirect_mode_,
+ resource_type_, request_context_type_, frame_type_, body_,
+ ServiceWorkerFetchType::FOREIGN_FETCH, this);
job_ = job->GetWeakPtr();
context_->FindReadyRegistrationForDocument(
@@ -179,7 +182,14 @@ void ForeignFetchRequestHandler::DidFindRegistration(
}
}
- if (!scope_matches) {
+ const url::Origin& request_origin = job->request()->initiator();
+ bool origin_matches = active_version->foreign_fetch_origins().empty();
+ for (const url::Origin& origin : active_version->foreign_fetch_origins()) {
+ if (request_origin.IsSameOriginWith(origin))
+ origin_matches = true;
+ }
+
+ if (!scope_matches || !origin_matches) {
job->FallbackToNetwork();
return;
}
@@ -201,7 +211,9 @@ void ForeignFetchRequestHandler::OnStartCompleted(
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks service_worker_start_time,
- base::TimeTicks service_worker_ready_time) {}
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) {}
ServiceWorkerVersion* ForeignFetchRequestHandler::GetServiceWorkerVersion(
ServiceWorkerMetrics::URLRequestJobResult* result) {
@@ -214,11 +226,6 @@ ServiceWorkerVersion* ForeignFetchRequestHandler::GetServiceWorkerVersion(
return target_worker_.get();
}
-GURL ForeignFetchRequestHandler::GetRequestingOrigin() {
- // TODO(mek): Implement this.
- return GURL();
-}
-
void ForeignFetchRequestHandler::ClearJob() {
job_.reset();
target_worker_ = nullptr;
diff --git a/chromium/content/browser/service_worker/foreign_fetch_request_handler.h b/chromium/content/browser/service_worker/foreign_fetch_request_handler.h
index 196f7e0f013..9bbf4ea1c1a 100644
--- a/chromium/content/browser/service_worker/foreign_fetch_request_handler.h
+++ b/chromium/content/browser/service_worker/foreign_fetch_request_handler.h
@@ -106,10 +106,11 @@ class CONTENT_EXPORT ForeignFetchRequestHandler
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks worker_start_time,
- base::TimeTicks service_worker_ready_time) override;
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) override;
ServiceWorkerVersion* GetServiceWorkerVersion(
ServiceWorkerMetrics::URLRequestJobResult* result) override;
- GURL GetRequestingOrigin() override;
// Sets |job_| to nullptr, and clears all extra response info associated with
// that job.
diff --git a/chromium/content/browser/service_worker/link_header_support.cc b/chromium/content/browser/service_worker/link_header_support.cc
new file mode 100644
index 00000000000..1a957c72693
--- /dev/null
+++ b/chromium/content/browser/service_worker/link_header_support.cc
@@ -0,0 +1,311 @@
+// 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 "content/browser/service_worker/link_header_support.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/origin_util.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+namespace {
+
+// A variation of base::StringTokenizer and net::HttpUtil::ValuesIterator.
+// Takes the parsing of StringTokenizer and adds support for quoted strings that
+// are quoted by matching <> (and does not support escaping in those strings).
+// Also has the behavior of ValuesIterator where it strips whitespace from all
+// values and only outputs non-empty values.
+// Only supports ',' as separator and supports '' "" and <> as quote chars.
+// TODO(mek): Figure out if there is a way to share this with the parsing code
+// in blink::LinkHeader.
+class ValueTokenizer {
+ public:
+ ValueTokenizer(std::string::const_iterator begin,
+ std::string::const_iterator end)
+ : token_begin_(begin), token_end_(begin), end_(end) {}
+
+ std::string::const_iterator token_begin() const { return token_begin_; }
+ std::string::const_iterator token_end() const { return token_end_; }
+
+ bool GetNext() {
+ while (GetNextInternal()) {
+ net::HttpUtil::TrimLWS(&token_begin_, &token_end_);
+
+ // Only return non-empty values.
+ if (token_begin_ != token_end_)
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ // Updates token_begin_ and token_end_ to point to the (possibly empty) next
+ // token. Returns false if end-of-string was reached first.
+ bool GetNextInternal() {
+ // First time this is called token_end_ points to the first character in the
+ // input. Every other time token_end_ points to the delimiter at the end of
+ // the last returned token (which could be the end of the string).
+
+ // End of string, return false.
+ if (token_end_ == end_)
+ return false;
+
+ // Skip past the delimiter.
+ if (*token_end_ == ',')
+ ++token_end_;
+
+ // Make token_begin_ point to the beginning of the next token, and search
+ // for the end of the token in token_end_.
+ token_begin_ = token_end_;
+
+ // Set to true if we're currently inside a quoted string.
+ bool in_quote = false;
+ // Set to true if we're currently inside a quoted string, and have just
+ // encountered an escape character. In this case a closing quote will be
+ // ignored.
+ bool in_escape = false;
+ // If currently in a quoted string, this is the character that (when not
+ // escaped) indicates the end of the string.
+ char quote_close_char = '\0';
+ // If currently in a quoted string, this is set to true if it is possible to
+ // escape the closing quote using '\'.
+ bool quote_allows_escape = false;
+
+ while (token_end_ != end_) {
+ char c = *token_end_;
+ if (in_quote) {
+ if (in_escape) {
+ in_escape = false;
+ } else if (quote_allows_escape && c == '\\') {
+ in_escape = true;
+ } else if (c == quote_close_char) {
+ in_quote = false;
+ }
+ } else {
+ if (c == ',')
+ break;
+ if (c == '\'' || c == '"' || c == '<') {
+ in_quote = true;
+ quote_close_char = (c == '<' ? '>' : c);
+ quote_allows_escape = (c != '<');
+ }
+ }
+ ++token_end_;
+ }
+ return true;
+ }
+
+ std::string::const_iterator token_begin_;
+ std::string::const_iterator token_end_;
+ std::string::const_iterator end_;
+};
+
+// Parses one link in a link header into its url and parameters.
+// A link is of the form "<some-url>; param1=value1; param2=value2".
+// Returns false if parsing the link failed, returns true on success. This
+// method is more lenient than the RFC. It doesn't fail on things like invalid
+// characters in the URL, and also doesn't verify that certain parameters should
+// or shouldn't be quoted strings.
+// If a parameter occurs more than once in the link, only the first value is
+// returned in params as this is the required behavior for all attributes chrome
+// currently cares about in link headers.
+bool ParseLink(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ std::string* url,
+ std::unordered_map<std::string, std::string>* params) {
+ // Can't parse an empty string.
+ if (begin == end)
+ return false;
+
+ // Extract the URL part (everything between '<' and first '>' character).
+ if (*begin != '<')
+ return false;
+ ++begin;
+ std::string::const_iterator url_begin = begin;
+ std::string::const_iterator url_end = std::find(begin, end, '>');
+ // Fail if we did not find a '>'.
+ if (url_end == end)
+ return false;
+ begin = url_end;
+ net::HttpUtil::TrimLWS(&url_begin, &url_end);
+ *url = std::string(url_begin, url_end);
+
+ // Skip the '>' at the end of the URL, trim any remaining whitespace, and make
+ // sure it is followed by a ';' to indicate the start of parameters.
+ ++begin;
+ net::HttpUtil::TrimLWS(&begin, &end);
+ if (begin != end && *begin != ';')
+ return false;
+
+ // Parse all the parameters.
+ net::HttpUtil::NameValuePairsIterator params_iterator(
+ begin, end, ';', net::HttpUtil::NameValuePairsIterator::VALUES_OPTIONAL);
+ while (params_iterator.GetNext()) {
+ if (!net::HttpUtil::IsToken(params_iterator.name_begin(),
+ params_iterator.name_end()))
+ return false;
+ std::string name = base::ToLowerASCII(base::StringPiece(
+ params_iterator.name_begin(), params_iterator.name_end()));
+ params->insert(std::make_pair(name, params_iterator.value()));
+ }
+ return params_iterator.valid();
+}
+
+void RegisterServiceWorkerFinished(int64_t trace_id, bool result) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "LinkHeaderResourceThrottle::HandleServiceWorkerLink",
+ trace_id, "Success", result);
+}
+
+void HandleServiceWorkerLink(
+ const net::URLRequest* request,
+ const std::string& url,
+ const std::unordered_map<std::string, std::string>& params,
+ ServiceWorkerContextWrapper* service_worker_context_for_testing) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ // TODO(mek): Integrate with experimental framework.
+ return;
+ }
+
+ if (ContainsKey(params, "anchor"))
+ return;
+
+ const ResourceRequestInfoImpl* request_info =
+ ResourceRequestInfoImpl::ForRequest(request);
+ ResourceMessageFilter* filter = request_info->filter();
+ ServiceWorkerContext* service_worker_context =
+ filter ? filter->service_worker_context()
+ : service_worker_context_for_testing;
+ if (!service_worker_context)
+ return;
+
+ // TODO(mek): serviceworker links should only be supported on requests from
+ // secure contexts. For now just check the initiator origin, even though that
+ // is not correct: 1) the initiator isn't the origin that matters in case of
+ // navigations, and 2) more than just a secure origin this needs to be a
+ // secure context.
+ if (!request->initiator().unique() &&
+ !IsOriginSecure(GURL(request->initiator().Serialize())))
+ return;
+
+ // TODO(mek): support for a serviceworker link on a request that wouldn't ever
+ // be able to be intercepted by a serviceworker isn't very useful, so this
+ // should share logic with ServiceWorkerRequestHandler and
+ // ForeignFetchRequestHandler to limit the requests for which serviceworker
+ // links are processed.
+
+ GURL context_url = request->url();
+ GURL script_url = context_url.Resolve(url);
+ auto scope_param = params.find("scope");
+ GURL scope_url = scope_param == params.end()
+ ? script_url.Resolve("./")
+ : context_url.Resolve(scope_param->second);
+
+ if (!context_url.is_valid() || !script_url.is_valid() ||
+ !scope_url.is_valid())
+ return;
+ if (!ServiceWorkerUtils::CanRegisterServiceWorker(context_url, scope_url,
+ script_url))
+ return;
+ std::string error;
+ if (ServiceWorkerUtils::ContainsDisallowedCharacter(scope_url, script_url,
+ &error))
+ return;
+
+ int render_process_id = -1;
+ int render_frame_id = -1;
+ ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_id,
+ &render_frame_id);
+
+ if (!GetContentClient()->browser()->AllowServiceWorker(
+ scope_url, request->first_party_for_cookies(),
+ request_info->GetContext(), render_process_id, render_frame_id))
+ return;
+
+ static int64_t trace_id = 0;
+ TRACE_EVENT_ASYNC_BEGIN2(
+ "ServiceWorker", "LinkHeaderResourceThrottle::HandleServiceWorkerLink",
+ ++trace_id, "Pattern", scope_url.spec(), "Script URL", script_url.spec());
+ service_worker_context->RegisterServiceWorker(
+ scope_url, script_url,
+ base::Bind(&RegisterServiceWorkerFinished, trace_id));
+}
+
+void ProcessLinkHeaderValueForRequest(
+ const net::URLRequest* request,
+ std::string::const_iterator value_begin,
+ std::string::const_iterator value_end,
+ ServiceWorkerContextWrapper* service_worker_context_for_testing) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::string url;
+ std::unordered_map<std::string, std::string> params;
+ if (!ParseLink(value_begin, value_end, &url, &params))
+ return;
+
+ for (const auto& rel :
+ base::SplitStringPiece(params["rel"], HTTP_LWS, base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ if (base::EqualsCaseInsensitiveASCII(rel, "serviceworker"))
+ HandleServiceWorkerLink(request, url, params,
+ service_worker_context_for_testing);
+ }
+}
+
+} // namespace
+
+void ProcessRequestForLinkHeaders(const net::URLRequest* request) {
+ std::string link_header;
+ request->GetResponseHeaderByName("link", &link_header);
+ if (link_header.empty())
+ return;
+
+ ProcessLinkHeaderForRequest(request, link_header);
+}
+
+void ProcessLinkHeaderForRequest(
+ const net::URLRequest* request,
+ const std::string& link_header,
+ ServiceWorkerContextWrapper* service_worker_context_for_testing) {
+ ValueTokenizer tokenizer(link_header.begin(), link_header.end());
+ while (tokenizer.GetNext()) {
+ ProcessLinkHeaderValueForRequest(request, tokenizer.token_begin(),
+ tokenizer.token_end(),
+ service_worker_context_for_testing);
+ }
+}
+
+void SplitLinkHeaderForTesting(const std::string& header,
+ std::vector<std::string>* values) {
+ values->clear();
+ ValueTokenizer tokenizer(header.begin(), header.end());
+ while (tokenizer.GetNext()) {
+ values->push_back(
+ std::string(tokenizer.token_begin(), tokenizer.token_end()));
+ }
+}
+
+bool ParseLinkHeaderValueForTesting(
+ const std::string& link,
+ std::string* url,
+ std::unordered_map<std::string, std::string>* params) {
+ return ParseLink(link.begin(), link.end(), url, params);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/link_header_support.h b/chromium/content/browser/service_worker/link_header_support.h
new file mode 100644
index 00000000000..b47a6b06503
--- /dev/null
+++ b/chromium/content/browser/service_worker/link_header_support.h
@@ -0,0 +1,38 @@
+// 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 CONTENT_BROWSER_SERVICE_WORKER_LINK_HEADER_SUPPORT_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_LINK_HEADER_SUPPORT_H_
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace net {
+class URLRequest;
+}
+
+namespace content {
+class ServiceWorkerContextWrapper;
+
+void ProcessRequestForLinkHeaders(const net::URLRequest* request);
+
+CONTENT_EXPORT void ProcessLinkHeaderForRequest(
+ const net::URLRequest* request,
+ const std::string& link_header,
+ ServiceWorkerContextWrapper* service_worker_context_for_testing = nullptr);
+
+CONTENT_EXPORT void SplitLinkHeaderForTesting(const std::string& header,
+ std::vector<std::string>* values);
+CONTENT_EXPORT bool ParseLinkHeaderValueForTesting(
+ const std::string& link,
+ std::string* url,
+ std::unordered_map<std::string, std::string>* params);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_LINK_HEADER_SUPPORT_H_
diff --git a/chromium/content/browser/service_worker/link_header_support_unittest.cc b/chromium/content/browser/service_worker/link_header_support_unittest.cc
new file mode 100644
index 00000000000..ae293fe720e
--- /dev/null
+++ b/chromium/content/browser/service_worker/link_header_support_unittest.cc
@@ -0,0 +1,410 @@
+// 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 "content/browser/service_worker/link_header_support.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+TEST(LinkHeaderTest, SplitEmpty) {
+ std::vector<std::string> values;
+ SplitLinkHeaderForTesting("", &values);
+ ASSERT_EQ(0u, values.size());
+}
+
+TEST(LinkHeaderTest, SplitSimple) {
+ std::vector<std::string> values;
+ SplitLinkHeaderForTesting("hello", &values);
+ ASSERT_EQ(1u, values.size());
+ EXPECT_EQ("hello", values[0]);
+
+ SplitLinkHeaderForTesting("foo, bar", &values);
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ("foo", values[0]);
+ EXPECT_EQ("bar", values[1]);
+
+ SplitLinkHeaderForTesting(" 1\t,\t2,3", &values);
+ ASSERT_EQ(3u, values.size());
+ EXPECT_EQ("1", values[0]);
+ EXPECT_EQ("2", values[1]);
+ EXPECT_EQ("3", values[2]);
+}
+
+TEST(LinkHeaderTest, SplitSkipsEmpty) {
+ std::vector<std::string> values;
+ SplitLinkHeaderForTesting(", foo, , \t, bar", &values);
+ ASSERT_EQ(2u, values.size());
+ EXPECT_EQ("foo", values[0]);
+ EXPECT_EQ("bar", values[1]);
+}
+
+TEST(LinkHeaderTest, SplitQuotes) {
+ std::vector<std::string> values;
+ SplitLinkHeaderForTesting("\"foo,bar\", 'bar,foo', <hel,lo>", &values);
+ ASSERT_EQ(3u, values.size());
+ EXPECT_EQ("\"foo,bar\"", values[0]);
+ EXPECT_EQ("'bar,foo'", values[1]);
+ EXPECT_EQ("<hel,lo>", values[2]);
+}
+
+TEST(LinkHeaderTest, SplitEscapedQuotes) {
+ std::vector<std::string> values;
+ SplitLinkHeaderForTesting("\"f\\\"oo,bar\", 'b\\'ar,foo', <hel\\>,lo>",
+ &values);
+ ASSERT_EQ(4u, values.size());
+ EXPECT_EQ("\"f\\\"oo,bar\"", values[0]);
+ EXPECT_EQ("'b\\'ar,foo'", values[1]);
+ EXPECT_EQ("<hel\\>", values[2]);
+ EXPECT_EQ("lo>", values[3]);
+}
+
+struct SimpleParseTestData {
+ const char* link;
+ bool valid;
+ const char* url;
+ const char* rel;
+ const char* as;
+};
+
+void PrintTo(const SimpleParseTestData& test, std::ostream* os) {
+ *os << ::testing::PrintToString(test.link);
+}
+
+class SimpleParseTest : public ::testing::TestWithParam<SimpleParseTestData> {};
+
+TEST_P(SimpleParseTest, Simple) {
+ const SimpleParseTestData test = GetParam();
+
+ std::string url;
+ std::unordered_map<std::string, std::string> params;
+ EXPECT_EQ(test.valid,
+ ParseLinkHeaderValueForTesting(test.link, &url, &params));
+ if (test.valid) {
+ EXPECT_EQ(test.url, url);
+ EXPECT_EQ(test.rel, params["rel"]);
+ EXPECT_EQ(test.as, params["as"]);
+ }
+}
+
+// Test data mostly copied from blink::LinkHeaderTest. Expectations for some
+// test cases are different though. Mostly because blink::LinkHeader is stricter
+// about validity while parsing (primarily things like mismatched quotes), and
+// factors in knowledge about semantics of Link headers (parameters that are
+// required to have a value if they occur, some parameters are auto-lower-cased,
+// headers with an "anchor" parameter are rejected by base::LinkHeader).
+// The code this tests purely parses without actually interpreting the data, as
+// it is expected that another layer on top will do more specific validations.
+const SimpleParseTestData simple_parse_tests[] = {
+ {"</images/cat.jpg>; rel=prefetch", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg>;rel=prefetch", true, "/images/cat.jpg", "prefetch", ""},
+ {"</images/cat.jpg> ;rel=prefetch", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg> ; rel=prefetch", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"< /images/cat.jpg> ; rel=prefetch", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/cat.jpg > ; rel=prefetch", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/cat.jpg wutwut> ; rel=prefetch", true,
+ "/images/cat.jpg wutwut", "prefetch", ""},
+ {"</images/cat.jpg wutwut \t > ; rel=prefetch", true,
+ "/images/cat.jpg wutwut", "prefetch", ""},
+ {"</images/cat.jpg>; rel=prefetch ", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg>; Rel=prefetch ", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg>; Rel=PReFetCh ", true, "/images/cat.jpg", "PReFetCh",
+ ""},
+ {"</images/cat.jpg>; rel=prefetch; rel=somethingelse", true,
+ "/images/cat.jpg", "prefetch", ""},
+ {"</images/cat.jpg>\t\t ; \trel=prefetch \t ", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/cat.jpg>; rel= prefetch", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"<../images/cat.jpg?dog>; rel= prefetch", true, "../images/cat.jpg?dog",
+ "prefetch", ""},
+ {"</images/cat.jpg>; rel =prefetch", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg>; rel pel=prefetch", false},
+ {"< /images/cat.jpg>", true, "/images/cat.jpg", "", ""},
+ {"</images/cat.jpg>; wut=sup; rel =prefetch", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/cat.jpg>; wut=sup ; rel =prefetch", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/cat.jpg>; wut=sup ; rel =prefetch \t ;", true,
+ "/images/cat.jpg", "prefetch", ""},
+ {"</images/cat.jpg> wut=sup ; rel =prefetch \t ;", false},
+ {"< /images/cat.jpg", false},
+ {"< http://wut.com/ sdfsdf ?sd>; rel=dns-prefetch", true,
+ "http://wut.com/ sdfsdf ?sd", "dns-prefetch", ""},
+ {"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=dns-prefetch", true,
+ "http://wut.com/%20%20%3dsdfsdf?sd", "dns-prefetch", ""},
+ {"< http://wut.com/dfsdf?sdf=ghj&wer=rty>; rel=prefetch", true,
+ "http://wut.com/dfsdf?sdf=ghj&wer=rty", "prefetch", ""},
+ {"< http://wut.com/dfsdf?sdf=ghj&wer=rty>;;;;; rel=prefetch", true,
+ "http://wut.com/dfsdf?sdf=ghj&wer=rty", "prefetch", ""},
+ {"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=preload;as=image", true,
+ "http://wut.com/%20%20%3dsdfsdf?sd", "preload", "image"},
+ {"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=preload;as=whatever", true,
+ "http://wut.com/%20%20%3dsdfsdf?sd", "preload", "whatever"},
+ {"</images/cat.jpg>; rel=prefetch;", true, "/images/cat.jpg", "prefetch",
+ ""},
+ {"</images/cat.jpg>; rel=prefetch ;", true, "/images/cat.jpg",
+ "prefetch", ""},
+ {"</images/ca,t.jpg>; rel=prefetch ;", true, "/images/ca,t.jpg",
+ "prefetch", ""},
+ {"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE and "
+ "backslash\"",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE \\\" and "
+ "backslash: \\\"",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; title=\"title with a DQUOTE \\\" and backslash: \"; "
+ "rel=stylesheet; ",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; title=\'title with a DQUOTE \\\' and backslash: \'; "
+ "rel=stylesheet; ",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; title=\"title with a DQUOTE \\\" and ;backslash,: \"; "
+ "rel=stylesheet; ",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; title=\"title with a DQUOTE \' and ;backslash,: \"; "
+ "rel=stylesheet; ",
+ true, "simple.css", "stylesheet", ""},
+ {"<simple.css>; title=\"\"; rel=stylesheet; ", true, "simple.css",
+ "stylesheet", ""},
+ {"<simple.css>; title=\"\"; rel=\"stylesheet\"; ", true, "simple.css",
+ "stylesheet", ""},
+ {"<simple.css>; rel=stylesheet; title=\"", true, "simple.css", "stylesheet",
+ ""},
+ {"<simple.css>; rel=stylesheet; title=\"\"", true, "simple.css",
+ "stylesheet", ""},
+ {"<simple.css>; rel=\"stylesheet\"; title=\"", true, "simple.css",
+ "stylesheet", ""},
+ {"<simple.css>; rel=\";style,sheet\"; title=\"", true, "simple.css",
+ ";style,sheet", ""},
+ {"<simple.css>; rel=\"bla'sdf\"; title=\"", true, "simple.css", "bla'sdf",
+ ""},
+ {"<simple.css>; rel=\"\"; title=\"\"", true, "simple.css", "", ""},
+ {"<simple.css>; rel=''; title=\"\"", true, "simple.css", "", ""},
+ {"<simple.css>; rel=''; bla", true, "simple.css", "", ""},
+ {"<simple.css>; rel='prefetch", true, "simple.css", "prefetch", ""},
+ {"<simple.css>; rel=\"prefetch", true, "simple.css", "prefetch", ""},
+ {"<simple.css>; rel=\"", true, "simple.css", "", ""},
+ {"simple.css; rel=prefetch", false},
+ {"<simple.css>; rel=prefetch; rel=foobar", true, "simple.css", "prefetch",
+ ""},
+};
+
+INSTANTIATE_TEST_CASE_P(LinkHeaderTest,
+ SimpleParseTest,
+ testing::ValuesIn(simple_parse_tests));
+
+void SaveFoundRegistrationsCallback(
+ ServiceWorkerStatusCode expected_status,
+ bool* called,
+ std::vector<ServiceWorkerRegistrationInfo>* registrations,
+ ServiceWorkerStatusCode status,
+ const std::vector<ServiceWorkerRegistrationInfo>& result) {
+ EXPECT_EQ(expected_status, status);
+ *called = true;
+ *registrations = result;
+}
+
+ServiceWorkerContextWrapper::GetRegistrationsInfosCallback
+SaveFoundRegistrations(
+ ServiceWorkerStatusCode expected_status,
+ bool* called,
+ std::vector<ServiceWorkerRegistrationInfo>* registrations) {
+ *called = false;
+ return base::Bind(&SaveFoundRegistrationsCallback, expected_status, called,
+ registrations);
+}
+
+class LinkHeaderServiceWorkerTest : public ::testing::Test {
+ public:
+ LinkHeaderServiceWorkerTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ resource_context_(&request_context_) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+ ~LinkHeaderServiceWorkerTest() override {}
+
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
+ }
+
+ void TearDown() override { helper_.reset(); }
+
+ ServiceWorkerContextWrapper* context_wrapper() {
+ return helper_->context_wrapper();
+ }
+
+ void ProcessLinkHeader(const GURL& request_url,
+ const std::string& link_header) {
+ scoped_ptr<net::URLRequest> request = request_context_.CreateRequest(
+ request_url, net::DEFAULT_PRIORITY, &request_delegate_);
+ ResourceRequestInfo::AllocateForTesting(
+ request.get(), RESOURCE_TYPE_SCRIPT, &resource_context_,
+ -1 /* render_process_id */, -1 /* render_view_id */,
+ -1 /* render_frame_id */, false /* is_main_frame */,
+ false /* parent_is_main_frame */, true /* allow_download */,
+ true /* is_async */, false /* is_using_lofi */);
+
+ ProcessLinkHeaderForRequest(request.get(), link_header, context_wrapper());
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::vector<ServiceWorkerRegistrationInfo> GetRegistrations() {
+ bool called;
+ std::vector<ServiceWorkerRegistrationInfo> registrations;
+ context_wrapper()->GetAllRegistrations(
+ SaveFoundRegistrations(SERVICE_WORKER_OK, &called, &registrations));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ return registrations;
+ }
+
+ private:
+ TestBrowserThreadBundle thread_bundle_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ net::TestURLRequestContext request_context_;
+ net::TestDelegate request_delegate_;
+ MockResourceContext resource_context_;
+};
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_Basic) {
+ ProcessLinkHeader(GURL("https://example.com/foo/bar/"),
+ "<../foo.js>; rel=serviceworker");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(1u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foo/"), registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/foo/foo.js"),
+ registrations[0].active_version.script_url);
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeWithFragment) {
+ ProcessLinkHeader(GURL("https://example.com/foo/bar/"),
+ "<../bar.js>; rel=serviceworker; scope=\"scope#ref\"");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(1u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foo/bar/scope"),
+ registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/foo/bar.js"),
+ registrations[0].active_version.script_url);
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeAbsoluteUrl) {
+ ProcessLinkHeader(GURL("https://example.com/foo/bar/"),
+ "<bar.js>; rel=serviceworker; "
+ "scope=\"https://example.com:443/foo/bar/scope\"");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(1u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foo/bar/scope"),
+ registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/foo/bar/bar.js"),
+ registrations[0].active_version.script_url);
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeDifferentOrigin) {
+ ProcessLinkHeader(
+ GURL("https://example.com/foobar/"),
+ "<bar.js>; rel=serviceworker; scope=\"https://google.com/scope\"");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(0u, registrations.size());
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeUrlEncodedSlash) {
+ ProcessLinkHeader(GURL("https://example.com/foobar/"),
+ "<bar.js>; rel=serviceworker; scope=\"./foo%2Fbar\"");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(0u, registrations.size());
+}
+
+TEST_F(LinkHeaderServiceWorkerTest,
+ InstallServiceWorker_ScriptUrlEncodedSlash) {
+ ProcessLinkHeader(GURL("https://example.com/foobar/"),
+ "<foo%2Fbar.js>; rel=serviceworker");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(0u, registrations.size());
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScriptAbsoluteUrl) {
+ ProcessLinkHeader(
+ GURL("https://example.com/foobar/"),
+ "<https://example.com/bar.js>; rel=serviceworker; scope=foo");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(1u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foobar/foo"), registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/bar.js"),
+ registrations[0].active_version.script_url);
+}
+
+TEST_F(LinkHeaderServiceWorkerTest,
+ InstallServiceWorker_ScriptDifferentOrigin) {
+ ProcessLinkHeader(
+ GURL("https://example.com/foobar/"),
+ "<https://google.com/bar.js>; rel=serviceworker; scope=foo");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(0u, registrations.size());
+}
+
+TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_MultipleWorkers) {
+ ProcessLinkHeader(GURL("https://example.com/foobar/"),
+ "<bar.js>; rel=serviceworker; scope=foo, <baz.js>; "
+ "rel=serviceworker; scope=scope");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(2u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foobar/foo"), registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/foobar/bar.js"),
+ registrations[0].active_version.script_url);
+ EXPECT_EQ(GURL("https://example.com/foobar/scope"), registrations[1].pattern);
+ EXPECT_EQ(GURL("https://example.com/foobar/baz.js"),
+ registrations[1].active_version.script_url);
+}
+
+TEST_F(LinkHeaderServiceWorkerTest,
+ InstallServiceWorker_ValidAndInvalidValues) {
+ ProcessLinkHeader(
+ GURL("https://example.com/foobar/"),
+ "<https://google.com/bar.js>; rel=serviceworker; scope=foo, <baz.js>; "
+ "rel=serviceworker; scope=scope");
+
+ std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations();
+ ASSERT_EQ(1u, registrations.size());
+ EXPECT_EQ(GURL("https://example.com/foobar/scope"), registrations[0].pattern);
+ EXPECT_EQ(GURL("https://example.com/foobar/baz.js"),
+ registrations[0].active_version.script_url);
+}
+
+} // namespace
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_browsertest.cc b/chromium/content/browser/service_worker/service_worker_browsertest.cc
index 205f067a1eb..b8f99a4b3b3 100644
--- a/chromium/content/browser/service_worker/service_worker_browsertest.cc
+++ b/chromium/content/browser/service_worker/service_worker_browsertest.cc
@@ -4,16 +4,22 @@
#include <stddef.h>
#include <stdint.h>
+#include <map>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
@@ -21,6 +27,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
@@ -29,19 +36,25 @@
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/referrer.h"
+#include "content/public/common/resource_type.h"
#include "content/public/common/security_style.h"
#include "content/public/common/ssl_status.h"
+#include "content/public/common/web_preferences.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 "content/shell/browser/shell.h"
#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/test/test_content_browser_client.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
@@ -74,12 +87,9 @@ void RunOnIOThreadWithDelay(const base::Closure& closure,
base::TimeDelta delay) {
base::RunLoop run_loop;
BrowserThread::PostDelayedTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&RunAndQuit,
- closure,
- run_loop.QuitClosure(),
- base::ThreadTaskRunnerHandle::Get()),
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
+ base::RetainedRef(base::ThreadTaskRunnerHandle::Get())),
delay);
run_loop.Run();
}
@@ -110,38 +120,6 @@ base::Closure CreatePrepareReceiver(bool* is_prepared) {
return base::Bind(&ReceivePrepareResult, is_prepared);
}
-// Contrary to the style guide, the output parameter of this function comes
-// before input parameters so Bind can be used on it to create a FetchCallback
-// to pass to DispatchFetchEvent.
-void ReceiveFetchResult(BrowserThread::ID run_quit_thread,
- const base::Closure& quit,
- ChromeBlobStorageContext* blob_context,
- FetchResult* out_result,
- ServiceWorkerStatusCode actual_status,
- ServiceWorkerFetchEventResult actual_result,
- const ServiceWorkerResponse& actual_response) {
- out_result->status = actual_status;
- out_result->result = actual_result;
- out_result->response = actual_response;
- if (!actual_response.blob_uuid.empty()) {
- out_result->blob_data_handle =
- blob_context->context()->GetBlobDataFromUUID(
- actual_response.blob_uuid);
- }
- if (!quit.is_null())
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
-}
-
-ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
- BrowserThread::ID run_quit_thread,
- const base::Closure& quit,
- ChromeBlobStorageContext* blob_context,
- FetchResult* result) {
- return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
- make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
- result);
-}
-
void ReceiveFindRegistrationStatus(
BrowserThread::ID run_quit_thread,
const base::Closure& quit,
@@ -224,6 +202,53 @@ scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
return std::move(http_response);
}
+scoped_ptr<net::test_server::HttpResponse> VerifySaveDataHeaderInRequest(
+ const net::test_server::HttpRequest& request) {
+ auto it = request.headers.find("Save-Data");
+ EXPECT_NE(request.headers.end(), it);
+ EXPECT_EQ("on", it->second);
+
+ scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse());
+ http_response->set_content_type("text/javascript");
+ return std::move(http_response);
+}
+
+scoped_ptr<net::test_server::HttpResponse> VerifySaveDataHeaderNotInRequest(
+ const net::test_server::HttpRequest& request) {
+ auto it = request.headers.find("Save-Data");
+ EXPECT_EQ(request.headers.end(), it);
+ return make_scoped_ptr(new net::test_server::BasicHttpResponse());
+}
+
+scoped_ptr<net::test_server::HttpResponse>
+VerifySaveDataNotInAccessControlRequestHeader(
+ const net::test_server::HttpRequest& request) {
+ // Save-Data should be present.
+ auto it = request.headers.find("Save-Data");
+ EXPECT_NE(request.headers.end(), it);
+ EXPECT_EQ("on", it->second);
+
+ scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse());
+ if (request.method == net::test_server::METHOD_OPTIONS) {
+ // Access-Control-Request-Headers should contain 'X-Custom-Header' and not
+ // contain 'Save-Data'.
+ auto acrh_iter = request.headers.find("Access-Control-Request-Headers");
+ EXPECT_NE(request.headers.end(), acrh_iter);
+ EXPECT_NE(std::string::npos, acrh_iter->second.find("x-custom-header"));
+ EXPECT_EQ(std::string::npos, acrh_iter->second.find("save-data"));
+ http_response->AddCustomHeader("Access-Control-Allow-Headers",
+ acrh_iter->second);
+ http_response->AddCustomHeader("Access-Control-Allow-Methods", "GET");
+ http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
+ } else {
+ http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
+ http_response->set_content("PASS");
+ }
+ return std::move(http_response);
+}
+
// The ImportsBustMemcache test requires that the imported script
// would naturally be cached in blink's memcache, but the embedded
// test server doesn't produce headers that allow the blink's memcache
@@ -231,7 +256,7 @@ scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
// an experiration far in the future.
class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
public:
- LongLivedResourceInterceptor(const std::string& body)
+ explicit LongLivedResourceInterceptor(const std::string& body)
: body_(body) {}
~LongLivedResourceInterceptor() override {}
@@ -597,17 +622,30 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
void StartOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
- version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiver(BrowserThread::UI, done, result));
}
void InstallOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
- version_->DispatchInstallEvent(
+ version_->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::INSTALL,
+ base::Bind(&self::DispatchInstallEventOnIOThread, this, done, result),
CreateReceiver(BrowserThread::UI, done, result));
}
+ void DispatchInstallEventOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ int request_id =
+ version_->StartRequest(ServiceWorkerMetrics::EventType::INSTALL,
+ CreateReceiver(BrowserThread::UI, done, result));
+ version_->DispatchSimpleEvent<ServiceWorkerHostMsg_InstallEventFinished>(
+ request_id, ServiceWorkerMsg_InstallEvent(request_id));
+ }
+
void StoreOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result,
int64_t version_id) {
@@ -624,26 +662,69 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
registration_->SetActiveVersion(version_.get());
- version_->DispatchActivateEvent(
+ version_->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::ACTIVATE,
+ base::Bind(&self::DispatchActivateEventOnIOThread, this, done, result),
CreateReceiver(BrowserThread::UI, done, result));
}
+ void DispatchActivateEventOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ int request_id =
+ version_->StartRequest(ServiceWorkerMetrics::EventType::INSTALL,
+ CreateReceiver(BrowserThread::UI, done, result));
+ version_->DispatchSimpleEvent<ServiceWorkerHostMsg_ActivateEventFinished>(
+ request_id, ServiceWorkerMsg_ActivateEvent(request_id));
+ }
+
void FetchOnIOThread(const base::Closure& done,
bool* prepare_result,
FetchResult* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ServiceWorkerFetchRequest request(
- embedded_test_server()->GetURL("/service_worker/empty.html"),
- "GET",
- ServiceWorkerHeaderMap(),
- Referrer(),
- false);
+ scoped_ptr<ServiceWorkerFetchRequest> request(new ServiceWorkerFetchRequest(
+ embedded_test_server()->GetURL("/service_worker/empty.html"), "GET",
+ ServiceWorkerHeaderMap(), Referrer(), false));
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->DispatchFetchEvent(
- request,
+ fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
+ std::move(request), version_.get(), RESOURCE_TYPE_MAIN_FRAME,
CreatePrepareReceiver(prepare_result),
- CreateResponseReceiver(
- BrowserThread::UI, done, blob_context_.get(), result));
+ CreateResponseReceiver(done, blob_context_.get(), result)));
+ fetch_dispatcher_->Run();
+ }
+
+ // Contrary to the style guide, the output parameter of this function comes
+ // before input parameters so Bind can be used on it to create a FetchCallback
+ // to pass to DispatchFetchEvent.
+ void ReceiveFetchResultOnIOThread(
+ const base::Closure& quit,
+ ChromeBlobStorageContext* blob_context,
+ FetchResult* out_result,
+ ServiceWorkerStatusCode actual_status,
+ ServiceWorkerFetchEventResult actual_result,
+ const ServiceWorkerResponse& actual_response,
+ const scoped_refptr<ServiceWorkerVersion>& worker) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ASSERT_TRUE(fetch_dispatcher_);
+ fetch_dispatcher_.reset();
+ out_result->status = actual_status;
+ out_result->result = actual_result;
+ out_result->response = actual_response;
+ if (!actual_response.blob_uuid.empty()) {
+ out_result->blob_data_handle =
+ blob_context->context()->GetBlobDataFromUUID(
+ actual_response.blob_uuid);
+ }
+ if (!quit.is_null())
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
+ }
+
+ ServiceWorkerFetchDispatcher::FetchCallback CreateResponseReceiver(
+ const base::Closure& quit,
+ ChromeBlobStorageContext* blob_context,
+ FetchResult* result) {
+ return base::Bind(&self::ReceiveFetchResultOnIOThread, this, quit,
+ base::RetainedRef(blob_context), result);
}
void StopOnIOThread(const base::Closure& done,
@@ -656,6 +737,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
scoped_refptr<ChromeBlobStorageContext> blob_context_;
+ scoped_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
};
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
@@ -791,13 +873,13 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
ActivateTestHelper("/service_worker/worker_activate_rejected.js",
- SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
+ SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
InstallWithWaitUntil_Rejected) {
InstallTestHelper("/service_worker/worker_install_rejected.js",
- SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
+ SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
@@ -815,7 +897,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
base::Bind(&self::InstallOnIOThread, this,
install_run_loop.QuitClosure(), &status));
install_run_loop.Run();
- ASSERT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
+ ASSERT_EQ(SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED, status);
const base::string16 expected =
base::ASCIIToUTF16("Rejecting oninstall event");
@@ -827,7 +909,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
class WaitForLoaded : public EmbeddedWorkerInstance::Listener {
public:
- WaitForLoaded(const base::Closure& quit) : quit_(quit) {}
+ explicit WaitForLoaded(const base::Closure& quit) : quit_(quit) {}
void OnThreadStarted() override {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
@@ -838,10 +920,7 @@ class WaitForLoaded : public EmbeddedWorkerInstance::Listener {
base::Closure quit_;
};
-// This test has started flaking somewhat consistently on Win, Mac and Linux.
-// Disabling for now, see http://crbug.com/496065.
-IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
- DISABLED_TimeoutStartingWorker) {
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutStartingWorker) {
RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
"/service_worker/while_true_worker.js"));
@@ -897,7 +976,9 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent) {
base::TimeDelta::FromMilliseconds(100));
install_run_loop.Run();
- EXPECT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
+ // Terminating a worker, even one in an infinite loop, is treated as if
+ // waitUntil was rejected in the renderer code.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED, status);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
@@ -922,6 +1003,35 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ FetchEvent_ResponseViaCache) {
+ ServiceWorkerFetchEventResult result;
+ ServiceWorkerResponse response1;
+ ServiceWorkerResponse response2;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+ const base::Time start_time(base::Time::Now());
+
+ RunOnIOThread(
+ base::Bind(&self::SetUpRegistrationOnIOThread, this,
+ "/service_worker/fetch_event_response_via_cache.js"));
+
+ FetchOnRegisteredWorker(&result, &response1, &blob_data_handle);
+ ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
+ EXPECT_EQ(200, response1.status_code);
+ EXPECT_EQ("OK", response1.status_text);
+ EXPECT_TRUE(response1.response_time >= start_time);
+ EXPECT_FALSE(response1.is_in_cache_storage);
+ EXPECT_EQ(std::string(), response2.cache_storage_cache_name);
+
+ FetchOnRegisteredWorker(&result, &response2, &blob_data_handle);
+ ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
+ EXPECT_EQ(200, response2.status_code);
+ EXPECT_EQ("OK", response2.status_text);
+ EXPECT_EQ(response1.response_time, response2.response_time);
+ EXPECT_TRUE(response2.is_in_cache_storage);
+ EXPECT_EQ("cache_name", response2.cache_storage_cache_name);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
FetchEvent_respondWithRejection) {
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
@@ -950,6 +1060,174 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
ASSERT_FALSE(blob_data_handle);
}
+class MockContentBrowserClient : public TestContentBrowserClient {
+ public:
+ MockContentBrowserClient()
+ : TestContentBrowserClient(), data_saver_enabled_(false) {}
+
+ ~MockContentBrowserClient() override {}
+
+ void set_data_saver_enabled(bool enabled) { data_saver_enabled_ = enabled; }
+
+ // ContentBrowserClient overrides:
+ bool IsDataSaverEnabled(BrowserContext* context) override {
+ return data_saver_enabled_;
+ }
+
+ void OverrideWebkitPrefs(RenderViewHost* render_view_host,
+ WebPreferences* prefs) override {
+ prefs->data_saver_enabled = data_saver_enabled_;
+ }
+
+ private:
+ bool data_saver_enabled_;
+};
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchWithSaveData) {
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifySaveDataHeaderInRequest));
+ MockContentBrowserClient content_browser_client;
+ content_browser_client.set_data_saver_enabled(true);
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ InstallTestHelper("/service_worker/fetch_in_install.js", SERVICE_WORKER_OK);
+ SetBrowserClientForTesting(old_client);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ RequestWorkerScriptWithSaveData) {
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifySaveDataHeaderInRequest));
+ MockContentBrowserClient content_browser_client;
+ content_browser_client.set_data_saver_enabled(true);
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
+ SetBrowserClientForTesting(old_client);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchWithoutSaveData) {
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifySaveDataHeaderNotInRequest));
+ MockContentBrowserClient content_browser_client;
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ InstallTestHelper("/service_worker/fetch_in_install.js", SERVICE_WORKER_OK);
+ SetBrowserClientForTesting(old_client);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, FetchPageWithSaveData) {
+ const char kPageUrl[] = "/service_worker/handle_fetch.html";
+ const char kWorkerUrl[] = "/service_worker/add_save_data_to_title.js";
+ MockContentBrowserClient content_browser_client;
+ content_browser_client.set_data_saver_enabled(true);
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ shell()->web_contents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+ observer->Wait();
+
+ const base::string16 title1 = base::ASCIIToUTF16("save-data=on");
+ TitleWatcher title_watcher1(shell()->web_contents(), title1);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ EXPECT_EQ(title1, title_watcher1.WaitAndGetTitle());
+
+ SetBrowserClientForTesting(old_client);
+ shell()->Close();
+
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+// Tests that when data saver is enabled and a cross-origin fetch by a webpage
+// is intercepted by a serviceworker, and the serviceworker does a fetch, the
+// preflight request does not have save-data in Access-Control-Request-Headers.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, CrossOriginFetchWithSaveData) {
+ const char kPageUrl[] = "/service_worker/fetch_cross_origin.html";
+ const char kWorkerUrl[] = "/service_worker/fetch_event_pass_through.js";
+ net::EmbeddedTestServer cross_origin_server;
+ cross_origin_server.ServeFilesFromSourceDirectory("content/test/data");
+ cross_origin_server.RegisterRequestHandler(
+ base::Bind(&VerifySaveDataNotInAccessControlRequestHeader));
+ cross_origin_server.Start();
+
+ MockContentBrowserClient content_browser_client;
+ content_browser_client.set_data_saver_enabled(true);
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ shell()->web_contents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+ observer->Wait();
+
+ const base::string16 title = base::ASCIIToUTF16("PASS");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(),
+ embedded_test_server()->GetURL(base::StringPrintf(
+ "%s?%s", kPageUrl,
+ cross_origin_server.GetURL("/cross_origin_request.html")
+ .spec()
+ .c_str())));
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+
+ SetBrowserClientForTesting(old_client);
+ shell()->Close();
+
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
+ FetchPageWithSaveDataPassThroughOnFetch) {
+ const char kPageUrl[] = "/service_worker/pass_through_fetch.html";
+ const char kWorkerUrl[] = "/service_worker/fetch_event_pass_through.js";
+ MockContentBrowserClient content_browser_client;
+ content_browser_client.set_data_saver_enabled(true);
+ ContentBrowserClient* old_client =
+ SetBrowserClientForTesting(&content_browser_client);
+ shell()->web_contents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+ observer->Wait();
+
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifySaveDataHeaderInRequest));
+
+ NavigateToURLBlockUntilNavigationsComplete(
+ shell(), embedded_test_server()->GetURL(kPageUrl), 1);
+
+ SetBrowserClientForTesting(old_client);
+ shell()->Close();
+
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
const char kPageUrl[] = "/service_worker/reload.html";
const char kWorkerUrl[] = "/service_worker/fetch_event_reload.js";
diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
index bc0eac40557..8c88982c718 100644
--- a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
@@ -11,7 +11,6 @@
#include <string>
#include "base/macros.h"
-#include "base/stl_util.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,7 +37,10 @@ namespace {
// there are any expected reads that have not yet happened.
class MockServiceWorkerResponseReader : public ServiceWorkerResponseReader {
public:
- MockServiceWorkerResponseReader() : ServiceWorkerResponseReader(0, nullptr) {}
+ MockServiceWorkerResponseReader()
+ : ServiceWorkerResponseReader(
+ 0,
+ base::WeakPtr<AppCacheDiskCacheInterface>()) {}
~MockServiceWorkerResponseReader() override {}
// ServiceWorkerResponseReader overrides
@@ -90,6 +92,8 @@ class MockServiceWorkerResponseReader : public ServiceWorkerResponseReader {
size_t pending_buffer_len_;
scoped_refptr<HttpResponseInfoIOBuffer> pending_info_;
net::CompletionCallback pending_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerResponseReader);
};
void MockServiceWorkerResponseReader::ReadInfo(
@@ -194,7 +198,9 @@ void MockServiceWorkerResponseReader::CompletePendingRead() {
class MockServiceWorkerResponseWriter : public ServiceWorkerResponseWriter {
public:
MockServiceWorkerResponseWriter()
- : ServiceWorkerResponseWriter(0, nullptr),
+ : ServiceWorkerResponseWriter(
+ 0,
+ base::WeakPtr<AppCacheDiskCacheInterface>()),
info_written_(0),
data_written_(0) {}
~MockServiceWorkerResponseWriter() override {}
@@ -236,6 +242,8 @@ class MockServiceWorkerResponseWriter : public ServiceWorkerResponseWriter {
size_t data_written_;
net::CompletionCallback pending_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerResponseWriter);
};
void MockServiceWorkerResponseWriter::WriteInfo(
@@ -311,14 +319,14 @@ void MockServiceWorkerResponseWriter::CompletePendingWrite() {
class ServiceWorkerCacheWriterTest : public ::testing::Test {
public:
- ServiceWorkerCacheWriterTest()
- : readers_deleter_(&readers_), writers_deleter_(&writers_) {}
+ ServiceWorkerCacheWriterTest() {}
+ ~ServiceWorkerCacheWriterTest() override {}
MockServiceWorkerResponseReader* ExpectReader() {
scoped_ptr<MockServiceWorkerResponseReader> reader(
new MockServiceWorkerResponseReader);
MockServiceWorkerResponseReader* borrowed_reader = reader.get();
- readers_.push_back(reader.release()); // give ownership to |readers_|
+ readers_.push_back(std::move(reader));
return borrowed_reader;
}
@@ -326,7 +334,7 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test {
scoped_ptr<MockServiceWorkerResponseWriter> writer(
new MockServiceWorkerResponseWriter);
MockServiceWorkerResponseWriter* borrowed_writer = writer.get();
- writers_.push_back(writer.release()); // give ownership to |writers_|
+ writers_.push_back(std::move(writer));
return borrowed_writer;
}
@@ -340,17 +348,8 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test {
}
protected:
- // TODO(ellyjones): when unique_ptr<> is allowed, make these instead:
- // std::list<unique_ptr<...>>
- // Right now, these cannot use scoped_ptr.
- // Their elements are deleted by the STLElementDeleters below when this object
- // goes out of scope.
- std::list<MockServiceWorkerResponseReader*> readers_;
- std::list<MockServiceWorkerResponseWriter*> writers_;
- STLElementDeleter<std::list<MockServiceWorkerResponseReader*>>
- readers_deleter_;
- STLElementDeleter<std::list<MockServiceWorkerResponseWriter*>>
- writers_deleter_;
+ std::list<scoped_ptr<MockServiceWorkerResponseReader>> readers_;
+ std::list<scoped_ptr<MockServiceWorkerResponseWriter>> writers_;
scoped_ptr<ServiceWorkerCacheWriter> cache_writer_;
bool write_complete_ = false;
net::Error last_error_;
@@ -358,14 +357,15 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test {
scoped_ptr<ServiceWorkerResponseReader> CreateReader() {
if (readers_.empty())
return make_scoped_ptr<ServiceWorkerResponseReader>(nullptr);
- scoped_ptr<ServiceWorkerResponseReader> reader(readers_.front());
+ scoped_ptr<ServiceWorkerResponseReader> reader(std::move(readers_.front()));
readers_.pop_front();
return reader;
}
+
scoped_ptr<ServiceWorkerResponseWriter> CreateWriter() {
if (writers_.empty())
return make_scoped_ptr<ServiceWorkerResponseWriter>(nullptr);
- scoped_ptr<ServiceWorkerResponseWriter> writer(writers_.front());
+ scoped_ptr<ServiceWorkerResponseWriter> writer(std::move(writers_.front()));
writers_.pop_front();
return writer;
}
@@ -391,6 +391,9 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test {
return cache_writer_->MaybeWriteData(buf.get(), data.size(),
CreateWriteCallback());
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheWriterTest);
};
// Passthrough tests:
diff --git a/chromium/content/browser/service_worker/service_worker_client_utils.cc b/chromium/content/browser/service_worker/service_worker_client_utils.cc
index 26ef4d35f18..93fe0f3ef33 100644
--- a/chromium/content/browser/service_worker/service_worker_client_utils.cc
+++ b/chromium/content/browser/service_worker/service_worker_client_utils.cc
@@ -11,13 +11,17 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/storage_partition_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/service_worker/service_worker_client_info.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/child_process_host.h"
@@ -90,8 +94,60 @@ class OpenURLObserver : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(OpenURLObserver);
};
+ServiceWorkerClientInfo GetWindowClientInfoOnUI(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& client_uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ if (!render_frame_host)
+ return ServiceWorkerClientInfo();
+
+ // TODO(mlamouri,michaeln): it is possible to end up collecting information
+ // for a frame that is actually being navigated and isn't exactly what we are
+ // expecting.
+ return ServiceWorkerClientInfo(
+ client_uuid, render_frame_host->GetVisibilityState(),
+ render_frame_host->IsFocused(), render_frame_host->GetLastCommittedURL(),
+ render_frame_host->GetParent() ? REQUEST_CONTEXT_FRAME_TYPE_NESTED
+ : REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ render_frame_host->frame_tree_node()->last_focus_time(),
+ blink::WebServiceWorkerClientTypeWindow);
+}
+
+ServiceWorkerClientInfo FocusOnUI(int render_process_id,
+ int render_frame_id,
+ const std::string& client_uuid) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderFrameHost(render_frame_host));
+
+ if (!render_frame_host || !web_contents)
+ return ServiceWorkerClientInfo();
+
+ FrameTreeNode* frame_tree_node = render_frame_host->frame_tree_node();
+
+ // Focus the frame in the frame tree node, in case it has changed.
+ frame_tree_node->frame_tree()->SetFocusedFrame(
+ frame_tree_node, render_frame_host->GetSiteInstance());
+
+ // Focus the frame's view to make sure the frame is now considered as focused.
+ render_frame_host->GetView()->Focus();
+
+ // Move the web contents to the foreground.
+ web_contents->Activate();
+
+ return GetWindowClientInfoOnUI(render_process_id, render_frame_id,
+ client_uuid);
+}
+
// This is only called for main frame navigations in OpenWindowOnUI().
-void DidOpenURL(const OpenURLCallback& callback, WebContents* web_contents) {
+void DidOpenURLOnUI(const OpenURLCallback& callback,
+ WebContents* web_contents) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(web_contents);
RenderFrameHostImpl* rfhi =
@@ -133,7 +189,7 @@ void OpenWindowOnUI(
true /* is_renderer_initiated */);
GetContentClient()->browser()->OpenURL(browser_context, params,
- base::Bind(&DidOpenURL, callback));
+ base::Bind(&DidOpenURLOnUI, callback));
}
void NavigateClientOnUI(const GURL& url,
@@ -176,15 +232,13 @@ void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context,
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!context) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(),
- ServiceWorkerClientInfo());
+ callback.Run(SERVICE_WORKER_ERROR_ABORT, ServiceWorkerClientInfo());
return;
}
if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
render_frame_id == MSG_ROUTING_NONE) {
- callback.Run(SERVICE_WORKER_ERROR_FAILED, std::string(),
- ServiceWorkerClientInfo());
+ callback.Run(SERVICE_WORKER_ERROR_FAILED, ServiceWorkerClientInfo());
return;
}
@@ -196,19 +250,23 @@ void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context,
provider_host->frame_id() != render_frame_id) {
continue;
}
- provider_host->GetWindowClientInfo(
- base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid()));
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&GetWindowClientInfoOnUI, provider_host->process_id(),
+ provider_host->route_id(), provider_host->client_uuid()),
+ base::Bind(callback, SERVICE_WORKER_OK));
return;
}
// If here, it means that no provider_host was found, in which case, the
// renderer should still be informed that the window was opened.
- callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo());
+ callback.Run(SERVICE_WORKER_OK, ServiceWorkerClientInfo());
}
void AddWindowClient(
ServiceWorkerProviderHost* host,
std::vector<base::Tuple<int, int, std::string>>* client_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (host->client_type() != blink::WebServiceWorkerClientTypeWindow)
return;
client_info->push_back(base::MakeTuple(host->process_id(), host->frame_id(),
@@ -218,6 +276,7 @@ void AddWindowClient(
void AddNonWindowClient(ServiceWorkerProviderHost* host,
const ServiceWorkerClientQueryOptions& options,
ServiceWorkerClients* clients) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
blink::WebServiceWorkerClientType host_client_type = host->client_type();
if (host_client_type == blink::WebServiceWorkerClientTypeWindow)
return;
@@ -225,12 +284,11 @@ void AddNonWindowClient(ServiceWorkerProviderHost* host,
options.client_type != host_client_type)
return;
- ServiceWorkerClientInfo client_info(blink::WebPageVisibilityStateHidden,
- false, // is_focused
- host->document_url(),
- REQUEST_CONTEXT_FRAME_TYPE_NONE,
- base::TimeTicks(), host_client_type);
- client_info.client_uuid = host->client_uuid();
+ ServiceWorkerClientInfo client_info(
+ host->client_uuid(), blink::WebPageVisibilityStateHidden,
+ false, // is_focused
+ host->document_url(), REQUEST_CONTEXT_FRAME_TYPE_NONE, base::TimeTicks(),
+ host_client_type);
clients->push_back(client_info);
}
@@ -239,12 +297,12 @@ void OnGetWindowClientsOnUI(
const std::vector<base::Tuple<int, int, std::string>>& clients_info,
const GURL& script_url,
const GetWindowClientsCallback& callback) {
- scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients);
for (const auto& it : clients_info) {
- ServiceWorkerClientInfo info =
- ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get<0>(it),
- base::get<1>(it));
+ ServiceWorkerClientInfo info = GetWindowClientInfoOnUI(
+ base::get<0>(it), base::get<1>(it), base::get<2>(it));
// If the request to the provider_host returned an empty
// ServiceWorkerClientInfo, that means that it wasn't possible to associate
@@ -259,7 +317,6 @@ void OnGetWindowClientsOnUI(
if (info.url.GetOrigin() != script_url.GetOrigin())
continue;
- info.client_uuid = base::get<2>(it);
clients->push_back(info);
}
@@ -287,6 +344,7 @@ void DidGetClients(const ClientsCallback& callback,
void GetNonWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
const ServiceWorkerClientQueryOptions& options,
ServiceWorkerClients* clients) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!options.include_uncontrolled) {
for (auto& controllee : controller->controllee_map())
AddNonWindowClient(controllee.second, options, clients);
@@ -343,6 +401,18 @@ void GetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
} // namespace
+void FocusWindowClient(ServiceWorkerProviderHost* provider_host,
+ const ClientCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_EQ(blink::WebServiceWorkerClientTypeWindow,
+ provider_host->client_type());
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&FocusOnUI, provider_host->process_id(),
+ provider_host->frame_id(), provider_host->client_uuid()),
+ callback);
+}
+
void OpenWindow(const GURL& url,
const GURL& script_url,
int worker_process_id,
@@ -371,6 +441,34 @@ void NavigateClient(const GURL& url,
base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback)));
}
+void GetClient(ServiceWorkerProviderHost* provider_host,
+ const ClientCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ blink::WebServiceWorkerClientType client_type = provider_host->client_type();
+ DCHECK(client_type == blink::WebServiceWorkerClientTypeWindow ||
+ client_type == blink::WebServiceWorkerClientTypeWorker ||
+ client_type == blink::WebServiceWorkerClientTypeSharedWorker)
+ << client_type;
+
+ if (client_type == blink::WebServiceWorkerClientTypeWindow) {
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&GetWindowClientInfoOnUI, provider_host->process_id(),
+ provider_host->route_id(), provider_host->client_uuid()),
+ callback);
+ return;
+ }
+
+ ServiceWorkerClientInfo client_info(
+ provider_host->client_uuid(), blink::WebPageVisibilityStateHidden,
+ false, // is_focused
+ provider_host->document_url(), REQUEST_CONTEXT_FRAME_TYPE_NONE,
+ base::TimeTicks(), provider_host->client_type());
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, client_info));
+}
+
void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
const ServiceWorkerClientQueryOptions& options,
const ClientsCallback& callback) {
diff --git a/chromium/content/browser/service_worker/service_worker_client_utils.h b/chromium/content/browser/service_worker/service_worker_client_utils.h
index 258268e1e0d..be46f6c13e7 100644
--- a/chromium/content/browser/service_worker/service_worker_client_utils.h
+++ b/chromium/content/browser/service_worker/service_worker_client_utils.h
@@ -17,6 +17,7 @@ class GURL;
namespace content {
class ServiceWorkerContextCore;
+class ServiceWorkerProviderHost;
class ServiceWorkerVersion;
struct ServiceWorkerClientInfo;
struct ServiceWorkerClientQueryOptions;
@@ -25,11 +26,17 @@ namespace service_worker_client_utils {
using NavigationCallback =
base::Callback<void(ServiceWorkerStatusCode status,
- const std::string& client_uuid,
const ServiceWorkerClientInfo& client_info)>;
+using ClientCallback =
+ base::Callback<void(const ServiceWorkerClientInfo& client_info)>;
using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
using ClientsCallback = base::Callback<void(ServiceWorkerClients* clients)>;
+// Focuses the window client associated with |provider_host|. |callback| is
+// called with the client information on completion.
+void FocusWindowClient(ServiceWorkerProviderHost* provider_host,
+ const ClientCallback& callback);
+
// Opens a new window and navigates it to |url|. |callback| is called with the
// window's client information on completion.
void OpenWindow(const GURL& url,
@@ -47,6 +54,11 @@ void NavigateClient(const GURL& url,
const base::WeakPtr<ServiceWorkerContextCore>& context,
const NavigationCallback& callback);
+// Gets the client specified by |provider_host|. |callback| is called with the
+// client information on completion.
+void GetClient(ServiceWorkerProviderHost* provider_host,
+ const ClientCallback& callback);
+
// Collects clients matched with |options|. |callback| is called with the client
// information sorted in MRU order (most recently focused order) on completion.
void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
diff --git a/chromium/content/browser/service_worker/service_worker_context_core.cc b/chromium/content/browser/service_worker/service_worker_context_core.cc
index f6aa2123468..1bf5d3e11ba 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_core.cc
@@ -4,6 +4,8 @@
#include "content/browser/service_worker/service_worker_context_core.h"
+#include <limits>
+#include <set>
#include <utility>
#include "base/barrier_closure.h"
@@ -102,8 +104,9 @@ class ClearAllServiceWorkersHelper
void DidGetAllRegistrations(
const base::WeakPtr<ServiceWorkerContextCore>& context,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
- if (!context)
+ if (!context || status != SERVICE_WORKER_OK)
return;
// Make a copy of live versions map because StopWorker() removes the version
// from it when we were starting up and don't have a process yet.
@@ -217,6 +220,7 @@ ServiceWorkerContextCore::ServiceWorkerContextCore(
: wrapper_(wrapper),
providers_(new ProcessToProviderMap),
provider_by_uuid_(new ProviderByClientUUIDMap),
+ force_update_on_page_load_(false),
next_handle_id_(0),
next_registration_handle_id_(0),
was_service_worker_registered_(false),
@@ -365,12 +369,6 @@ void ServiceWorkerContextCore::RegisterServiceWorker(
const RegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
was_service_worker_registered_ = true;
- if (storage()->IsDisabled()) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(),
- kInvalidServiceWorkerRegistrationId);
- return;
- }
-
job_coordinator_->Register(
pattern,
script_url,
@@ -385,9 +383,6 @@ void ServiceWorkerContextCore::UpdateServiceWorker(
ServiceWorkerRegistration* registration,
bool force_bypass_cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (storage()->IsDisabled())
- return;
-
job_coordinator_->Update(registration, force_bypass_cache);
}
@@ -398,44 +393,16 @@ void ServiceWorkerContextCore::UpdateServiceWorker(
ServiceWorkerProviderHost* provider_host,
const UpdateCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (storage()->IsDisabled()) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(),
- kInvalidServiceWorkerRegistrationId);
- return;
- }
-
job_coordinator_->Update(registration, force_bypass_cache,
skip_script_comparison, provider_host,
base::Bind(&ServiceWorkerContextCore::UpdateComplete,
AsWeakPtr(), callback));
}
-void ServiceWorkerContextCore::SetForceUpdateOnPageLoad(
- int64_t registration_id,
- bool force_update_on_page_load) {
- ServiceWorkerRegistration* registration =
- GetLiveRegistration(registration_id);
- if (!registration)
- return;
- registration->set_force_update_on_page_load(force_update_on_page_load);
-
- if (observer_list_.get()) {
- observer_list_->Notify(
- FROM_HERE,
- &ServiceWorkerContextObserver::OnForceUpdateOnPageLoadChanged,
- registration_id, force_update_on_page_load);
- }
-}
-
void ServiceWorkerContextCore::UnregisterServiceWorker(
const GURL& pattern,
const UnregistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (storage()->IsDisabled()) {
- callback.Run(SERVICE_WORKER_ERROR_ABORT);
- return;
- }
-
job_coordinator_->Unregister(
pattern,
base::Bind(&ServiceWorkerContextCore::UnregistrationComplete,
@@ -448,12 +415,6 @@ void ServiceWorkerContextCore::UnregisterServiceWorkers(
const GURL& origin,
const UnregistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (storage()->IsDisabled()) {
- // Not posting as new task to match implementations above.
- callback.Run(SERVICE_WORKER_ERROR_ABORT);
- return;
- }
-
storage()->GetAllRegistrationsInfos(base::Bind(
&ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin,
AsWeakPtr(), callback, origin));
@@ -462,7 +423,12 @@ void ServiceWorkerContextCore::UnregisterServiceWorkers(
void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
const UnregistrationCallback& result,
const GURL& origin,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+ if (status != SERVICE_WORKER_OK) {
+ result.Run(status);
+ return;
+ }
std::set<GURL> scopes;
for (const auto& registration_info : registrations) {
if (origin == registration_info.pattern.GetOrigin()) {
@@ -718,6 +684,36 @@ void ServiceWorkerContextCore::CheckHasServiceWorker(
AsWeakPtr(), other_url, callback));
}
+void ServiceWorkerContextCore::UpdateVersionFailureCount(
+ int64_t version_id,
+ ServiceWorkerStatusCode status) {
+ // Don't count these, they aren't start worker failures.
+ if (status == SERVICE_WORKER_ERROR_DISALLOWED)
+ return;
+
+ auto it = failure_counts_.find(version_id);
+ if (status == SERVICE_WORKER_OK) {
+ if (it != failure_counts_.end())
+ failure_counts_.erase(it);
+ return;
+ }
+
+ if (it != failure_counts_.end()) {
+ DCHECK_GT(it->second, 0);
+ if (it->second < std::numeric_limits<int>::max())
+ ++it->second;
+ } else {
+ failure_counts_[version_id] = 1;
+ }
+}
+
+int ServiceWorkerContextCore::GetVersionFailureCount(int64_t version_id) {
+ auto it = failure_counts_.find(version_id);
+ if (it == failure_counts_.end())
+ return 0;
+ return it->second;
+}
+
void ServiceWorkerContextCore::OnRunningStateChanged(
ServiceWorkerVersion* version) {
if (!observer_list_)
diff --git a/chromium/content/browser/service_worker/service_worker_context_core.h b/chromium/content/browser/service_worker/service_worker_context_core.h
index f9448864207..2551336bd45 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.h
+++ b/chromium/content/browser/service_worker/service_worker_context_core.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <map>
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -206,13 +207,15 @@ class CONTENT_EXPORT ServiceWorkerContextCore
ServiceWorkerProviderHost* provider_host,
const UpdateCallback& callback);
- // Used in DevTools to update the service worker registration without
- // consulting the browser cache while loading the controlled page. The loading
- // is delayed until the update completes and the new worker is activated. The
- // new worker skips the waiting state and immediately becomes active after
- // installed.
- void SetForceUpdateOnPageLoad(int64_t registration_id,
- bool force_update_on_page_load);
+ // Used in DevTools to update the service worker registrations without
+ // consulting the browser cache while loading the controlled page. The
+ // loading is delayed until the update completes and the new worker is
+ // activated. The new worker skips the waiting state and immediately
+ // becomes active after installed.
+ bool force_update_on_page_load() { return force_update_on_page_load_; }
+ void set_force_update_on_page_load(bool force_update_on_page_load) {
+ force_update_on_page_load_ = force_update_on_page_load;
+ }
// This class maintains collections of live instances, this class
// does not own these object or influence their lifetime.
@@ -276,6 +279,12 @@ class CONTENT_EXPORT ServiceWorkerContextCore
const GURL& other_url,
const ServiceWorkerContext::CheckHasServiceWorkerCallback callback);
+ void UpdateVersionFailureCount(int64_t version_id,
+ ServiceWorkerStatusCode status);
+ // Returns the count of consecutive start worker failures for the given
+ // version. The count resets to zero when the worker successfully starts.
+ int GetVersionFailureCount(int64_t version_id);
+
base::WeakPtr<ServiceWorkerContextCore> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -307,6 +316,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void DidGetAllRegistrationsForUnregisterForOrigin(
const UnregistrationCallback& result,
const GURL& origin,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations);
void DidFindRegistrationForCheckHasServiceWorker(
@@ -330,12 +340,14 @@ class CONTENT_EXPORT ServiceWorkerContextCore
std::map<int64_t, ServiceWorkerRegistration*> live_registrations_;
std::map<int64_t, ServiceWorkerVersion*> live_versions_;
std::map<int64_t, scoped_refptr<ServiceWorkerVersion>> protected_versions_;
+ std::map<int64_t /* version_id */, int /* count */> failure_counts_;
// PlzNavigate
// Map of ServiceWorkerNavigationHandleCores used for navigation requests.
std::map<int, ServiceWorkerNavigationHandleCore*>
navigation_handle_cores_map_;
+ bool force_update_on_page_load_;
int next_handle_id_;
int next_registration_handle_id_;
// Set in RegisterServiceWorker(), cleared in ClearAllServiceWorkersForTest().
diff --git a/chromium/content/browser/service_worker/service_worker_context_observer.h b/chromium/content/browser/service_worker/service_worker_context_observer.h
index 86c238546b8..b643153f951 100644
--- a/chromium/content/browser/service_worker/service_worker_context_observer.h
+++ b/chromium/content/browser/service_worker/service_worker_context_observer.h
@@ -80,8 +80,6 @@ class ServiceWorkerContextObserver {
const GURL& pattern) {}
virtual void OnRegistrationDeleted(int64_t registration_id,
const GURL& pattern) {}
- virtual void OnForceUpdateOnPageLoadChanged(int64_t registration_id,
- bool force_update_on_page_load) {}
// Notified when the storage corruption recovery is completed and all stored
// data is wiped out.
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler.cc b/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
index 8b76146de80..c354eae6cd3 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -83,6 +83,8 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
incumbent_resource_id =
stored_version->script_cache_map()->LookupResourceId(request->url());
}
+ if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER)
+ version_->embedded_worker()->OnURLJobCreatedForMainScript();
return new ServiceWorkerWriteToCacheJob(
request, network_delegate, resource_type_, context_, version_.get(),
extra_load_flags, resource_id, incumbent_resource_id);
@@ -90,6 +92,8 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
int64_t resource_id = kInvalidServiceWorkerResourceId;
if (ShouldReadFromScriptCache(request->url(), &resource_id)) {
+ if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER)
+ version_->embedded_worker()->OnURLJobCreatedForMainScript();
return new ServiceWorkerReadFromCacheJob(request, network_delegate,
resource_type_, context_, version_,
resource_id);
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index 94bc88e612b..260fd9d21db 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -17,6 +17,7 @@
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
#include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/browser/resource_request_info.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_context.h"
@@ -160,4 +161,30 @@ TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateForceBypassCache) {
EXPECT_TRUE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE);
}
+TEST_F(ServiceWorkerContextRequestHandlerTest,
+ ServiceWorkerDataRequestAnnotation) {
+ version_->SetStatus(ServiceWorkerVersion::NEW);
+ provider_host_->running_hosted_version_ = version_;
+
+ // Conduct a resource fetch for the main script.
+ const GURL kScriptUrl("http://host/script.js");
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
+ scoped_ptr<ServiceWorkerContextRequestHandler> handler(
+ new ServiceWorkerContextRequestHandler(
+ context()->AsWeakPtr(), provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ RESOURCE_TYPE_SERVICE_WORKER));
+ scoped_ptr<net::URLRequestJob> job(
+ handler->MaybeCreateJob(request.get(), nullptr, nullptr));
+ ASSERT_TRUE(job.get());
+ ServiceWorkerWriteToCacheJob* sw_job =
+ static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
+
+ // Verify that the request is properly annotated as originating from a
+ // Service Worker.
+ EXPECT_TRUE(ResourceRequestInfo::OriginatedFromServiceWorker(
+ sw_job->net_request_.get()));
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.cc b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
index d28f8bf6f96..55ed1ec7f8c 100644
--- a/chromium/content/browser/service_worker/service_worker_context_watcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
@@ -61,6 +61,7 @@ void ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread() {
}
void ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread(
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
context_->AddObserver(this);
@@ -280,17 +281,4 @@ void ServiceWorkerContextWatcher::OnRegistrationDeleted(int64_t registration_id,
ServiceWorkerRegistrationInfo::IS_DELETED);
}
-void ServiceWorkerContextWatcher::OnForceUpdateOnPageLoadChanged(
- int64_t registration_id,
- bool force_update_on_page_load) {
- ServiceWorkerRegistration* registration =
- context_->GetLiveRegistration(registration_id);
- if (!registration)
- return;
- std::vector<ServiceWorkerRegistrationInfo> registrations;
- registrations.push_back(registration->GetInfo());
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(registration_callback_, registrations));
-}
-
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.h b/chromium/content/browser/service_worker/service_worker_context_watcher.h
index 506418bacc1..0ba5a53f8ef 100644
--- a/chromium/content/browser/service_worker/service_worker_context_watcher.h
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.h
@@ -47,6 +47,7 @@ class ServiceWorkerContextWatcher
void GetStoredRegistrationsOnIOThread();
void OnStoredRegistrationsOnIOThread(
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations);
void StopOnIOThread();
@@ -98,8 +99,6 @@ class ServiceWorkerContextWatcher
const GURL& pattern) override;
void OnRegistrationDeleted(int64_t registration_id,
const GURL& pattern) override;
- void OnForceUpdateOnPageLoadChanged(int64_t registration_id,
- bool force_update_on_page_load) override;
base::ScopedPtrHashMap<int64_t, scoped_ptr<ServiceWorkerVersionInfo>>
version_info_map_;
diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
index cfe5d87e8f0..d513a6931db 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -29,7 +29,7 @@
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/special_storage_policy.h"
@@ -62,6 +62,7 @@ void StartActiveWorkerOnIO(
// it from being deleted while starting the worker. If the refcount of
// |registration| is 1, it will be deleted after WorkerStarted is called.
registration->active_version()->StartWorker(
+ ServiceWorkerMetrics::EventType::UNKNOWN,
base::Bind(WorkerStarted, callback));
return;
}
@@ -101,6 +102,8 @@ ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
}
ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
+ DCHECK(!resource_context_);
+ DCHECK(!request_context_getter_);
}
void ServiceWorkerContextWrapper::Init(
@@ -130,6 +133,28 @@ void ServiceWorkerContextWrapper::Shutdown() {
base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
}
+void ServiceWorkerContextWrapper::InitializeResourceContext(
+ ResourceContext* resource_context,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ resource_context_ = resource_context;
+ request_context_getter_ = request_context_getter;
+ // Can be null in tests.
+ if (request_context_getter_)
+ request_context_getter_->AddObserver(this);
+}
+
+void ServiceWorkerContextWrapper::OnContextShuttingDown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // OnContextShuttingDown is called when the ProfileIOData (ResourceContext) is
+ // shutting down, so call ShutdownOnIO() to clear resource_context_.
+ // This doesn't seem to be called when using content_shell, so we still must
+ // also call ShutdownOnIO() in Shutdown(), which is called when the storage
+ // partition is destroyed.
+ ShutdownOnIO();
+}
+
void ServiceWorkerContextWrapper::DeleteAndStartOver() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!context_core_) {
@@ -158,12 +183,6 @@ ResourceContext* ServiceWorkerContextWrapper::resource_context() {
return resource_context_;
}
-void ServiceWorkerContextWrapper::set_resource_context(
- ResourceContext* resource_context) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- resource_context_ = resource_context;
-}
-
static void FinishRegistrationOnIO(
const ServiceWorkerContext::ResultCallback& continuation,
ServiceWorkerStatusCode status,
@@ -192,10 +211,8 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker(
return;
}
if (!context_core_) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(continuation, false));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(continuation, false));
return;
}
context()->RegisterServiceWorker(
@@ -228,10 +245,8 @@ void ServiceWorkerContextWrapper::UnregisterServiceWorker(
return;
}
if (!context_core_) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(continuation, false));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(continuation, false));
return;
}
@@ -277,19 +292,17 @@ void ServiceWorkerContextWrapper::StartServiceWorker(
}
void ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad(
- int64_t registration_id,
bool force_update_on_page_load) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad, this,
- registration_id, force_update_on_page_load));
+ force_update_on_page_load));
return;
}
if (!context_core_)
return;
- context_core_->SetForceUpdateOnPageLoad(registration_id,
- force_update_on_page_load);
+ context_core_->set_force_update_on_page_load(force_update_on_page_load);
}
void ServiceWorkerContextWrapper::GetAllOriginsInfo(
@@ -309,6 +322,7 @@ void ServiceWorkerContextWrapper::GetAllOriginsInfo(
void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
const GetUsageInfoCallback& callback,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::vector<ServiceWorkerUsageInfo> usage_infos;
@@ -574,7 +588,8 @@ void ServiceWorkerContextWrapper::GetAllRegistrations(
const GetRegistrationsInfosCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!context_core_) {
- RunSoon(base::Bind(callback, std::vector<ServiceWorkerRegistrationInfo>()));
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT,
+ std::vector<ServiceWorkerRegistrationInfo>()));
return;
}
context_core_->storage()->GetAllRegistrationsInfos(callback);
@@ -657,15 +672,11 @@ void ServiceWorkerContextWrapper::InitInternal(
storage::SpecialStoragePolicy* special_storage_policy) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&ServiceWorkerContextWrapper::InitInternal,
- this,
- user_data_directory,
- base::Passed(&database_task_manager),
- disk_cache_thread,
- make_scoped_refptr(quota_manager_proxy),
- make_scoped_refptr(special_storage_policy)));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::InitInternal, this,
+ user_data_directory, base::Passed(&database_task_manager),
+ disk_cache_thread, base::RetainedRef(quota_manager_proxy),
+ base::RetainedRef(special_storage_policy)));
return;
}
// TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
@@ -683,6 +694,10 @@ void ServiceWorkerContextWrapper::InitInternal(
void ServiceWorkerContextWrapper::ShutdownOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Can be null in tests.
+ if (request_context_getter_)
+ request_context_getter_->RemoveObserver(this);
+ request_context_getter_ = nullptr;
resource_context_ = nullptr;
context_core_.reset();
}
diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.h b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
index a81e8889265..4009d3ce2aa 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <string>
#include <vector>
#include "base/files/file_path.h"
@@ -16,6 +17,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/common/content_export.h"
#include "content/public/browser/service_worker_context.h"
+#include "net/url_request/url_request_context_getter_observer.h"
namespace base {
class FilePath;
@@ -42,6 +44,7 @@ class StoragePartitionImpl;
// is what is used internally in the service worker lib.
class CONTENT_EXPORT ServiceWorkerContextWrapper
: NON_EXPORTED_BASE(public ServiceWorkerContext),
+ public net::URLRequestContextGetterObserver,
public base::RefCountedThreadSafe<ServiceWorkerContextWrapper> {
public:
using StatusCallback = base::Callback<void(ServiceWorkerStatusCode)>;
@@ -63,6 +66,14 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
storage::SpecialStoragePolicy* special_storage_policy);
void Shutdown();
+ // Must be called on the IO thread.
+ void InitializeResourceContext(
+ ResourceContext* resource_context,
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter);
+
+ // For net::URLRequestContextGetterObserver
+ void OnContextShuttingDown() override;
+
// Deletes all files on disk and restarts the system asynchronously. This
// leaves the system in a disabled state until it's done. This should be
// called on the IO thread.
@@ -79,8 +90,6 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// shutdown.
ResourceContext* resource_context();
- void set_resource_context(ResourceContext* resource_context);
-
// The process manager can be used on either UI or IO.
ServiceWorkerProcessManager* process_manager() {
return process_manager_.get();
@@ -102,11 +111,13 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
void StopAllServiceWorkersForOrigin(const GURL& origin) override;
void ClearAllServiceWorkersForTest(const base::Closure& callback) override;
+ // These methods must only be called from the IO thread.
ServiceWorkerRegistration* GetLiveRegistration(int64_t registration_id);
ServiceWorkerVersion* GetLiveVersion(int64_t version_id);
std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo();
std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo();
+ // Must be called from the IO thread.
void HasMainFrameProviderHost(const GURL& origin,
const BoolCallback& callback) const;
@@ -119,6 +130,8 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// - If the registration does not have the active version but has the waiting
// version, activates the waiting version and runs |callback| when it is
// activated.
+ //
+ // Must be called from the IO thread.
void FindReadyRegistrationForDocument(
const GURL& document_url,
const FindRegistrationCallback& callback);
@@ -132,10 +145,13 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// - If the registration does not have the active version but has the waiting
// version, activates the waiting version and runs |callback| when it is
// activated.
+ //
+ // Must be called from the IO thread.
void FindReadyRegistrationForId(int64_t registration_id,
const GURL& origin,
const FindRegistrationCallback& callback);
+ // All these methods must be called from the IO thread.
void GetAllRegistrations(const GetRegistrationsInfosCallback& callback);
void GetRegistrationUserData(int64_t registration_id,
const std::string& key,
@@ -152,15 +168,19 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
const std::string& key,
const GetUserDataForAllRegistrationsCallback& callback);
+ // This function can be called from any thread, but the callback will always
+ // be called on the UI thread.
void StartServiceWorker(const GURL& pattern, const StatusCallback& callback);
+
+ // These methods can be called from any thread.
void UpdateRegistration(const GURL& pattern);
- void SetForceUpdateOnPageLoad(int64_t registration_id,
- bool force_update_on_page_load);
+ void SetForceUpdateOnPageLoad(bool force_update_on_page_load);
void AddObserver(ServiceWorkerContextObserver* observer);
void RemoveObserver(ServiceWorkerContextObserver* observer);
bool is_incognito() const { return is_incognito_; }
+ // Must be called from the IO thread.
bool OriginHasForeignFetchRegistrations(const GURL& origin);
private:
@@ -198,6 +218,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
void DidGetAllRegistrationsForGetAllOrigins(
const GetUsageInfoCallback& callback,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations);
void DidCheckHasServiceWorker(const CheckHasServiceWorkerCallback& callback,
@@ -215,7 +236,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
const scoped_refptr<base::ObserverListThreadSafe<
ServiceWorkerContextObserver>> observer_list_;
const scoped_ptr<ServiceWorkerProcessManager> process_manager_;
- // Cleared in Shutdown():
+ // Cleared in ShutdownOnIO():
scoped_ptr<ServiceWorkerContextCore> context_core_;
// Initialized in Init(); true if the user data directory is empty.
@@ -227,6 +248,8 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// The ResourceContext associated with this context.
ResourceContext* resource_context_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextWrapper);
};
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 42e72fe1da8..88cc1b9191f 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -20,7 +20,7 @@
#include "content/public/common/content_client.h"
#include "content/public/common/resource_response_info.h"
#include "net/base/load_flags.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "net/url_request/url_request.h"
namespace content {
@@ -103,8 +103,8 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
scoped_ptr<ServiceWorkerURLRequestJob> job(new ServiceWorkerURLRequestJob(
request, network_delegate, provider_host_->client_uuid(),
blob_storage_context_, resource_context, request_mode_, credentials_mode_,
- redirect_mode_, is_main_resource_load_, request_context_type_,
- frame_type_, body_, this));
+ redirect_mode_, resource_type_, request_context_type_, frame_type_, body_,
+ ServiceWorkerFetchType::FETCH, this));
job_ = job->GetWeakPtr();
resource_context_ = resource_context;
@@ -143,6 +143,8 @@ void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
response_type_via_service_worker_;
response_info->service_worker_start_time = service_worker_start_time_;
response_info->service_worker_ready_time = service_worker_ready_time_;
+ response_info->is_in_cache_storage = response_is_in_cache_storage_;
+ response_info->cache_storage_cache_name = response_cache_storage_cache_name_;
}
void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
@@ -180,7 +182,7 @@ ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
return;
const bool need_to_update = !force_update_started_ && registration &&
- registration->force_update_on_page_load();
+ context_->force_update_on_page_load();
if (provider_host_ && !need_to_update)
provider_host_->SetAllowAssociation(true);
@@ -233,11 +235,9 @@ ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
if (active_version.get() &&
active_version->status() == ServiceWorkerVersion::ACTIVATING) {
provider_host_->SetAllowAssociation(false);
- registration->active_version()->RegisterStatusChangeCallback(
- base::Bind(&self::OnVersionStatusChanged,
- weak_factory_.GetWeakPtr(),
- registration,
- active_version));
+ registration->active_version()->RegisterStatusChangeCallback(base::Bind(
+ &self::OnVersionStatusChanged, weak_factory_.GetWeakPtr(),
+ base::RetainedRef(registration), base::RetainedRef(active_version)));
TRACE_EVENT_ASYNC_END2(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
@@ -389,11 +389,15 @@ void ServiceWorkerControlleeRequestHandler::OnStartCompleted(
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks service_worker_start_time,
- base::TimeTicks service_worker_ready_time) {
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) {
was_fetched_via_service_worker_ = was_fetched_via_service_worker;
was_fallback_required_ = was_fallback_required;
original_url_via_service_worker_ = original_url_via_service_worker;
response_type_via_service_worker_ = response_type_via_service_worker;
+ response_is_in_cache_storage_ = response_is_in_cache_storage;
+ response_cache_storage_cache_name_ = response_cache_storage_cache_name;
// Update times, if not already set by a previous Job.
if (service_worker_start_time_.is_null()) {
@@ -433,11 +437,6 @@ void ServiceWorkerControlleeRequestHandler::MainResourceLoadFailed() {
provider_host_->NotifyControllerLost();
}
-GURL ServiceWorkerControlleeRequestHandler::GetRequestingOrigin() {
- DCHECK(provider_host_);
- return provider_host_->document_url().GetOrigin();
-}
-
void ServiceWorkerControlleeRequestHandler::ClearJob() {
job_.reset();
was_fetched_via_service_worker_ = false;
@@ -445,6 +444,8 @@ void ServiceWorkerControlleeRequestHandler::ClearJob() {
original_url_via_service_worker_ = GURL();
response_type_via_service_worker_ =
blink::WebServiceWorkerResponseTypeDefault;
+ response_is_in_cache_storage_ = false;
+ response_cache_storage_cache_name_ = std::string();
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
index 1526385a460..736f1b5ea5c 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -100,14 +100,15 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks worker_start_time,
- base::TimeTicks service_worker_ready_time) override;
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) override;
ServiceWorkerVersion* GetServiceWorkerVersion(
ServiceWorkerMetrics::URLRequestJobResult* result) override;
bool RequestStillValid(
ServiceWorkerMetrics::URLRequestJobResult* result) override;
void MainResourceLoadFailed() override;
- GURL GetRequestingOrigin() override;
// Sets |job_| to nullptr, and clears all extra response info associated with
// that job, except for timing information.
@@ -137,6 +138,8 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
blink::WebServiceWorkerResponseType response_type_via_service_worker_;
base::TimeTicks service_worker_start_time_;
base::TimeTicks service_worker_ready_time_;
+ bool response_is_in_cache_storage_ = false;
+ std::string response_cache_storage_cache_name_;
base::WeakPtrFactory<ServiceWorkerControlleeRequestHandler> weak_factory_;
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index bf79f74dea1..dd522e0e7d0 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -38,13 +38,32 @@ int kMockProviderId = 1;
}
+class FailureHelper : public EmbeddedWorkerTestHelper {
+ public:
+ FailureHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+ ~FailureHelper() override {}
+
+ protected:
+ void OnStartWorker(int embedded_worker_id,
+ int64_t service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ bool pause_after_download) override {
+ SimulateWorkerStopped(embedded_worker_id);
+ }
+};
+
class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
public:
ServiceWorkerControlleeRequestHandlerTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
+ SetUpWithHelper(new EmbeddedWorkerTestHelper(base::FilePath()));
+ }
+
+ void SetUpWithHelper(EmbeddedWorkerTestHelper* helper) {
+ helper_.reset(helper);
// A new unstored registration/version.
scope_ = GURL("http://host/scope/");
diff --git a/chromium/content/browser/service_worker/service_worker_database.cc b/chromium/content/browser/service_worker/service_worker_database.cc
index c4c3a8b952b..5254e87cd39 100644
--- a/chromium/content/browser/service_worker/service_worker_database.cc
+++ b/chromium/content/browser/service_worker/service_worker_database.cc
@@ -25,6 +25,7 @@
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/env.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/origin.h"
// LevelDB database schema
// =======================
@@ -283,6 +284,9 @@ ServiceWorkerDatabase::RegistrationData::RegistrationData()
resources_total_size_bytes(0) {
}
+ServiceWorkerDatabase::RegistrationData::RegistrationData(
+ const RegistrationData& other) = default;
+
ServiceWorkerDatabase::RegistrationData::~RegistrationData() {
}
@@ -1193,6 +1197,15 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ParseRegistrationData(
}
out->foreign_fetch_scopes.push_back(sub_scope_url);
}
+ for (int i = 0; i < data.foreign_fetch_origin_size(); ++i) {
+ url::Origin parsed_origin(GURL(data.foreign_fetch_origin(i)));
+ if (parsed_origin.unique()) {
+ DLOG(ERROR) << "Foreign fetch origin '" << data.foreign_fetch_origin(i)
+ << "' is not valid.";
+ return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
+ }
+ out->foreign_fetch_origins.push_back(parsed_origin);
+ }
return ServiceWorkerDatabase::STATUS_OK;
}
@@ -1224,6 +1237,8 @@ void ServiceWorkerDatabase::WriteRegistrationDataInBatch(
<< "'.";
data.add_foreign_fetch_scope(url.spec());
}
+ for (const url::Origin& origin : registration.foreign_fetch_origins)
+ data.add_foreign_fetch_origin(origin.Serialize());
std::string value;
bool success = data.SerializeToString(&value);
diff --git a/chromium/content/browser/service_worker/service_worker_database.h b/chromium/content/browser/service_worker/service_worker_database.h
index 191ef4d7d56..a32e60afbad 100644
--- a/chromium/content/browser/service_worker/service_worker_database.h
+++ b/chromium/content/browser/service_worker/service_worker_database.h
@@ -21,6 +21,7 @@
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace leveldb {
class DB;
@@ -68,11 +69,13 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
bool has_fetch_handler;
base::Time last_update_check;
std::vector<GURL> foreign_fetch_scopes;
+ std::vector<url::Origin> foreign_fetch_origins;
// Not populated until ServiceWorkerStorage::StoreRegistration is called.
int64_t resources_total_size_bytes;
RegistrationData();
+ RegistrationData(const RegistrationData& other);
~RegistrationData();
};
diff --git a/chromium/content/browser/service_worker/service_worker_database.proto b/chromium/content/browser/service_worker/service_worker_database.proto
index 5cce5a78bdc..e85f2a7c830 100644
--- a/chromium/content/browser/service_worker/service_worker_database.proto
+++ b/chromium/content/browser/service_worker/service_worker_database.proto
@@ -27,6 +27,7 @@ message ServiceWorkerRegistrationData {
optional uint64 resources_total_size_bytes = 8;
repeated string foreign_fetch_scope = 9;
+ repeated string foreign_fetch_origin = 10;
}
message ServiceWorkerResourceRecord {
diff --git a/chromium/content/browser/service_worker/service_worker_database_task_manager.h b/chromium/content/browser/service_worker/service_worker_database_task_manager.h
index dbe9aa25190..f13472a5258 100644
--- a/chromium/content/browser/service_worker/service_worker_database_task_manager.h
+++ b/chromium/content/browser/service_worker/service_worker_database_task_manager.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
namespace base {
diff --git a/chromium/content/browser/service_worker/service_worker_database_unittest.cc b/chromium/content/browser/service_worker/service_worker_database_unittest.cc
index 2b99bb4206f..9cdbae66638 100644
--- a/chromium/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_database_unittest.cc
@@ -18,6 +18,7 @@
#include "content/common/service_worker/service_worker_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+#include "url/origin.h"
namespace content {
@@ -70,6 +71,7 @@ void VerifyRegistrationData(const RegistrationData& expected,
EXPECT_EQ(expected.resources_total_size_bytes,
actual.resources_total_size_bytes);
EXPECT_EQ(expected.foreign_fetch_scopes, actual.foreign_fetch_scopes);
+ EXPECT_EQ(expected.foreign_fetch_origins, actual.foreign_fetch_origins);
}
void VerifyResourceRecords(const std::vector<Resource>& expected,
@@ -758,6 +760,8 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
data.version_id = 200;
data.resources_total_size_bytes = 10 + 11;
data.foreign_fetch_scopes.push_back(URL(origin, "/foo"));
+ data.foreign_fetch_origins.push_back(
+ url::Origin(GURL("https://chromium.org")));
std::vector<Resource> resources1;
resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 10));
@@ -787,6 +791,8 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
updated_data.version_id = data.version_id + 1;
updated_data.resources_total_size_bytes = 12 + 13;
updated_data.foreign_fetch_scopes.clear();
+ updated_data.foreign_fetch_origins.push_back(
+ url::Origin(GURL("https://example.com")));
std::vector<Resource> resources2;
resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 12));
resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 13));
diff --git a/chromium/content/browser/service_worker/service_worker_disk_cache.cc b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
index ef8f168f852..f398e61bd2e 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
@@ -11,17 +11,17 @@ ServiceWorkerDiskCache::ServiceWorkerDiskCache()
ServiceWorkerResponseReader::ServiceWorkerResponseReader(
int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseReader(resource_id, 0, disk_cache) {}
ServiceWorkerResponseWriter::ServiceWorkerResponseWriter(
int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseWriter(resource_id, 0, disk_cache) {}
ServiceWorkerResponseMetadataWriter::ServiceWorkerResponseMetadataWriter(
int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache)
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
: AppCacheResponseMetadataWriter(resource_id, 0, disk_cache) {}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_disk_cache.h b/chromium/content/browser/service_worker/service_worker_disk_cache.h
index 90f29bcb3f3..b5ce04cddc5 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.h
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.h
@@ -29,8 +29,10 @@ class CONTENT_EXPORT ServiceWorkerResponseReader
protected:
// Should only be constructed by the storage class.
friend class ServiceWorkerStorage;
- ServiceWorkerResponseReader(int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache);
+
+ ServiceWorkerResponseReader(
+ int64_t resource_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
};
class CONTENT_EXPORT ServiceWorkerResponseWriter
@@ -38,8 +40,10 @@ class CONTENT_EXPORT ServiceWorkerResponseWriter
protected:
// Should only be constructed by the storage class.
friend class ServiceWorkerStorage;
- ServiceWorkerResponseWriter(int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache);
+
+ ServiceWorkerResponseWriter(
+ int64_t resource_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
};
class CONTENT_EXPORT ServiceWorkerResponseMetadataWriter
@@ -47,8 +51,10 @@ class CONTENT_EXPORT ServiceWorkerResponseMetadataWriter
protected:
// Should only be constructed by the storage class.
friend class ServiceWorkerStorage;
- ServiceWorkerResponseMetadataWriter(int64_t resource_id,
- ServiceWorkerDiskCache* disk_cache);
+
+ ServiceWorkerResponseMetadataWriter(
+ int64_t resource_id,
+ const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
};
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc b/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
index f8d80e08730..d15732d41aa 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -10,11 +10,13 @@
#include "base/macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/bad_message.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/service_worker_client_utils.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_handle.h"
@@ -30,7 +32,6 @@
#include "content/public/common/content_client.h"
#include "content/public/common/origin_util.h"
#include "ipc/ipc_message_macros.h"
-#include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
#include "url/gurl.h"
@@ -52,21 +53,9 @@ const uint32_t kFilteredMessageClasses[] = {
ServiceWorkerMsgStart, EmbeddedWorkerMsgStart,
};
-bool AllOriginsMatch(const GURL& url_a, const GURL& url_b, const GURL& url_c) {
- return url_a.GetOrigin() == url_b.GetOrigin() &&
- url_a.GetOrigin() == url_c.GetOrigin();
-}
-
-bool CanRegisterServiceWorker(const GURL& document_url,
- const GURL& pattern,
- const GURL& script_url) {
- DCHECK(document_url.is_valid());
- DCHECK(pattern.is_valid());
- DCHECK(script_url.is_valid());
- return AllOriginsMatch(document_url, pattern, script_url) &&
- OriginCanAccessServiceWorkers(document_url) &&
- OriginCanAccessServiceWorkers(pattern) &&
- OriginCanAccessServiceWorkers(script_url);
+void RunSoon(const base::Closure& callback) {
+ if (!callback.is_null())
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
}
bool CanUnregisterServiceWorker(const GURL& document_url,
@@ -120,10 +109,9 @@ ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
void ServiceWorkerDispatcherHost::Init(
ServiceWorkerContextWrapper* context_wrapper) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&ServiceWorkerDispatcherHost::Init,
- this, make_scoped_refptr(context_wrapper)));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&ServiceWorkerDispatcherHost::Init, this,
+ base::RetainedRef(context_wrapper)));
return;
}
@@ -183,6 +171,8 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnProviderDestroyed)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId,
OnSetHostedVersionId)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DeprecatedPostMessageToWorker,
+ OnDeprecatedPostMessageToWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
OnPostMessageToWorker)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection,
@@ -261,7 +251,7 @@ ServiceWorkerHandle* ServiceWorkerDispatcherHost::FindServiceWorkerHandle(
return handle;
}
}
- return NULL;
+ return nullptr;
}
ServiceWorkerRegistrationHandle*
@@ -329,8 +319,8 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
return;
}
- if (!CanRegisterServiceWorker(
- provider_host->document_url(), pattern, script_url)) {
+ if (!ServiceWorkerUtils::CanRegisterServiceWorker(
+ provider_host->document_url(), pattern, script_url)) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_REGISTER_CANNOT);
return;
}
@@ -352,11 +342,9 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
return;
}
- TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
- "ServiceWorkerDispatcherHost::RegisterServiceWorker",
- request_id,
- "Pattern", pattern.spec(),
- "Script URL", script_url.spec());
+ TRACE_EVENT_ASYNC_BEGIN2(
+ "ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+ request_id, "Scope", pattern.spec(), "Script URL", script_url.spec());
GetContext()->RegisterServiceWorker(
pattern,
script_url,
@@ -442,6 +430,9 @@ void ServiceWorkerDispatcherHost::OnUpdateServiceWorker(
return;
}
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerDispatcherHost::UpdateServiceWorker",
+ request_id, "Scope", registration->pattern().spec());
GetContext()->UpdateServiceWorker(
registration, false /* force_bypass_cache */,
false /* skip_script_comparison */, provider_host,
@@ -511,7 +502,7 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
TRACE_EVENT_ASYNC_BEGIN1(
"ServiceWorker", "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
- request_id, "Pattern", registration->pattern().spec());
+ request_id, "Scope", registration->pattern().spec());
GetContext()->UnregisterServiceWorker(
registration->pattern(),
base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete, this,
@@ -523,11 +514,10 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
int request_id,
int provider_id,
const GURL& document_url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnGetRegistration");
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
@@ -581,17 +571,9 @@ void ServiceWorkerDispatcherHost::OnGetRegistration(
return;
}
- if (GetContext()->storage()->IsDisabled()) {
- SendGetRegistrationError(thread_id, request_id, SERVICE_WORKER_ERROR_ABORT);
- return;
- }
-
- TRACE_EVENT_ASYNC_BEGIN1(
- "ServiceWorker",
- "ServiceWorkerDispatcherHost::GetRegistration",
- request_id,
- "Document URL", document_url.spec());
-
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerDispatcherHost::GetRegistration",
+ request_id, "Document URL", document_url.spec());
GetContext()->storage()->FindRegistrationForDocument(
document_url,
base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete,
@@ -605,6 +587,8 @@ void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id,
int request_id,
int provider_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnGetRegistrations");
if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
@@ -654,16 +638,9 @@ void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id,
return;
}
- if (GetContext()->storage()->IsDisabled()) {
- SendGetRegistrationsError(thread_id, request_id,
- SERVICE_WORKER_ERROR_ABORT);
- return;
- }
-
TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
"ServiceWorkerDispatcherHost::GetRegistrations",
request_id);
-
GetContext()->storage()->GetRegistrationsForOrigin(
provider_host->document_url().GetOrigin(),
base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete, this,
@@ -689,10 +666,8 @@ void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
return;
TRACE_EVENT_ASYNC_BEGIN0(
- "ServiceWorker",
- "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+ "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
request_id);
-
if (!provider_host->GetRegistrationForReady(base::Bind(
&ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete,
this, thread_id, request_id, provider_host->AsWeakPtr()))) {
@@ -703,7 +678,9 @@ void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
int handle_id,
+ int provider_id,
const base::string16& message,
+ const url::Origin& source_origin,
const std::vector<TransferredMessagePort>& sent_message_ports) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerDispatcherHost::OnPostMessageToWorker");
@@ -716,6 +693,71 @@ void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
return;
}
+ ServiceWorkerProviderHost* sender_provider_host =
+ GetContext()->GetProviderHost(render_process_id_, provider_id);
+ if (!sender_provider_host) {
+ bad_message::ReceivedBadMessage(this, bad_message::SWDH_POST_MESSAGE);
+ return;
+ }
+
+ DispatchExtendableMessageEvent(
+ make_scoped_refptr(handle->version()), message, source_origin,
+ sent_message_ports, sender_provider_host,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+}
+
+void ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ ServiceWorkerProviderHost* sender_provider_host,
+ const StatusCallback& callback) {
+ for (const TransferredMessagePort& port : sent_message_ports)
+ MessagePortService::GetInstance()->HoldMessages(port.id);
+
+ switch (sender_provider_host->provider_type()) {
+ case SERVICE_WORKER_PROVIDER_FOR_WINDOW:
+ case SERVICE_WORKER_PROVIDER_FOR_WORKER:
+ case SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER:
+ service_worker_client_utils::GetClient(
+ sender_provider_host,
+ base::Bind(&ServiceWorkerDispatcherHost::
+ DispatchExtendableMessageEventInternal<
+ ServiceWorkerClientInfo>,
+ this, worker, message, source_origin, sent_message_ports,
+ callback));
+ break;
+ case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER:
+ RunSoon(base::Bind(
+ &ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal<
+ ServiceWorkerObjectInfo>,
+ this, worker, message, source_origin, sent_message_ports, callback,
+ sender_provider_host->GetOrCreateServiceWorkerHandle(
+ sender_provider_host->running_hosted_version())));
+ break;
+ case SERVICE_WORKER_PROVIDER_FOR_SANDBOXED_FRAME:
+ case SERVICE_WORKER_PROVIDER_UNKNOWN:
+ NOTREACHED() << sender_provider_host->provider_type();
+ break;
+ }
+}
+
+void ServiceWorkerDispatcherHost::OnDeprecatedPostMessageToWorker(
+ int handle_id,
+ const base::string16& message,
+ const std::vector<TransferredMessagePort>& sent_message_ports) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnDeprecatedPostMessageToWorker");
+ if (!GetContext())
+ return;
+
+ ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
+ if (!handle) {
+ bad_message::ReceivedBadMessage(this, bad_message::SWDH_POST_MESSAGE);
+ return;
+ }
+
handle->version()->DispatchMessageEvent(
message, sent_message_ports,
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
@@ -748,11 +790,11 @@ void ServiceWorkerDispatcherHost::OnProviderCreated(
GetContext()->GetNavigationHandleCore(provider_id);
if (navigation_handle_core != nullptr)
provider_host = navigation_handle_core->RetrievePreCreatedHost();
- if (provider_host == nullptr) {
- bad_message::ReceivedBadMessage(
- this, bad_message::SWDH_PROVIDER_CREATED_NO_HOST);
+
+ // If no host is found, the navigation has been cancelled in the meantime.
+ // Just return as the navigation will be stopped in the renderer as well.
+ if (provider_host == nullptr)
return;
- }
DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, provider_type);
provider_host->CompleteNavigationInitialized(render_process_id_, route_id,
this);
@@ -776,8 +818,15 @@ void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
if (!GetContext())
return;
if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
- bad_message::ReceivedBadMessage(
- this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST);
+ // PlzNavigate: in some cancellation of navigation cases, it is possible
+ // for the pre-created hoist to have been destroyed before being claimed by
+ // the renderer. The provider is then destroyed in the renderer, and no
+ // matching host will be found.
+ if (!IsBrowserSideNavigationEnabled() ||
+ !ServiceWorkerUtils::IsBrowserAssignedProviderId(provider_id)) {
+ bad_message::ReceivedBadMessage(
+ this, bad_message::SWDH_PROVIDER_DESTROYED_NO_HOST);
+ }
return;
}
GetContext()->RemoveProviderHost(render_process_id_, provider_id);
@@ -799,12 +848,16 @@ void ServiceWorkerDispatcherHost::OnSetHostedVersionId(int provider_id,
if (!provider_host->IsContextAlive())
return;
+ // We might not be STARTING if the stop sequence was entered (STOPPING) or
+ // ended up being detached (STOPPED).
ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
- if (!version || version->running_status() == ServiceWorkerVersion::STOPPING)
+ if (!version || version->running_status() != ServiceWorkerVersion::STARTING)
return;
- if (!provider_host->SetHostedVersionId(version_id))
+ if (!provider_host->SetHostedVersion(version)) {
bad_message::ReceivedBadMessage(this, bad_message::SWDH_SET_HOSTED_VERSION);
+ return;
+ }
// Retrieve the registration associated with |version|. The registration
// must be alive because the version keeps it during starting worker.
@@ -825,6 +878,96 @@ void ServiceWorkerDispatcherHost::OnSetHostedVersionId(int provider_id,
provider_id, info, attrs));
}
+template <typename SourceInfo>
+void ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback,
+ const SourceInfo& source_info) {
+ if (!source_info.IsValid()) {
+ DidFailToDispatchExtendableMessageEvent<SourceInfo>(
+ sent_message_ports, source_info, callback, SERVICE_WORKER_ERROR_FAILED);
+ return;
+ }
+ worker->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::MESSAGE,
+ base::Bind(&ServiceWorkerDispatcherHost::
+ DispatchExtendableMessageEventAfterStartWorker,
+ this, worker, message, source_origin, sent_message_ports,
+ ExtendableMessageEventSource(source_info), callback),
+ base::Bind(
+ &ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent<
+ SourceInfo>,
+ this, sent_message_ports, source_info, callback));
+}
+
+void ServiceWorkerDispatcherHost::
+ DispatchExtendableMessageEventAfterStartWorker(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const ExtendableMessageEventSource& source,
+ const StatusCallback& callback) {
+ int request_id =
+ worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE, callback);
+
+ MessagePortMessageFilter* filter =
+ worker->embedded_worker()->message_port_message_filter();
+ std::vector<int> new_routing_ids;
+ filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
+
+ ServiceWorkerMsg_ExtendableMessageEvent_Params params;
+ params.message = message;
+ params.source_origin = source_origin;
+ params.message_ports = sent_message_ports;
+ params.new_routing_ids = new_routing_ids;
+ params.source = source;
+
+ // Hide the client url if the client has a unique origin.
+ if (source_origin.unique()) {
+ if (params.source.client_info.IsValid())
+ params.source.client_info.url = GURL();
+ else
+ params.source.service_worker_info.url = GURL();
+ }
+
+ worker->DispatchSimpleEvent<
+ ServiceWorkerHostMsg_ExtendableMessageEventFinished>(
+ request_id, ServiceWorkerMsg_ExtendableMessageEvent(request_id, params));
+}
+
+template <typename SourceInfo>
+void ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent(
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const SourceInfo& source_info,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status) {
+ // Transfering the message ports failed, so destroy the ports.
+ for (const TransferredMessagePort& port : sent_message_ports)
+ MessagePortService::GetInstance()->ClosePort(port.id);
+ if (source_info.IsValid())
+ ReleaseSourceInfo(source_info);
+ callback.Run(status);
+}
+
+void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
+ const ServiceWorkerClientInfo& source_info) {
+ // ServiceWorkerClientInfo is just a snapshot of the client. There is no need
+ // to do anything for it.
+}
+
+void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
+ const ServiceWorkerObjectInfo& source_info) {
+ ServiceWorkerHandle* handle = handles_.Lookup(source_info.handle_id);
+ DCHECK(handle);
+ handle->DecrementRefCount();
+ if (handle->HasNoRefCount())
+ handles_.Remove(source_info.handle_id);
+}
+
ServiceWorkerRegistrationHandle*
ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
int64_t registration_id) {
@@ -863,6 +1006,9 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker", "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+ request_id, "Status", status, "Registration ID", registration_id);
if (!GetContext())
return;
@@ -872,7 +1018,13 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK) {
- SendRegistrationError(thread_id, request_id, status, status_message);
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(status, status_message,
+ &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
return;
}
@@ -887,11 +1039,6 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
thread_id, request_id, info, attrs));
- TRACE_EVENT_ASYNC_END1("ServiceWorker",
- "ServiceWorkerDispatcherHost::RegisterServiceWorker",
- request_id,
- "Registration ID",
- registration_id);
}
void ServiceWorkerDispatcherHost::UpdateComplete(
@@ -901,6 +1048,9 @@ void ServiceWorkerDispatcherHost::UpdateComplete(
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker", "ServiceWorkerDispatcherHost::UpdateServiceWorker",
+ request_id, "Status", status, "Registration ID", registration_id);
if (!GetContext())
return;
@@ -910,7 +1060,13 @@ void ServiceWorkerDispatcherHost::UpdateComplete(
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK) {
- SendUpdateError(thread_id, request_id, status, status_message);
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(status, status_message,
+ &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) + error_message));
return;
}
@@ -924,9 +1080,6 @@ void ServiceWorkerDispatcherHost::UpdateComplete(
registration, &info, &attrs);
Send(new ServiceWorkerMsg_ServiceWorkerUpdated(thread_id, request_id));
- TRACE_EVENT_ASYNC_END1("ServiceWorker",
- "ServiceWorkerDispatcherHost::UpdateServiceWorker",
- request_id, "Registration ID", registration_id);
}
void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
@@ -1126,19 +1279,24 @@ void ServiceWorkerDispatcherHost::UnregistrationComplete(
int thread_id,
int request_id,
ServiceWorkerStatusCode status) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
+ request_id, "Status", status);
if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
- SendUnregistrationError(thread_id, request_id, status);
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+ &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) +
+ error_message));
return;
}
const bool is_success = (status == SERVICE_WORKER_OK);
Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id,
request_id,
is_success));
- TRACE_EVENT_ASYNC_END1(
- "ServiceWorker",
- "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
- request_id,
- "Status", status);
}
void ServiceWorkerDispatcherHost::GetRegistrationComplete(
@@ -1147,13 +1305,10 @@ void ServiceWorkerDispatcherHost::GetRegistrationComplete(
int request_id,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
- TRACE_EVENT_ASYNC_END1("ServiceWorker",
- "ServiceWorkerDispatcherHost::GetRegistration",
- request_id,
- "Registration ID",
- registration.get() ? registration->id()
- : kInvalidServiceWorkerRegistrationId);
-
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistration",
+ request_id, "Status", status, "Registration ID",
+ registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
if (!GetContext())
return;
@@ -1163,7 +1318,15 @@ void ServiceWorkerDispatcherHost::GetRegistrationComplete(
return; // The provider has already been destroyed.
if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
- SendGetRegistrationError(thread_id, request_id, status);
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+ &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ error_message));
+
return;
}
@@ -1185,11 +1348,12 @@ void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
int thread_id,
int provider_id,
int request_id,
+ ServiceWorkerStatusCode status,
const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
registrations) {
- TRACE_EVENT_ASYNC_END0("ServiceWorker",
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
"ServiceWorkerDispatcherHost::GetRegistrations",
- request_id);
+ request_id, "Status", status);
if (!GetContext())
return;
@@ -1198,6 +1362,18 @@ void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
if (!provider_host)
return; // The provider has already been destroyed.
+ if (status != SERVICE_WORKER_OK) {
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(status, std::string(),
+ &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+ thread_id, request_id, error_type,
+ base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+ error_message));
+ return;
+ }
+
std::vector<ServiceWorkerRegistrationObjectInfo> object_infos;
std::vector<ServiceWorkerVersionAttributes> version_attrs;
@@ -1224,13 +1400,10 @@ void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration) {
DCHECK(registration);
- TRACE_EVENT_ASYNC_END1("ServiceWorker",
- "ServiceWorkerDispatcherHost::GetRegistrationForReady",
- request_id,
- "Registration ID",
- registration ? registration->id()
- : kInvalidServiceWorkerRegistrationId);
-
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker", "ServiceWorkerDispatcherHost::GetRegistrationForReady",
+ request_id, "Registration ID",
+ registration ? registration->id() : kInvalidServiceWorkerRegistrationId);
if (!GetContext())
return;
@@ -1242,75 +1415,6 @@ void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
thread_id, request_id, info, attrs));
}
-void ServiceWorkerDispatcherHost::SendRegistrationError(
- int thread_id,
- int request_id,
- ServiceWorkerStatusCode status,
- const std::string& status_message) {
- base::string16 error_message;
- blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(status, status_message,
- &error_type, &error_message);
- Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
- thread_id, request_id, error_type,
- base::ASCIIToUTF16(kServiceWorkerRegisterErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendUpdateError(
- int thread_id,
- int request_id,
- ServiceWorkerStatusCode status,
- const std::string& status_message) {
- base::string16 error_message;
- blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(status, status_message,
- &error_type, &error_message);
- Send(new ServiceWorkerMsg_ServiceWorkerUpdateError(
- thread_id, request_id, error_type,
- base::ASCIIToUTF16(kServiceWorkerUpdateErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendUnregistrationError(
- int thread_id,
- int request_id,
- ServiceWorkerStatusCode status) {
- base::string16 error_message;
- blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
- &error_message);
- Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
- thread_id, request_id, error_type,
- base::ASCIIToUTF16(kServiceWorkerUnregisterErrorPrefix) + error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendGetRegistrationError(
- int thread_id,
- int request_id,
- ServiceWorkerStatusCode status) {
- base::string16 error_message;
- blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
- &error_message);
- Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
- thread_id, request_id, error_type,
- base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
- error_message));
-}
-
-void ServiceWorkerDispatcherHost::SendGetRegistrationsError(
- int thread_id,
- int request_id,
- ServiceWorkerStatusCode status) {
- base::string16 error_message;
- blink::WebServiceWorkerError::ErrorType error_type;
- GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
- &error_message);
- Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
- thread_id, request_id, error_type,
- base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
- error_message));
-}
-
ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
if (!context_wrapper_.get())
return nullptr;
diff --git a/chromium/content/browser/service_worker/service_worker_dispatcher_host.h b/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
index 89ff78997c2..b0287ffba11 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -21,6 +21,10 @@
class GURL;
struct EmbeddedWorkerHostMsg_ReportConsoleMessage_Params;
+namespace url {
+class Origin;
+}
+
namespace content {
class MessagePortMessageFilter;
@@ -84,8 +88,11 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
private:
friend class BrowserThread;
friend class base::DeleteHelper<ServiceWorkerDispatcherHost>;
+ friend class ServiceWorkerDispatcherHostTest;
friend class TestingServiceWorkerDispatcherHost;
+ using StatusCallback = base::Callback<void(ServiceWorkerStatusCode status)>;
+
// IPC Message handlers
void OnRegisterServiceWorker(int thread_id,
int request_id,
@@ -136,10 +143,51 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
void OnDecrementRegistrationRefCount(int registration_handle_id);
void OnPostMessageToWorker(
int handle_id,
+ int provider_id,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports);
+
+ // TODO(nhiroki): Remove this after ExtendableMessageEvent is enabled by
+ // default (crbug.com/543198).
+ void OnDeprecatedPostMessageToWorker(
+ int handle_id,
const base::string16& message,
const std::vector<TransferredMessagePort>& sent_message_ports);
+
void OnTerminateWorker(int handle_id);
+ void DispatchExtendableMessageEvent(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ ServiceWorkerProviderHost* sender_provider_host,
+ const StatusCallback& callback);
+ template <typename SourceInfo>
+ void DispatchExtendableMessageEventInternal(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const StatusCallback& callback,
+ const SourceInfo& source_info);
+ void DispatchExtendableMessageEventAfterStartWorker(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const ExtendableMessageEventSource& source,
+ const StatusCallback& callback);
+ template <typename SourceInfo>
+ void DidFailToDispatchExtendableMessageEvent(
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ const SourceInfo& source_info,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status);
+ void ReleaseSourceInfo(const ServiceWorkerClientInfo& source_info);
+ void ReleaseSourceInfo(const ServiceWorkerObjectInfo& source_info);
+
ServiceWorkerRegistrationHandle* FindRegistrationHandle(
int provider_id,
int64_t registration_handle_id);
@@ -157,63 +205,37 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id);
-
void UpdateComplete(int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id);
-
void UnregistrationComplete(int thread_id,
int request_id,
ServiceWorkerStatusCode status);
-
void GetRegistrationComplete(
int thread_id,
int provider_id,
int request_id,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
-
void GetRegistrationsComplete(
int thread_id,
int provider_id,
int request_id,
+ ServiceWorkerStatusCode status,
const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
registrations);
-
void GetRegistrationForReadyComplete(
int thread_id,
int request_id,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
ServiceWorkerRegistration* registration);
- void SendRegistrationError(int thread_id,
- int request_id,
- ServiceWorkerStatusCode status,
- const std::string& status_message);
-
- void SendUpdateError(int thread_id,
- int request_id,
- ServiceWorkerStatusCode status,
- const std::string& status_message);
-
- void SendUnregistrationError(int thread_id,
- int request_id,
- ServiceWorkerStatusCode status);
-
- void SendGetRegistrationError(int thread_id,
- int request_id,
- ServiceWorkerStatusCode status);
-
- void SendGetRegistrationsError(int thread_id,
- int request_id,
- ServiceWorkerStatusCode status);
-
ServiceWorkerContextCore* GetContext();
- int render_process_id_;
+ const int render_process_id_;
MessagePortMessageFilter* const message_port_message_filter_;
ResourceContext* resource_context_;
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
diff --git a/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 84e1b6e0a35..7c9ad083ef9 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -11,11 +11,13 @@
#include "base/files/file_path.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/message_port_service.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/service_worker/service_worker_handle.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/common/content_switches.h"
@@ -35,8 +37,17 @@ static void SaveStatusCallback(bool* called,
*out = status;
}
+void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) {
+ int port_id = -1;
+ MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr,
+ &port_id);
+ TransferredMessagePort dummy_port;
+ dummy_port.id = port_id;
+ ports->push_back(dummy_port);
}
+} // namespace
+
static const int kRenderFrameId = 1;
class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
@@ -65,25 +76,86 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
~TestingServiceWorkerDispatcherHost() override {}
};
+class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
+ public:
+ FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+
+ void OnStartWorker(int embedded_worker_id,
+ int64_t service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ bool pause_after_download) override {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id);
+ }
+};
+
class ServiceWorkerDispatcherHostTest : public testing::Test {
protected:
ServiceWorkerDispatcherHostTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
- dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
- helper_->mock_render_process_id(), context_wrapper(),
- &resource_context_, helper_.get());
+ Initialize(make_scoped_ptr(new EmbeddedWorkerTestHelper(base::FilePath())));
}
- void TearDown() override { helper_.reset(); }
+ void TearDown() override {
+ version_ = nullptr;
+ registration_ = nullptr;
+ helper_.reset();
+ }
ServiceWorkerContextCore* context() { return helper_->context(); }
ServiceWorkerContextWrapper* context_wrapper() {
return helper_->context_wrapper();
}
+ void Initialize(scoped_ptr<EmbeddedWorkerTestHelper> helper) {
+ helper_.reset(helper.release());
+ dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
+ helper_->mock_render_process_id(), context_wrapper(),
+ &resource_context_, helper_.get());
+ }
+
+ void SetUpRegistration(const GURL& scope, const GURL& script_url) {
+ registration_ = new ServiceWorkerRegistration(
+ scope, 1L, helper_->context()->AsWeakPtr());
+ version_ = new ServiceWorkerVersion(registration_.get(), script_url, 1L,
+ helper_->context()->AsWeakPtr());
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records;
+ records.push_back(
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100));
+ version_->script_cache_map()->SetResources(records);
+
+ // Make the registration findable via storage functions.
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ bool called = false;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ helper_->context()->storage()->StoreRegistration(
+ registration_.get(), version_.get(),
+ base::Bind(&SaveStatusCallback, &called, &status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ }
+
+ void SendSetHostedVersionId(int provider_id, int64_t version_id) {
+ dispatcher_host_->OnMessageReceived(
+ ServiceWorkerHostMsg_SetVersionId(provider_id, version_id));
+ }
+
+ void SendProviderCreated(ServiceWorkerProviderType type,
+ const GURL& pattern) {
+ const int64_t kProviderId = 99;
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
+ kProviderId, MSG_ROUTING_NONE, type));
+ helper_->SimulateAddProcessToPattern(pattern,
+ helper_->mock_render_process_id());
+ provider_host_ = context()->GetProviderHost(
+ helper_->mock_render_process_id(), kProviderId);
+ }
+
void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) {
dispatcher_host_->OnMessageReceived(
ServiceWorkerHostMsg_RegisterServiceWorker(
@@ -146,6 +218,18 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
dispatcher_host_->ipc_sink()->ClearMessages();
}
+ void DispatchExtendableMessageEvent(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ const base::string16& message,
+ const url::Origin& source_origin,
+ const std::vector<TransferredMessagePort>& sent_message_ports,
+ ServiceWorkerProviderHost* sender_provider_host,
+ const ServiceWorkerDispatcherHost::StatusCallback& callback) {
+ dispatcher_host_->DispatchExtendableMessageEvent(
+ std::move(worker), message, source_origin, sent_message_ports,
+ sender_provider_host, callback);
+ }
+
ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) {
return new ServiceWorkerProviderHost(
helper_->mock_render_process_id(), kRenderFrameId, provider_id,
@@ -153,11 +237,13 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
dispatcher_host_.get());
}
-
TestBrowserThreadBundle browser_thread_bundle_;
content::MockResourceContext resource_context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ ServiceWorkerProviderHost* provider_host_;
};
class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
@@ -526,60 +612,33 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistrations_EarlyContextDeletion) {
}
TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
+ GURL pattern = GURL("http://www.example.com/");
+ GURL script_url = GURL("http://www.example.com/service_worker.js");
int process_id = helper_->mock_render_process_id();
- // Add a provider and worker.
- const int64_t kProviderId = 99; // Dummy value
- dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
- kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_WINDOW, pattern);
+ SetUpRegistration(pattern, script_url);
+ int64_t provider_id = provider_host_->provider_id();
- GURL pattern = GURL("http://www.example.com/");
- scoped_refptr<ServiceWorkerRegistration> registration(
- new ServiceWorkerRegistration(pattern,
- 1L,
- helper_->context()->AsWeakPtr()));
- scoped_refptr<ServiceWorkerVersion> version(
- new ServiceWorkerVersion(registration.get(),
- GURL("http://www.example.com/service_worker.js"),
- 1L,
- helper_->context()->AsWeakPtr()));
- std::vector<ServiceWorkerDatabase::ResourceRecord> records;
- records.push_back(
- ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100));
- version->script_cache_map()->SetResources(records);
-
- // Make the registration findable via storage functions.
- helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing));
- base::RunLoop().RunUntilIdle();
+ // Start up the worker.
bool called = false;
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
- helper_->context()->storage()->StoreRegistration(
- registration.get(),
- version.get(),
- base::Bind(&SaveStatusCallback, &called, &status));
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(called);
- ASSERT_EQ(SERVICE_WORKER_OK, status);
-
- helper_->SimulateAddProcessToPattern(pattern, process_id);
-
- // Start up the worker.
- status = SERVICE_WORKER_ERROR_ABORT;
- version->StartWorker(base::Bind(&SaveStatusCallback, &called, &status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ base::Bind(&SaveStatusCallback, &called, &status));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called);
EXPECT_EQ(SERVICE_WORKER_OK, status);
- EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId));
- EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
+ EXPECT_TRUE(context()->GetProviderHost(process_id, provider_id));
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
// Simulate the render process crashing.
dispatcher_host_->OnFilterRemoved();
// The dispatcher host should clean up the state from the process.
- EXPECT_FALSE(context()->GetProviderHost(process_id, kProviderId));
- EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status());
+ EXPECT_FALSE(context()->GetProviderHost(process_id, provider_id));
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
// We should be able to hook up a new dispatcher host although the old object
// is not yet destroyed. This is what the browser does when reusing a crashed
@@ -592,8 +651,114 @@ TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
// the old dispatcher cleaned up the old provider host, the new one won't
// complain.
new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated(
- kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
+ provider_id, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW));
EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_);
}
+TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent) {
+ GURL pattern = GURL("http://www.example.com/");
+ GURL script_url = GURL("http://www.example.com/service_worker.js");
+
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern);
+ SetUpRegistration(pattern, script_url);
+
+ // Set the running hosted version so that we can retrieve a valid service
+ // worker object information for the source attribute of the message event.
+ provider_host_->running_hosted_version_ = version_;
+
+ // Set aside the initial refcount of the worker handle.
+ provider_host_->GetOrCreateServiceWorkerHandle(version_.get());
+ ServiceWorkerHandle* sender_worker_handle =
+ dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(),
+ version_->version_id());
+ const int ref_count = sender_worker_handle->ref_count();
+
+ // Dispatch ExtendableMessageEvent.
+ std::vector<TransferredMessagePort> ports;
+ SetUpDummyMessagePort(&ports);
+ bool called = false;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ DispatchExtendableMessageEvent(
+ version_, base::string16(), url::Origin(version_->scope().GetOrigin()),
+ ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status));
+ for (TransferredMessagePort port : ports)
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id));
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+
+ // Messages should be held until ports are created at the destination.
+ for (TransferredMessagePort port : ports)
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id));
+
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent_Fail) {
+ GURL pattern = GURL("http://www.example.com/");
+ GURL script_url = GURL("http://www.example.com/service_worker.js");
+
+ Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper));
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern);
+ SetUpRegistration(pattern, script_url);
+
+ // Set the running hosted version so that we can retrieve a valid service
+ // worker object information for the source attribute of the message event.
+ provider_host_->running_hosted_version_ = version_;
+
+ // Set aside the initial refcount of the worker handle.
+ provider_host_->GetOrCreateServiceWorkerHandle(version_.get());
+ ServiceWorkerHandle* sender_worker_handle =
+ dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(),
+ version_->version_id());
+ const int ref_count = sender_worker_handle->ref_count();
+
+ // Try to dispatch ExtendableMessageEvent. This should fail to start the
+ // worker and to dispatch the event.
+ std::vector<TransferredMessagePort> ports;
+ SetUpDummyMessagePort(&ports);
+ bool called = false;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+ DispatchExtendableMessageEvent(
+ version_, base::string16(), url::Origin(version_->scope().GetOrigin()),
+ ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status));
+ for (TransferredMessagePort port : ports)
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id));
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
+
+ // The error callback should clean up the ports and handle.
+ for (TransferredMessagePort port : ports)
+ EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port.id));
+ EXPECT_EQ(ref_count, sender_worker_handle->ref_count());
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, OnSetHostedVersionId) {
+ GURL pattern = GURL("http://www.example.com/");
+ GURL script_url = GURL("http://www.example.com/service_worker.js");
+
+ Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper));
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern);
+ SetUpRegistration(pattern, script_url);
+
+ const int64_t kProviderId = 99; // Dummy value
+ bool called;
+ ServiceWorkerStatusCode status;
+ // StartWorker puts the worker in STARTING state but it will have no
+ // process id yet.
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ base::Bind(&SaveStatusCallback, &called, &status));
+ EXPECT_NE(version_->embedded_worker()->process_id(),
+ provider_host_->process_id());
+ // SendSetHostedVersionId should reject because the provider host process id
+ // is different.
+ SendSetHostedVersionId(kProviderId, version_->version_id());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
+ ServiceWorkerMsg_AssociateRegistration::ID));
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 60c4eb66ef6..dfcce9a5f9a 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -9,18 +9,41 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/service_worker/service_worker_messages.h"
namespace content {
+namespace {
+using EventType = ServiceWorkerMetrics::EventType;
+EventType ResourceTypeToEventType(ResourceType resource_type) {
+ switch (resource_type) {
+ case RESOURCE_TYPE_MAIN_FRAME:
+ return EventType::FETCH_MAIN_FRAME;
+ case RESOURCE_TYPE_SUB_FRAME:
+ return EventType::FETCH_SUB_FRAME;
+ case RESOURCE_TYPE_SHARED_WORKER:
+ return EventType::FETCH_SHARED_WORKER;
+ case RESOURCE_TYPE_SERVICE_WORKER:
+ case RESOURCE_TYPE_LAST_TYPE:
+ NOTREACHED() << resource_type;
+ return EventType::FETCH_SUB_RESOURCE;
+ default:
+ return EventType::FETCH_SUB_RESOURCE;
+ }
+}
+} // namespace
+
ServiceWorkerFetchDispatcher::ServiceWorkerFetchDispatcher(
scoped_ptr<ServiceWorkerFetchRequest> request,
ServiceWorkerVersion* version,
+ ResourceType resource_type,
const base::Closure& prepare_callback,
const FetchCallback& fetch_callback)
: version_(version),
prepare_callback_(prepare_callback),
fetch_callback_(fetch_callback),
request_(std::move(request)),
+ resource_type_(resource_type),
weak_factory_(this) {}
ServiceWorkerFetchDispatcher::~ServiceWorkerFetchDispatcher() {}
@@ -36,7 +59,7 @@ void ServiceWorkerFetchDispatcher::Run() {
weak_factory_.GetWeakPtr()));
return;
}
- DispatchFetchEvent();
+ DidWaitActivation();
}
void ServiceWorkerFetchDispatcher::DidWaitActivation() {
@@ -45,7 +68,12 @@ void ServiceWorkerFetchDispatcher::DidWaitActivation() {
DidFailActivation();
return;
}
- DispatchFetchEvent();
+ version_->RunAfterStartWorker(
+ GetEventType(),
+ base::Bind(&ServiceWorkerFetchDispatcher::DispatchFetchEvent,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&ServiceWorkerFetchDispatcher::DidFail,
+ weak_factory_.GetWeakPtr()));
}
void ServiceWorkerFetchDispatcher::DidFailActivation() {
@@ -59,14 +87,18 @@ void ServiceWorkerFetchDispatcher::DidFailActivation() {
}
void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
- TRACE_EVENT_ASYNC_BEGIN0(
- "ServiceWorker",
- "ServiceWorkerFetchDispatcher::DispatchFetchEvent",
- request_.get());
- version_->DispatchFetchEvent(
- *request_.get(),
- base::Bind(&ServiceWorkerFetchDispatcher::DidPrepare,
- weak_factory_.GetWeakPtr()),
+ DCHECK_EQ(ServiceWorkerVersion::RUNNING, version_->running_status())
+ << "Worker stopped too soon after it was started.";
+
+ DCHECK(!prepare_callback_.is_null());
+ base::Closure prepare_callback = prepare_callback_;
+ prepare_callback.Run();
+
+ int request_id = version_->StartRequest(
+ GetEventType(), base::Bind(&ServiceWorkerFetchDispatcher::DidFail,
+ weak_factory_.GetWeakPtr()));
+ version_->DispatchEvent<ServiceWorkerHostMsg_FetchEventFinished>(
+ request_id, ServiceWorkerMsg_FetchEvent(request_id, *request_.get()),
base::Bind(&ServiceWorkerFetchDispatcher::DidFinish,
weak_factory_.GetWeakPtr()));
}
@@ -77,17 +109,34 @@ void ServiceWorkerFetchDispatcher::DidPrepare() {
prepare_callback.Run();
}
+void ServiceWorkerFetchDispatcher::DidFail(ServiceWorkerStatusCode status) {
+ DCHECK(!fetch_callback_.is_null());
+ FetchCallback fetch_callback = fetch_callback_;
+ scoped_refptr<ServiceWorkerVersion> version = version_;
+ fetch_callback.Run(status, SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
+ ServiceWorkerResponse(), version);
+}
+
void ServiceWorkerFetchDispatcher::DidFinish(
- ServiceWorkerStatusCode status,
+ int request_id,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response) {
- TRACE_EVENT_ASYNC_END0(
- "ServiceWorker",
- "ServiceWorkerFetchDispatcher::DispatchFetchEvent",
- request_.get());
+ const bool handled =
+ (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE);
+ if (!version_->FinishRequest(request_id, handled))
+ NOTREACHED() << "Should only receive one reply per event";
+
DCHECK(!fetch_callback_.is_null());
FetchCallback fetch_callback = fetch_callback_;
- fetch_callback.Run(status, fetch_result, response, version_);
+ scoped_refptr<ServiceWorkerVersion> version = version_;
+ fetch_callback.Run(SERVICE_WORKER_OK, fetch_result, response, version);
+}
+
+ServiceWorkerMetrics::EventType ServiceWorkerFetchDispatcher::GetEventType()
+ const {
+ if (request_->fetch_type == ServiceWorkerFetchType::FOREIGN_FETCH)
+ return ServiceWorkerMetrics::EventType::FOREIGN_FETCH;
+ return ResourceTypeToEventType(resource_type_);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
index 518be84906b..82a4a2d551d 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -8,24 +8,28 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
+#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/common/resource_type.h"
namespace content {
class ServiceWorkerVersion;
// A helper class to dispatch fetch event to a service worker.
-class ServiceWorkerFetchDispatcher {
+class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
public:
typedef base::Callback<void(ServiceWorkerStatusCode,
ServiceWorkerFetchEventResult,
const ServiceWorkerResponse&,
- scoped_refptr<ServiceWorkerVersion>)>
+ const scoped_refptr<ServiceWorkerVersion>&)>
FetchCallback;
ServiceWorkerFetchDispatcher(scoped_ptr<ServiceWorkerFetchRequest> request,
ServiceWorkerVersion* version,
+ ResourceType resource_type,
const base::Closure& prepare_callback,
const FetchCallback& fetch_callback);
~ServiceWorkerFetchDispatcher();
@@ -39,14 +43,18 @@ class ServiceWorkerFetchDispatcher {
void DidFailActivation();
void DispatchFetchEvent();
void DidPrepare();
- void DidFinish(ServiceWorkerStatusCode status,
+ void DidFail(ServiceWorkerStatusCode status);
+ void DidFinish(int request_id,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response);
+ ServiceWorkerMetrics::EventType GetEventType() const;
+
scoped_refptr<ServiceWorkerVersion> version_;
base::Closure prepare_callback_;
FetchCallback fetch_callback_;
scoped_ptr<ServiceWorkerFetchRequest> request_;
+ ResourceType resource_type_;
base::WeakPtrFactory<ServiceWorkerFetchDispatcher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerFetchDispatcher);
diff --git a/chromium/content/browser/service_worker/service_worker_handle.h b/chromium/content/browser/service_worker/service_worker_handle.h
index a9c0e443a51..4d8651af83d 100644
--- a/chromium/content/browser/service_worker/service_worker_handle.h
+++ b/chromium/content/browser/service_worker/service_worker_handle.h
@@ -54,6 +54,7 @@ class CONTENT_EXPORT ServiceWorkerHandle
int handle_id() const { return handle_id_; }
ServiceWorkerVersion* version() { return version_.get(); }
+ int ref_count() const { return ref_count_; }
bool HasNoRefCount() const { return ref_count_ <= 0; }
void IncrementRefCount();
void DecrementRefCount();
diff --git a/chromium/content/browser/service_worker/service_worker_handle_unittest.cc b/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
index 25514ffbd58..ae15a98e549 100644
--- a/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <vector>
+
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
@@ -142,20 +144,18 @@ TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
// Start the worker, and then...
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
- // ...dispatch install event.
- status = SERVICE_WORKER_ERROR_FAILED;
+ // ...update state to installing...
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
- version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ // ...and update state to installed.
version_->SetStatus(ServiceWorkerVersion::INSTALLED);
- ASSERT_EQ(4UL, ipc_sink()->message_count());
+ ASSERT_EQ(3UL, ipc_sink()->message_count());
ASSERT_EQ(0L, dispatcher_host_->bad_message_received_count_);
// We should be sending 1. StartWorker,
@@ -165,13 +165,10 @@ TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
VerifyStateChangedMessage(handle->handle_id(),
blink::WebServiceWorkerStateInstalling,
ipc_sink()->GetMessageAt(1));
- // 3. SendMessageToWorker (to send InstallEvent), and
- EXPECT_EQ(EmbeddedWorkerContextMsg_MessageToWorker::ID,
- ipc_sink()->GetMessageAt(2)->type());
- // 4. StateChanged (state == Installed).
+ // 3. StateChanged (state == Installed).
VerifyStateChangedMessage(handle->handle_id(),
blink::WebServiceWorkerStateInstalled,
- ipc_sink()->GetMessageAt(3));
+ ipc_sink()->GetMessageAt(2));
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_info.cc b/chromium/content/browser/service_worker/service_worker_info.cc
index 836e979763d..0f4a4c5d9e7 100644
--- a/chromium/content/browser/service_worker/service_worker_info.cc
+++ b/chromium/content/browser/service_worker/service_worker_info.cc
@@ -51,12 +51,14 @@ ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
thread_id(thread_id),
devtools_agent_route_id(devtools_agent_route_id) {}
+ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
+ const ServiceWorkerVersionInfo& other) = default;
+
ServiceWorkerVersionInfo::~ServiceWorkerVersionInfo() {}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo()
: registration_id(kInvalidServiceWorkerRegistrationId),
delete_flag(IS_NOT_DELETED),
- force_update_on_page_load(IS_NOT_FORCED),
stored_version_size_bytes(0) {}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
@@ -66,14 +68,12 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
: pattern(pattern),
registration_id(registration_id),
delete_flag(delete_flag),
- force_update_on_page_load(IS_NOT_FORCED),
stored_version_size_bytes(0) {}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
const GURL& pattern,
int64_t registration_id,
DeleteFlag delete_flag,
- ForceUpdateOnPageLoad force_update_on_page_load,
const ServiceWorkerVersionInfo& active_version,
const ServiceWorkerVersionInfo& waiting_version,
const ServiceWorkerVersionInfo& installing_version,
@@ -81,12 +81,14 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
: pattern(pattern),
registration_id(registration_id),
delete_flag(delete_flag),
- force_update_on_page_load(force_update_on_page_load),
active_version(active_version),
waiting_version(waiting_version),
installing_version(installing_version),
stored_version_size_bytes(stored_version_size_bytes) {}
+ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
+ const ServiceWorkerRegistrationInfo& other) = default;
+
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo() {}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_info.h b/chromium/content/browser/service_worker/service_worker_info.h
index b1c0a73f082..8de17feaa24 100644
--- a/chromium/content/browser/service_worker/service_worker_info.h
+++ b/chromium/content/browser/service_worker/service_worker_info.h
@@ -37,6 +37,7 @@ struct CONTENT_EXPORT ServiceWorkerVersionInfo {
int process_id,
int thread_id,
int devtools_agent_route_id);
+ ServiceWorkerVersionInfo(const ServiceWorkerVersionInfo& other);
~ServiceWorkerVersionInfo();
ServiceWorkerVersion::RunningStatus running_status;
@@ -55,7 +56,6 @@ struct CONTENT_EXPORT ServiceWorkerVersionInfo {
struct CONTENT_EXPORT ServiceWorkerRegistrationInfo {
public:
enum DeleteFlag { IS_NOT_DELETED, IS_DELETED };
- enum ForceUpdateOnPageLoad { IS_NOT_FORCED, IS_FORCED };
ServiceWorkerRegistrationInfo();
ServiceWorkerRegistrationInfo(const GURL& pattern,
int64_t registration_id,
@@ -64,17 +64,16 @@ struct CONTENT_EXPORT ServiceWorkerRegistrationInfo {
const GURL& pattern,
int64_t registration_id,
DeleteFlag delete_flag,
- ForceUpdateOnPageLoad force_update_on_page_load,
const ServiceWorkerVersionInfo& active_version,
const ServiceWorkerVersionInfo& waiting_version,
const ServiceWorkerVersionInfo& installing_version,
int64_t active_version_total_size_bytes);
+ ServiceWorkerRegistrationInfo(const ServiceWorkerRegistrationInfo& other);
~ServiceWorkerRegistrationInfo();
GURL pattern;
int64_t registration_id;
DeleteFlag delete_flag;
- ForceUpdateOnPageLoad force_update_on_page_load;
ServiceWorkerVersionInfo active_version;
ServiceWorkerVersionInfo waiting_version;
ServiceWorkerVersionInfo installing_version;
diff --git a/chromium/content/browser/service_worker/service_worker_internals_ui.cc b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
index ae899dca58d..61eaffbba7b 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.cc
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
@@ -22,10 +22,12 @@
#include "content/grit/content_resources.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/child_process_host.h"
#include "content/public/common/url_constants.h"
using base::DictionaryValue;
@@ -89,29 +91,23 @@ void CallServiceWorkerVersionMethodWithVersionID(
(*version.get().*method)(callback);
}
-void DispatchPushEventWithVersionID(
- scoped_refptr<ServiceWorkerContextWrapper> context,
- int64_t version_id,
- const ServiceWorkerInternalsUI::StatusCallback& callback) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(DispatchPushEventWithVersionID,
- context,
- version_id,
- callback));
- return;
- }
-
- scoped_refptr<ServiceWorkerVersion> version =
- context->GetLiveVersion(version_id);
- if (!version.get()) {
- callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
- return;
- }
- std::string data = "Test push message from ServiceWorkerInternals.";
- version->DispatchPushEvent(callback, data);
+base::ProcessId GetRealProcessId(int process_host_id) {
+ if (process_host_id == ChildProcessHost::kInvalidUniqueID)
+ return base::kNullProcessId;
+
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_host_id);
+ if (!rph)
+ return base::kNullProcessId;
+
+ base::ProcessHandle handle = rph->GetHandle();
+ if (handle == base::kNullProcessHandle)
+ return base::kNullProcessId;
+ // TODO(nhiroki): On Windows, |rph->GetHandle()| does not duplicate ownership
+ // of the process handle and the render host still retains it. Therefore, we
+ // cannot create a base::Process object, which provides a proper way to get a
+ // process id, from the handle. For a stopgap, we use this deprecated
+ // function that does not require the ownership (http://crbug.com/417532).
+ return base::GetProcId(handle);
}
void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
@@ -153,7 +149,9 @@ void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
}
info->SetString("script_url", version.script_url.spec());
info->SetString("version_id", base::Int64ToString(version.version_id));
- info->SetInteger("process_id", version.process_id);
+ info->SetInteger("process_id",
+ static_cast<int>(GetRealProcessId(version.process_id)));
+ info->SetInteger("process_host_id", version.process_id);
info->SetInteger("thread_id", version.thread_id);
info->SetInteger("devtools_agent_route_id", version.devtools_agent_route_id);
}
@@ -207,6 +205,7 @@ ListValue* GetVersionListValue(
void DidGetStoredRegistrationsOnIOThread(
scoped_refptr<ServiceWorkerContextWrapper> context,
const GetRegistrationsCallback& callback,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
@@ -358,10 +357,6 @@ ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
base::Unretained(this),
&ServiceWorkerVersion::StopWorker));
web_ui->RegisterMessageCallback(
- "push",
- base::Bind(&ServiceWorkerInternalsUI::DispatchPushEvent,
- base::Unretained(this)));
- web_ui->RegisterMessageCallback(
"inspect",
base::Bind(&ServiceWorkerInternalsUI::InspectWorker,
base::Unretained(this)));
@@ -510,38 +505,15 @@ void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
method, context, version_id, callback);
}
-void ServiceWorkerInternalsUI::DispatchPushEvent(
- const ListValue* args) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- int callback_id;
- int partition_id;
- int64_t version_id = 0;
- std::string version_id_string;
- const DictionaryValue* cmd_args = NULL;
- scoped_refptr<ServiceWorkerContextWrapper> context;
- if (!args->GetInteger(0, &callback_id) ||
- !args->GetDictionary(1, &cmd_args) ||
- !cmd_args->GetInteger("partition_id", &partition_id) ||
- !GetServiceWorkerContext(partition_id, &context) ||
- !cmd_args->GetString("version_id", &version_id_string) ||
- !base::StringToInt64(version_id_string, &version_id)) {
- return;
- }
-
- base::Callback<void(ServiceWorkerStatusCode)> callback =
- base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
- DispatchPushEventWithVersionID(context, version_id, callback);
-}
-
void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
int callback_id;
const DictionaryValue* cmd_args = NULL;
- int process_id = 0;
+ int process_host_id = 0;
int devtools_agent_route_id = 0;
if (!args->GetInteger(0, &callback_id) ||
!args->GetDictionary(1, &cmd_args) ||
- !cmd_args->GetInteger("process_id", &process_id) ||
+ !cmd_args->GetInteger("process_host_id", &process_host_id) ||
!cmd_args->GetInteger("devtools_agent_route_id",
&devtools_agent_route_id)) {
return;
@@ -550,7 +522,8 @@ void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
scoped_refptr<DevToolsAgentHostImpl> agent_host(
ServiceWorkerDevToolsManager::GetInstance()
- ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
+ ->GetDevToolsAgentHostForWorker(process_host_id,
+ devtools_agent_route_id));
if (!agent_host.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
diff --git a/chromium/content/browser/service_worker/service_worker_internals_ui.h b/chromium/content/browser/service_worker/service_worker_internals_ui.h
index bc1c5b93511..b04df03aab9 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.h
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.h
@@ -52,7 +52,6 @@ class ServiceWorkerInternalsUI
void GetAllRegistrations(const base::ListValue* args);
void CallServiceWorkerVersionMethod(ServiceWorkerVersionMethod method,
const base::ListValue* args);
- void DispatchPushEvent(const base::ListValue* args);
void InspectWorker(const base::ListValue* args);
void Unregister(const base::ListValue* args);
void StartWorker(const base::ListValue* args);
diff --git a/chromium/content/browser/service_worker/service_worker_job_coordinator.cc b/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
index b8f71cf5796..9dd023e9e94 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
@@ -23,6 +23,9 @@ bool IsRegisterJob(const ServiceWorkerRegisterJobBase& job) {
ServiceWorkerJobCoordinator::JobQueue::JobQueue() {}
+ServiceWorkerJobCoordinator::JobQueue::JobQueue(const JobQueue& other) =
+ default;
+
ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
DCHECK(jobs_.empty()) << "Destroying JobQueue with " << jobs_.size()
<< " unfinished jobs";
diff --git a/chromium/content/browser/service_worker/service_worker_job_coordinator.h b/chromium/content/browser/service_worker/service_worker_job_coordinator.h
index 728b8206b8f..5b4c1f19eea 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.h
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.h
@@ -56,6 +56,7 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator {
class JobQueue {
public:
JobQueue();
+ JobQueue(const JobQueue& other);
~JobQueue();
// Adds a job to the queue. If an identical job is already at the end of the
diff --git a/chromium/content/browser/service_worker/service_worker_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
index a5572a4f60b..a86b0781706 100644
--- a/chromium/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
@@ -17,6 +17,7 @@
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "ipc/ipc_test_sink.h"
@@ -274,6 +275,8 @@ TEST_F(ServiceWorkerJobTest, Register) {
GURL("http://www.example.com/service_worker.js"));
ASSERT_NE(scoped_refptr<ServiceWorkerRegistration>(NULL), registration);
+ EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
+ ServiceWorkerMsg_InstallEvent::ID));
}
// Make sure registrations are cleaned up when they are unregistered.
@@ -359,7 +362,8 @@ class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
void OnStartWorker(int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
- const GURL& script_url) override {
+ const GURL& script_url,
+ bool pause_after_download) override {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id);
}
@@ -639,7 +643,8 @@ TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
registration.get(), script_url, 1L, helper_->context()->AsWeakPtr());
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(SERVICE_WORKER_OK, status);
@@ -788,6 +793,10 @@ class UpdateJobTestHelper
return context()->job_coordinator();
}
+ void set_force_start_worker_failure(bool force_start_worker_failure) {
+ force_start_worker_failure_ = force_start_worker_failure;
+ }
+
scoped_refptr<ServiceWorkerRegistration> SetupInitialRegistration(
const GURL& test_origin) {
scoped_refptr<ServiceWorkerRegistration> registration;
@@ -811,7 +820,8 @@ class UpdateJobTestHelper
void OnStartWorker(int embedded_worker_id,
int64_t version_id,
const GURL& scope,
- const GURL& script) override {
+ const GURL& script,
+ bool pause_after_download) override {
const std::string kMockScriptBody = "mock_script";
const uint64_t kMockScriptSize = 19284;
ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
@@ -823,29 +833,51 @@ class UpdateJobTestHelper
ASSERT_TRUE(version);
version->AddListener(this);
+ // Simulate network access.
+ base::TimeDelta time_since_last_check =
+ base::Time::Now() - registration->last_update_check();
+ if (!is_update || script.GetOrigin() != kNoChangeOrigin ||
+ time_since_last_check > base::TimeDelta::FromHours(
+ kServiceWorkerScriptMaxCacheAgeInHours)) {
+ version->embedded_worker()->OnNetworkAccessedForScriptLoad();
+ }
+
+ int64_t resource_id = storage()->NewResourceId();
+ version->script_cache_map()->NotifyStartedCaching(script, resource_id);
if (!is_update) {
// Spoof caching the script for the initial version.
- int64_t resource_id = storage()->NewResourceId();
- version->script_cache_map()->NotifyStartedCaching(script, resource_id);
WriteStringResponse(storage(), resource_id, kMockScriptBody);
version->script_cache_map()->NotifyFinishedCaching(
script, kMockScriptSize, net::URLRequestStatus(), std::string());
} else {
if (script.GetOrigin() == kNoChangeOrigin) {
- version->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
- EmbeddedWorkerTestHelper::OnStopWorker(embedded_worker_id);
+ // Simulate fetching the updated script and finding it's identical to
+ // the incumbent.
+ net::URLRequestStatus status =
+ net::URLRequestStatus::FromError(net::ERR_FILE_EXISTS);
+ version->script_cache_map()->NotifyFinishedCaching(
+ script, kMockScriptSize, status, std::string());
+ SimulateWorkerScriptLoaded(embedded_worker_id);
return;
}
// Spoof caching the script for the new version.
- int64_t resource_id = storage()->NewResourceId();
- version->script_cache_map()->NotifyStartedCaching(script, resource_id);
WriteStringResponse(storage(), resource_id, "mock_different_script");
version->script_cache_map()->NotifyFinishedCaching(
script, kMockScriptSize, net::URLRequestStatus(), std::string());
}
- EmbeddedWorkerTestHelper::OnStartWorker(embedded_worker_id, version_id,
- scope, script);
+
+ EmbeddedWorkerTestHelper::OnStartWorker(
+ embedded_worker_id, version_id, scope, script, pause_after_download);
+ }
+
+ void OnResumeAfterDownload(int embedded_worker_id) override {
+ if (!force_start_worker_failure_) {
+ EmbeddedWorkerTestHelper::OnResumeAfterDownload(embedded_worker_id);
+ } else {
+ SimulateWorkerThreadStarted(GetNextThreadId(), embedded_worker_id);
+ SimulateWorkerScriptEvaluated(embedded_worker_id, false);
+ }
}
// ServiceWorkerRegistration::Listener overrides
@@ -865,7 +897,6 @@ class UpdateJobTestHelper
}
void OnUpdateFound(ServiceWorkerRegistration* registration) override {
- ASSERT_FALSE(update_found_);
update_found_ = true;
}
@@ -882,6 +913,7 @@ class UpdateJobTestHelper
std::vector<AttributeChangeLogEntry> attribute_change_log_;
std::vector<StateChangeLogEntry> state_change_log_;
bool update_found_ = false;
+ bool force_start_worker_failure_ = false;
};
// Helper class for update tests that evicts the active version when the update
@@ -894,7 +926,8 @@ class EvictIncumbentVersionHelper : public UpdateJobTestHelper {
void OnStartWorker(int embedded_worker_id,
int64_t version_id,
const GURL& scope,
- const GURL& script) override {
+ const GURL& script,
+ bool pause_after_download) override {
ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
ServiceWorkerRegistration* registration =
context()->GetLiveRegistration(version->registration_id());
@@ -907,7 +940,7 @@ class EvictIncumbentVersionHelper : public UpdateJobTestHelper {
make_scoped_refptr(registration->active_version()));
}
UpdateJobTestHelper::OnStartWorker(embedded_worker_id, version_id, scope,
- script);
+ script, pause_after_download);
}
void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
@@ -965,16 +998,41 @@ TEST_F(ServiceWorkerJobTest, Update_BumpLastUpdateCheckTime) {
helper_.reset(update_helper);
scoped_refptr<ServiceWorkerRegistration> registration =
update_helper->SetupInitialRegistration(kNoChangeOrigin);
+ ASSERT_TRUE(registration.get());
- // Run an update where the last update check was less than 24 hours ago. The
- // check time shouldn't change, as we didn't bypass cache.
+ registration->AddListener(update_helper);
+
+ // Run an update where the script did not change and the network was not
+ // accessed. The check time should not be updated.
registration->set_last_update_check(kToday);
registration->active_version()->StartUpdate();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kToday, registration->last_update_check());
+ EXPECT_FALSE(update_helper->update_found_);
+
+ // Run an update where the script did not change and the network was accessed.
+ // The check time should be updated.
+ registration->set_last_update_check(kYesterday);
+ registration->active_version()->StartUpdate();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_LT(kYesterday, registration->last_update_check());
+ EXPECT_FALSE(update_helper->update_found_);
+ registration->RemoveListener(update_helper);
+
+ registration = update_helper->SetupInitialRegistration(kNewVersionOrigin);
+ ASSERT_TRUE(registration.get());
- // Run an update where the last update check was over 24 hours ago. The
- // check time should change, as the cache was bypassed.
+ registration->AddListener(update_helper);
+
+ // Run an update where the script changed. The check time should be updated.
+ registration->set_last_update_check(kYesterday);
+ registration->active_version()->StartUpdate();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_LT(kYesterday, registration->last_update_check());
+
+ // Run an update to a worker that loads successfully but fails to start up
+ // (script evaluation failure). The check time should be updated.
+ update_helper->set_force_start_worker_failure(true);
registration->set_last_update_check(kYesterday);
registration->active_version()->StartUpdate();
base::RunLoop().RunUntilIdle();
@@ -1370,7 +1428,8 @@ class EventCallbackHelper : public EmbeddedWorkerTestHelper {
void set_activate_event_result(blink::WebServiceWorkerEventResult result) {
activate_event_result_ = result;
}
-private:
+
+ private:
base::Closure install_callback_;
blink::WebServiceWorkerEventResult install_event_result_;
blink::WebServiceWorkerEventResult activate_event_result_;
@@ -1488,4 +1547,39 @@ TEST_F(ServiceWorkerJobTest, RemoveControlleeDuringInstall_RejectActivate) {
FindRegistrationForPattern(pattern, SERVICE_WORKER_OK);
}
+TEST_F(ServiceWorkerJobTest, Update_PauseAfterDownload) {
+ UpdateJobTestHelper* update_helper = new UpdateJobTestHelper;
+ helper_.reset(update_helper);
+ IPC::TestSink* sink = update_helper->ipc_sink();
+
+ // The initial version should not pause after download.
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ update_helper->SetupInitialRegistration(kNewVersionOrigin);
+ {
+ const IPC::Message* start_msg =
+ sink->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID);
+ ASSERT_TRUE(start_msg);
+ EmbeddedWorkerMsg_StartWorker::Param param;
+ EmbeddedWorkerMsg_StartWorker::Read(start_msg, &param);
+ EmbeddedWorkerMsg_StartWorker_Params start_params = base::get<0>(param);
+ EXPECT_FALSE(start_params.pause_after_download);
+ sink->ClearMessages();
+ }
+
+ // The updated version should pause after download.
+ registration->AddListener(update_helper);
+ registration->active_version()->StartUpdate();
+ base::RunLoop().RunUntilIdle();
+ {
+ const IPC::Message* start_msg =
+ sink->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID);
+ ASSERT_TRUE(start_msg);
+ EmbeddedWorkerMsg_StartWorker::Param param;
+ EmbeddedWorkerMsg_StartWorker::Read(start_msg, &param);
+ EmbeddedWorkerMsg_StartWorker_Params start_params = base::get<0>(param);
+ EXPECT_TRUE(start_params.pause_after_download);
+ sink->ClearMessages();
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.cc b/chromium/content/browser/service_worker/service_worker_metrics.cc
index c2fc43b905f..3fdb74f5651 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.cc
+++ b/chromium/content/browser/service_worker/service_worker_metrics.cc
@@ -16,6 +16,35 @@ namespace content {
namespace {
+std::string StartSituationToSuffix(
+ ServiceWorkerMetrics::StartSituation situation) {
+ switch (situation) {
+ case ServiceWorkerMetrics::StartSituation::DURING_STARTUP:
+ return "_DuringStartup";
+ case ServiceWorkerMetrics::StartSituation::NEW_PROCESS:
+ return "_NewProcess";
+ case ServiceWorkerMetrics::StartSituation::EXISTING_PROCESS:
+ return "_ExistingProcess";
+ default:
+ NOTREACHED() << static_cast<int>(situation);
+ }
+ return "_Unknown";
+}
+
+// Use this for histograms with dynamically generated names, which
+// otherwise can't use the UMA_HISTOGRAM macro without code duplication.
+void RecordSuffixedTimeHistogram(const std::string& name,
+ const std::string& suffix,
+ base::TimeDelta sample) {
+ const std::string name_with_suffix = name + suffix;
+ // This unrolls UMA_HISTOGRAM_MEDIUM_TIMES.
+ base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
+ name_with_suffix, base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(3), 50,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram_pointer->AddTime(sample);
+}
+
void RecordURLMetricOnUI(const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetContentClient()->browser()->RecordURLMetric(
@@ -46,6 +75,44 @@ enum EventHandledRatioType {
} // namespace
+const char* ServiceWorkerMetrics::EventTypeToString(EventType event_type) {
+ switch (event_type) {
+ case EventType::ACTIVATE:
+ return "Activate";
+ case EventType::INSTALL:
+ return "Install";
+ case EventType::SYNC:
+ return "Sync";
+ case EventType::NOTIFICATION_CLICK:
+ return "Notification Click";
+ case EventType::NOTIFICATION_CLOSE:
+ return "Notification Close";
+ case EventType::PUSH:
+ return "Push";
+ case EventType::GEOFENCING:
+ return "Geofencing";
+ case EventType::MESSAGE:
+ return "Message";
+ case EventType::FETCH_MAIN_FRAME:
+ return "Fetch Main Frame";
+ case EventType::FETCH_SUB_FRAME:
+ return "Fetch Sub Frame";
+ case EventType::FETCH_SHARED_WORKER:
+ return "Fetch Shared Worker";
+ case EventType::FETCH_SUB_RESOURCE:
+ return "Fetch Subresource";
+ case EventType::UNKNOWN:
+ return "Unknown";
+ case EventType::FOREIGN_FETCH:
+ return "Foreign Fetch";
+ case EventType::DEPRECATED_FETCH:
+ case EventType::NUM_TYPES:
+ break;
+ }
+ NOTREACHED() << "Got unexpected event type: " << static_cast<int>(event_type);
+ return "error";
+}
+
bool ServiceWorkerMetrics::ShouldExcludeSiteFromHistogram(Site site) {
return site == ServiceWorkerMetrics::Site::NEW_TAB_PAGE;
}
@@ -118,22 +185,37 @@ void ServiceWorkerMetrics::CountControlledPageLoad(const GURL& url) {
void ServiceWorkerMetrics::RecordStartWorkerStatus(
ServiceWorkerStatusCode status,
+ EventType purpose,
bool is_installed) {
if (is_installed) {
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status,
SERVICE_WORKER_ERROR_MAX_VALUE);
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Purpose",
+ static_cast<int>(purpose),
+ static_cast<int>(EventType::NUM_TYPES));
+ if (status == SERVICE_WORKER_ERROR_TIMEOUT) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ServiceWorker.StartWorker.Timeout.StartPurpose",
+ static_cast<int>(purpose), static_cast<int>(EventType::NUM_TYPES));
+ }
} else {
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartNewWorker.Status", status,
SERVICE_WORKER_ERROR_MAX_VALUE);
}
}
-void ServiceWorkerMetrics::RecordStartWorkerTime(const base::TimeDelta& time,
- bool is_installed) {
- if (is_installed)
- UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", time);
- else
+void ServiceWorkerMetrics::RecordStartWorkerTime(
+ base::TimeDelta time,
+ bool is_installed,
+ StartSituation start_situation) {
+ if (is_installed) {
+ std::string name = "ServiceWorker.StartWorker.Time";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, time);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(start_situation),
+ time);
+ } else {
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartNewWorker.Time", time);
+ }
}
void ServiceWorkerMetrics::RecordWorkerStopped(StopStatus status) {
@@ -142,7 +224,7 @@ void ServiceWorkerMetrics::RecordWorkerStopped(StopStatus status) {
static_cast<int>(StopStatus::NUM_TYPES));
}
-void ServiceWorkerMetrics::RecordStopWorkerTime(const base::TimeDelta& time) {
+void ServiceWorkerMetrics::RecordStopWorkerTime(base::TimeDelta time) {
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StopWorker.Time", time);
}
@@ -169,11 +251,24 @@ void ServiceWorkerMetrics::RecordEventHandledRatio(EventType event,
else if (handled_events == 0)
type = EVENT_HANDLED_NONE;
- // For now Fetch is the only type that is recorded.
- if (event != EventType::FETCH)
- return;
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.EventHandledRatioType.Fetch", type,
- NUM_EVENT_HANDLED_RATIO_TYPE);
+ // For now Fetch and Foreign Fetch are the only types that are recorded.
+ switch (event) {
+ case EventType::FETCH_MAIN_FRAME:
+ case EventType::FETCH_SUB_FRAME:
+ case EventType::FETCH_SHARED_WORKER:
+ case EventType::FETCH_SUB_RESOURCE:
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.EventHandledRatioType.Fetch",
+ type, NUM_EVENT_HANDLED_RATIO_TYPE);
+ break;
+ case EventType::FOREIGN_FETCH:
+ UMA_HISTOGRAM_ENUMERATION(
+ "ServiceWorker.EventHandledRatioType.ForeignFetch", type,
+ NUM_EVENT_HANDLED_RATIO_TYPE);
+ break;
+ default:
+ // Do nothing.
+ break;
+ }
}
void ServiceWorkerMetrics::RecordEventTimeout(EventType event) {
@@ -183,7 +278,8 @@ void ServiceWorkerMetrics::RecordEventTimeout(EventType event) {
}
void ServiceWorkerMetrics::RecordEventDuration(EventType event,
- const base::TimeDelta& time) {
+ base::TimeDelta time,
+ bool was_handled) {
switch (event) {
case EventType::ACTIVATE:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.ActivateEvent.Time", time);
@@ -191,6 +287,27 @@ void ServiceWorkerMetrics::RecordEventDuration(EventType event,
case EventType::INSTALL:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.InstallEvent.Time", time);
break;
+ case EventType::FETCH_MAIN_FRAME:
+ case EventType::FETCH_SUB_FRAME:
+ case EventType::FETCH_SHARED_WORKER:
+ case EventType::FETCH_SUB_RESOURCE:
+ if (was_handled) {
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.FetchEvent.HasResponse.Time",
+ time);
+ } else {
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.FetchEvent.Fallback.Time",
+ time);
+ }
+ break;
+ case EventType::FOREIGN_FETCH:
+ if (was_handled) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "ServiceWorker.ForeignFetchEvent.HasResponse.Time", time);
+ } else {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "ServiceWorker.ForeignFetchEvent.Fallback.Time", time);
+ }
+ break;
case EventType::SYNC:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.BackgroundSyncEvent.Time",
time);
@@ -199,17 +316,24 @@ void ServiceWorkerMetrics::RecordEventDuration(EventType event,
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.NotificationClickEvent.Time",
time);
break;
+ case EventType::NOTIFICATION_CLOSE:
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.NotificationCloseEvent.Time",
+ time);
+ break;
case EventType::PUSH:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.PushEvent.Time", time);
break;
+ case EventType::MESSAGE:
+ // TODO(nhiroki): Record event duration for Message event after
+ // ExtendableMessageEvent is enabled by default (crbug.com/543198).
+ break;
- // Event duration for fetch is recorded separately.
- case EventType::FETCH:
// For now event duration for these events is not recorded.
case EventType::GEOFENCING:
- case EventType::SERVICE_PORT_CONNECT:
break;
+ case EventType::DEPRECATED_FETCH:
+ case EventType::UNKNOWN:
case EventType::NUM_TYPES:
NOTREACHED() << "Invalid event type";
break;
@@ -228,23 +352,6 @@ void ServiceWorkerMetrics::RecordFetchEventStatus(
}
}
-void ServiceWorkerMetrics::RecordFetchEventTime(
- ServiceWorkerFetchEventResult result,
- const base::TimeDelta& time) {
- switch (result) {
- case ServiceWorkerFetchEventResult::
- SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK:
- UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.FetchEvent.Fallback.Time",
- time);
- break;
- case ServiceWorkerFetchEventResult::
- SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE:
- UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.FetchEvent.HasResponse.Time",
- time);
- break;
- }
-}
-
void ServiceWorkerMetrics::RecordURLRequestJobResult(
bool is_main_resource,
URLRequestJobResult result) {
@@ -276,9 +383,98 @@ void ServiceWorkerMetrics::RecordFallbackedRequestMode(FetchRequestMode mode) {
mode, FETCH_REQUEST_MODE_LAST + 1);
}
-void ServiceWorkerMetrics::RecordTimeBetweenEvents(
- const base::TimeDelta& time) {
+void ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeDelta time) {
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.TimeBetweenEvents", time);
}
+void ServiceWorkerMetrics::RecordProcessCreated(bool is_new_process) {
+ UMA_HISTOGRAM_BOOLEAN("EmbeddedWorkerInstance.ProcessCreated",
+ is_new_process);
+}
+
+void ServiceWorkerMetrics::RecordTimeToSendStartWorker(
+ base::TimeDelta duration,
+ StartSituation situation) {
+ std::string name = "EmbeddedWorkerInstance.Start.TimeToSendStartWorker";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+}
+
+void ServiceWorkerMetrics::RecordTimeToURLJob(base::TimeDelta duration,
+ StartSituation situation) {
+ std::string name = "EmbeddedWorkerInstance.Start.TimeToURLJob";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+}
+
+void ServiceWorkerMetrics::RecordTimeToLoad(base::TimeDelta duration,
+ LoadSource source,
+ StartSituation situation) {
+ std::string name;
+ switch (source) {
+ case LoadSource::NETWORK:
+ name = "EmbeddedWorkerInstance.Start.TimeToLoad.Network";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+ break;
+ case LoadSource::HTTP_CACHE:
+ name = "EmbeddedWorkerInstance.Start.TimeToLoad.HttpCache";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+ break;
+ case LoadSource::SERVICE_WORKER_STORAGE:
+ name = "EmbeddedWorkerInstance.Start.TimeToLoad.InstalledScript";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+ break;
+ default:
+ NOTREACHED() << static_cast<int>(source);
+ }
+}
+
+void ServiceWorkerMetrics::RecordTimeToStartThread(base::TimeDelta duration,
+ StartSituation situation) {
+ std::string name = "EmbeddedWorkerInstance.Start.TimeToStartThread";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+}
+
+void ServiceWorkerMetrics::RecordTimeToEvaluateScript(
+ base::TimeDelta duration,
+ StartSituation situation) {
+ std::string name = "EmbeddedWorkerInstance.Start.TimeToEvaluateScript";
+ UMA_HISTOGRAM_MEDIUM_TIMES(name, duration);
+ RecordSuffixedTimeHistogram(name, StartSituationToSuffix(situation),
+ duration);
+}
+
+const char* ServiceWorkerMetrics::LoadSourceToString(LoadSource source) {
+ switch (source) {
+ case LoadSource::NETWORK:
+ return "Network";
+ case LoadSource::HTTP_CACHE:
+ return "HTTP cache";
+ case LoadSource::SERVICE_WORKER_STORAGE:
+ return "Service worker storage";
+ }
+ NOTREACHED() << static_cast<int>(source);
+ return nullptr;
+}
+
+ServiceWorkerMetrics::StartSituation ServiceWorkerMetrics::GetStartSituation(
+ bool is_browser_startup_complete,
+ bool is_new_process) {
+ if (!is_browser_startup_complete)
+ return StartSituation::DURING_STARTUP;
+ if (is_new_process)
+ return StartSituation::NEW_PROCESS;
+ return StartSituation::EXISTING_PROCESS;
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.h b/chromium/content/browser/service_worker/service_worker_metrics.h
index 83dfb2ac5f8..e14d1ad3789 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.h
+++ b/chromium/content/browser/service_worker/service_worker_metrics.h
@@ -18,6 +18,7 @@ namespace content {
class ServiceWorkerMetrics {
public:
+ // Used for UMA. Append-only.
enum ReadResponseResult {
READ_OK,
READ_HEADERS_ERROR,
@@ -25,6 +26,7 @@ class ServiceWorkerMetrics {
NUM_READ_RESPONSE_RESULT_TYPES,
};
+ // Used for UMA. Append-only.
enum WriteResponseResult {
WRITE_OK,
WRITE_HEADERS_ERROR,
@@ -32,6 +34,7 @@ class ServiceWorkerMetrics {
NUM_WRITE_RESPONSE_RESULT_TYPES,
};
+ // Used for UMA. Append-only.
enum DeleteAndStartOverResult {
DELETE_OK,
DELETE_DATABASE_ERROR,
@@ -39,6 +42,7 @@ class ServiceWorkerMetrics {
NUM_DELETE_AND_START_OVER_RESULT_TYPES,
};
+ // Used for UMA. Append-only.
enum URLRequestJobResult {
REQUEST_JOB_FALLBACK_RESPONSE,
REQUEST_JOB_FALLBACK_FOR_CORS,
@@ -74,22 +78,43 @@ class ServiceWorkerMetrics {
// Used for UMA. Append-only.
enum class EventType {
- ACTIVATE,
- INSTALL,
- FETCH,
- SYNC,
- NOTIFICATION_CLICK,
- PUSH,
- GEOFENCING,
- SERVICE_PORT_CONNECT,
+ ACTIVATE = 0,
+ INSTALL = 1,
+ DEPRECATED_FETCH = 2, // Deprecated, use a more specific FETCH_ type.
+ SYNC = 3,
+ NOTIFICATION_CLICK = 4,
+ PUSH = 5,
+ GEOFENCING = 6,
+ // SERVICE_PORT_CONNECT = 7,
+ MESSAGE = 8,
+ NOTIFICATION_CLOSE = 9,
+ FETCH_MAIN_FRAME = 10,
+ FETCH_SUB_FRAME = 11,
+ FETCH_SHARED_WORKER = 12,
+ FETCH_SUB_RESOURCE = 13,
+ UNKNOWN = 14, // Used when event type is not known.
+ FOREIGN_FETCH = 15,
// Add new events to record here.
-
NUM_TYPES
};
// Used for UMA. Append only.
enum class Site { OTHER, NEW_TAB_PAGE, NUM_TYPES };
+ // Not used for UMA.
+ enum class StartSituation {
+ UNKNOWN,
+ DURING_STARTUP,
+ EXISTING_PROCESS,
+ NEW_PROCESS
+ };
+
+ // Not used for UMA.
+ enum class LoadSource { NETWORK, HTTP_CACHE, SERVICE_WORKER_STORAGE };
+
+ // Converts an event type to a string. Used for tracing.
+ static const char* EventTypeToString(EventType event_type);
+
// Excludes NTP scope from UMA for now as it tends to dominate the stats and
// makes the results largely skewed. Some metrics don't follow this policy
// and hence don't call this function.
@@ -117,18 +142,20 @@ class ServiceWorkerMetrics {
// Records the result of trying to start a worker. |is_installed| indicates
// whether the version has been installed.
static void RecordStartWorkerStatus(ServiceWorkerStatusCode status,
+ EventType purpose,
bool is_installed);
// Records the time taken to successfully start a worker. |is_installed|
// indicates whether the version has been installed.
- static void RecordStartWorkerTime(const base::TimeDelta& time,
- bool is_installed);
+ static void RecordStartWorkerTime(base::TimeDelta time,
+ bool is_installed,
+ StartSituation start_situation);
// Records the result of trying to stop a worker.
static void RecordWorkerStopped(StopStatus status);
// Records the time taken to successfully stop a worker.
- static void RecordStopWorkerTime(const base::TimeDelta& time);
+ static void RecordStopWorkerTime(base::TimeDelta time);
static void RecordActivateEventStatus(ServiceWorkerStatusCode status);
static void RecordInstallEventStatus(ServiceWorkerStatusCode status);
@@ -143,17 +170,14 @@ class ServiceWorkerMetrics {
static void RecordEventTimeout(EventType event);
// Records the amount of time spent handling an event.
- static void RecordEventDuration(EventType event, const base::TimeDelta& time);
+ static void RecordEventDuration(EventType event,
+ base::TimeDelta time,
+ bool was_handled);
// Records the result of dispatching a fetch event to a service worker.
static void RecordFetchEventStatus(bool is_main_resource,
ServiceWorkerStatusCode status);
- // Records the amount of time spent handling a fetch event with the given
- // result.
- static void RecordFetchEventTime(ServiceWorkerFetchEventResult result,
- const base::TimeDelta& time);
-
// Records result of a ServiceWorkerURLRequestJob that was forwarded to
// the service worker.
static void RecordURLRequestJobResult(bool is_main_resource,
@@ -171,7 +195,25 @@ class ServiceWorkerMetrics {
// Called at the beginning of each ServiceWorkerVersion::Dispatch*Event
// function. Records the time elapsed since idle (generally the time since the
// previous event ended).
- static void RecordTimeBetweenEvents(const base::TimeDelta& time);
+ static void RecordTimeBetweenEvents(base::TimeDelta time);
+
+ // The following record steps of EmbeddedWorkerInstance's start sequence.
+ static void RecordProcessCreated(bool is_new_process);
+ static void RecordTimeToSendStartWorker(base::TimeDelta duration,
+ StartSituation start_situation);
+ static void RecordTimeToURLJob(base::TimeDelta duration,
+ StartSituation start_situation);
+ static void RecordTimeToLoad(base::TimeDelta duration,
+ LoadSource source,
+ StartSituation start_situation);
+ static void RecordTimeToStartThread(base::TimeDelta duration,
+ StartSituation start_situation);
+ static void RecordTimeToEvaluateScript(base::TimeDelta duration,
+ StartSituation start_situation);
+
+ static const char* LoadSourceToString(LoadSource source);
+ static StartSituation GetStartSituation(bool is_browser_startup_complete,
+ bool is_new_process);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
diff --git a/chromium/content/browser/service_worker/service_worker_process_manager.cc b/chromium/content/browser/service_worker/service_worker_process_manager.cc
index 4b559edce8a..74253b59d57 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.cc
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.cc
@@ -11,9 +11,12 @@
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/service_worker/embedded_worker_settings.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/site_instance.h"
#include "content/public/common/child_process_host.h"
+#include "content/public/common/content_client.h"
#include "url/gurl.h"
namespace content {
@@ -40,6 +43,9 @@ ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(int process_id)
: process_id(process_id) {
}
+ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(
+ const ProcessInfo& other) = default;
+
ServiceWorkerProcessManager::ProcessInfo::~ProcessInfo() {
}
@@ -47,6 +53,7 @@ ServiceWorkerProcessManager::ServiceWorkerProcessManager(
BrowserContext* browser_context)
: browser_context_(browser_context),
process_id_for_test_(ChildProcessHost::kInvalidUniqueID),
+ new_process_id_for_test_(ChildProcessHost::kInvalidUniqueID),
weak_this_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
weak_this_ = weak_this_factory_.GetWeakPtr();
@@ -132,29 +139,36 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
int embedded_worker_id,
const GURL& pattern,
const GURL& script_url,
+ bool can_use_existing_process,
const base::Callback<void(ServiceWorkerStatusCode,
int process_id,
- bool is_new_process)>& callback) {
+ bool is_new_process,
+ const EmbeddedWorkerSettings&)>& callback) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
+ BrowserThread::UI, FROM_HERE,
base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess,
- weak_this_,
- embedded_worker_id,
- pattern,
- script_url,
- callback));
+ weak_this_, embedded_worker_id, pattern, script_url,
+ can_use_existing_process, callback));
return;
}
+ // This |EmbeddedWorkerSettings| only populates |data_saver_enabled|,
+ // but in general, this function will populate settings from prefs, while
+ // the caller will be responsible for populating settings from other sources,
+ // such as command line switches.
+ EmbeddedWorkerSettings settings;
+ settings.data_saver_enabled =
+ GetContentClient()->browser()->IsDataSaverEnabled(browser_context_);
+
if (process_id_for_test_ != ChildProcessHost::kInvalidUniqueID) {
// Let tests specify the returned process ID. Note: We may need to be able
// to specify the error code too.
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(callback, SERVICE_WORKER_OK, process_id_for_test_,
- false /* is_new_process */));
+ int result = can_use_existing_process ? process_id_for_test_
+ : new_process_id_for_test_;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, result,
+ false /* is_new_process */, settings));
return;
}
@@ -162,7 +176,7 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(callback, SERVICE_WORKER_ERROR_ABORT,
ChildProcessHost::kInvalidUniqueID,
- false /* is_new_process */));
+ false /* is_new_process */, settings));
return;
}
@@ -171,15 +185,18 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
CHECK(!ContainsKey(instance_info_, embedded_worker_id))
<< embedded_worker_id << " already has a process allocated";
- int process_id = FindAvailableProcess(pattern);
- if (process_id != ChildProcessHost::kInvalidUniqueID) {
- RenderProcessHost::FromID(process_id)->IncrementWorkerRefCount();
- instance_info_.insert(
- std::make_pair(embedded_worker_id, ProcessInfo(process_id)));
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(callback, SERVICE_WORKER_OK, process_id,
- false /* is_new_process */));
- return;
+ if (can_use_existing_process) {
+ int process_id = FindAvailableProcess(pattern);
+ if (process_id != ChildProcessHost::kInvalidUniqueID) {
+ RenderProcessHost::FromID(process_id)->IncrementWorkerRefCount();
+ instance_info_.insert(
+ std::make_pair(embedded_worker_id, ProcessInfo(process_id)));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, process_id,
+ false /* is_new_process */, settings));
+ return;
+ }
}
// No existing processes available; start a new one.
@@ -196,7 +213,7 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
BrowserThread::IO, FROM_HERE,
base::Bind(callback, SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND,
ChildProcessHost::kInvalidUniqueID,
- false /* is_new_process */));
+ false /* is_new_process */, settings));
return;
}
@@ -206,7 +223,7 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
rph->IncrementWorkerRefCount();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(callback, SERVICE_WORKER_OK, rph->GetID(),
- true /* is_new_process */));
+ true /* is_new_process */, settings));
}
void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) {
diff --git a/chromium/content/browser/service_worker/service_worker_process_manager.h b/chromium/content/browser/service_worker/service_worker_process_manager.h
index 443aafbd017..465ed5a8fea 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.h
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.h
@@ -20,6 +20,7 @@ class GURL;
namespace content {
class BrowserContext;
+struct EmbeddedWorkerSettings;
class SiteInstance;
// Interacts with the UI thread to keep RenderProcessHosts alive while the
@@ -49,9 +50,11 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
int embedded_worker_id,
const GURL& pattern,
const GURL& script_url,
+ bool can_use_existing_process,
const base::Callback<void(ServiceWorkerStatusCode,
int process_id,
- bool is_new_process)>& callback);
+ bool is_new_process,
+ const EmbeddedWorkerSettings&)>& callback);
// Drops a reference to a process that was running a Service Worker, and its
// SiteInstance. This must match a call to AllocateWorkerProcess.
@@ -66,6 +69,11 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
process_id_for_test_ = process_id;
}
+ // Sets the process ID to be used for tests that force creating a new process.
+ void SetNewProcessIdForTest(int process_id) {
+ new_process_id_for_test_ = process_id;
+ }
+
// Adds/removes process reference for the |pattern|, the process with highest
// references count will be chosen to start a worker.
void AddProcessReferenceToPattern(const GURL& pattern, int process_id);
@@ -87,6 +95,7 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
struct ProcessInfo {
explicit ProcessInfo(const scoped_refptr<SiteInstance>& site_instance);
explicit ProcessInfo(int process_id);
+ ProcessInfo(const ProcessInfo& other);
~ProcessInfo();
// Stores the SiteInstance the Worker lives inside. This needs to outlive
@@ -132,6 +141,7 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
// In unit tests, this will be returned as the process for all
// EmbeddedWorkerInstances.
int process_id_for_test_;
+ int new_process_id_for_test_;
// Candidate processes info for each pattern, should be accessed on the
// UI thread.
diff --git a/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc b/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc
index 384f996b862..98ded5986e9 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/browser/service_worker/service_worker_process_manager.h"
+#include "content/common/service_worker/embedded_worker_settings.h"
#include "content/public/common/child_process_host.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
@@ -24,7 +25,8 @@ void DidAllocateWorkerProcess(const base::Closure& quit_closure,
bool* is_new_process_out,
ServiceWorkerStatusCode status,
int process_id,
- bool is_new_process) {
+ bool is_new_process,
+ const EmbeddedWorkerSettings& settings) {
*status_out = status;
*process_id_out = process_id;
*is_new_process_out = is_new_process;
@@ -143,6 +145,7 @@ TEST_F(ServiceWorkerProcessManagerTest,
bool is_new_process = true;
process_manager_->AllocateWorkerProcess(
kEmbeddedWorkerId1, scope1, script_url_,
+ true /* can_use_existing_process */,
base::Bind(&DidAllocateWorkerProcess, run_loop1.QuitClosure(), &status,
&process_id, &is_new_process));
run_loop1.Run();
@@ -167,6 +170,7 @@ TEST_F(ServiceWorkerProcessManagerTest,
is_new_process = true;
process_manager_->AllocateWorkerProcess(
kEmbeddedWorkerId2, scope1, script_url_,
+ true /* can_use_existing_process */,
base::Bind(&DidAllocateWorkerProcess, run_loop2.QuitClosure(), &status,
&process_id, &is_new_process));
run_loop2.Run();
@@ -182,7 +186,7 @@ TEST_F(ServiceWorkerProcessManagerTest,
ASSERT_TRUE(found != instance_info.end());
EXPECT_EQ(host1->GetID(), found->second.process_id);
- // (3) Allocate a process to the other worker whose scope is different from
+ // (3) Allocate a process to a third worker whose scope is different from
// other workers.
base::RunLoop run_loop3;
status = SERVICE_WORKER_ERROR_MAX_VALUE;
@@ -190,6 +194,7 @@ TEST_F(ServiceWorkerProcessManagerTest,
is_new_process = true;
process_manager_->AllocateWorkerProcess(
kEmbeddedWorkerId3, scope2, script_url_,
+ true /* can_use_existing_process */,
base::Bind(&DidAllocateWorkerProcess, run_loop3.QuitClosure(), &status,
&process_id, &is_new_process));
run_loop3.Run();
@@ -234,7 +239,7 @@ TEST_F(ServiceWorkerProcessManagerTest, AllocateWorkerProcess_InShutdown) {
int process_id = -10;
bool is_new_process = true;
process_manager_->AllocateWorkerProcess(
- 1, pattern_, script_url_,
+ 1, pattern_, script_url_, true /* can_use_existing_process */,
base::Bind(&DidAllocateWorkerProcess, run_loop.QuitClosure(), &status,
&process_id, &is_new_process));
run_loop.Run();
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.cc b/chromium/content/browser/service_worker/service_worker_provider_host.cc
index 1d79f5290b0..0c8c35d8f9b 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.cc
@@ -9,9 +9,6 @@
#include "base/guid.h"
#include "base/stl_util.h"
#include "base/time/time.h"
-#include "content/browser/frame_host/frame_tree.h"
-#include "content/browser/frame_host/frame_tree_node.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
@@ -20,14 +17,10 @@
#include "content/browser/service_worker/service_worker_handle.h"
#include "content/browser/service_worker/service_worker_registration_handle.h"
#include "content/browser/service_worker/service_worker_version.h"
-#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/child_process_host.h"
@@ -35,32 +28,6 @@ namespace content {
namespace {
-ServiceWorkerClientInfo FocusOnUIThread(int render_process_id,
- int render_frame_id) {
- RenderFrameHostImpl* render_frame_host =
- RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
- WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
- WebContents::FromRenderFrameHost(render_frame_host));
-
- if (!render_frame_host || !web_contents)
- return ServiceWorkerClientInfo();
-
- FrameTreeNode* frame_tree_node = render_frame_host->frame_tree_node();
-
- // Focus the frame in the frame tree node, in case it has changed.
- frame_tree_node->frame_tree()->SetFocusedFrame(
- frame_tree_node, render_frame_host->GetSiteInstance());
-
- // Focus the frame's view to make sure the frame is now considered as focused.
- render_frame_host->GetView()->Focus();
-
- // Move the web contents to the foreground.
- web_contents->Activate();
-
- return ServiceWorkerProviderHost::GetWindowClientInfoOnUI(render_process_id,
- render_frame_id);
-}
-
// PlzNavigate
// Next ServiceWorkerProviderHost ID for navigations, starts at -2 and keeps
// going down.
@@ -218,25 +185,21 @@ void ServiceWorkerProviderHost::SetControllerVersionAttribute(
notify_controllerchange));
}
-bool ServiceWorkerProviderHost::SetHostedVersionId(int64_t version_id) {
- if (!context_)
- return true; // System is shutting down.
+bool ServiceWorkerProviderHost::SetHostedVersion(
+ ServiceWorkerVersion* version) {
+ // TODO(falken): Unclear why we check active_version. Should this just check
+ // that IsProviderForClient() is false?
if (active_version())
return false; // Unexpected bad message.
- ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
- if (!live_version)
- return true; // Was deleted before it got started.
-
- ServiceWorkerVersionInfo info = live_version->GetInfo();
- if (info.running_status != ServiceWorkerVersion::STARTING ||
- info.process_id != render_process_id_) {
+ DCHECK_EQ(ServiceWorkerVersion::STARTING, version->running_status());
+ if (version->embedded_worker()->process_id() != render_process_id_) {
// If we aren't trying to start this version in our process
// something is amiss.
return false;
}
- running_hosted_version_ = live_version;
+ running_hosted_version_ = version;
return true;
}
@@ -433,50 +396,6 @@ void ServiceWorkerProviderHost::PostMessageToClient(
Send(new ServiceWorkerMsg_MessageToDocument(params));
}
-void ServiceWorkerProviderHost::Focus(const GetClientInfoCallback& callback) {
- if (provider_type_ != SERVICE_WORKER_PROVIDER_FOR_WINDOW) {
- callback.Run(ServiceWorkerClientInfo());
- return;
- }
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&FocusOnUIThread, render_process_id_, route_id_), callback);
-}
-
-void ServiceWorkerProviderHost::GetWindowClientInfo(
- const GetClientInfoCallback& callback) const {
- if (provider_type_ != SERVICE_WORKER_PROVIDER_FOR_WINDOW) {
- callback.Run(ServiceWorkerClientInfo());
- return;
- }
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&ServiceWorkerProviderHost::GetWindowClientInfoOnUI,
- render_process_id_, route_id_),
- callback);
-}
-
-// static
-ServiceWorkerClientInfo ServiceWorkerProviderHost::GetWindowClientInfoOnUI(
- int render_process_id,
- int render_frame_id) {
- RenderFrameHostImpl* render_frame_host =
- RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
- if (!render_frame_host)
- return ServiceWorkerClientInfo();
-
- // TODO(mlamouri,michaeln): it is possible to end up collecting information
- // for a frame that is actually being navigated and isn't exactly what we are
- // expecting.
- return ServiceWorkerClientInfo(
- render_frame_host->GetVisibilityState(), render_frame_host->IsFocused(),
- render_frame_host->GetLastCommittedURL(),
- render_frame_host->GetParent() ? REQUEST_CONTEXT_FRAME_TYPE_NESTED
- : REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
- render_frame_host->frame_tree_node()->last_focus_time(),
- blink::WebServiceWorkerClientTypeWindow);
-}
-
void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
const GURL& pattern) {
associated_patterns_.push_back(pattern);
@@ -592,12 +511,11 @@ void ServiceWorkerProviderHost::SendSetVersionAttributesMessage(
return;
if (!IsReadyToSendMessages()) {
- queued_events_.push_back(
- base::Bind(&ServiceWorkerProviderHost::SendSetVersionAttributesMessage,
- AsWeakPtr(), registration_handle_id, changed_mask,
- make_scoped_refptr(installing_version),
- make_scoped_refptr(waiting_version),
- make_scoped_refptr(active_version)));
+ queued_events_.push_back(base::Bind(
+ &ServiceWorkerProviderHost::SendSetVersionAttributesMessage,
+ AsWeakPtr(), registration_handle_id, changed_mask,
+ base::RetainedRef(installing_version),
+ base::RetainedRef(waiting_version), base::RetainedRef(active_version)));
return;
}
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.h b/chromium/content/browser/service_worker/service_worker_provider_host.h
index 2748e293810..3f1d247b210 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.h
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.h
@@ -51,8 +51,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
: public NON_EXPORTED_BASE(ServiceWorkerRegistration::Listener),
public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
public:
- using GetClientInfoCallback =
- base::Callback<void(const ServiceWorkerClientInfo&)>;
using GetRegistrationForReadyCallback =
base::Callback<void(ServiceWorkerRegistration* reigstration)>;
@@ -133,9 +131,9 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// Clears the associated registration and stop listening to it.
void DisassociateRegistration();
- // Returns false if the version is not in the expected STARTING in our
- // process state. That would be indicative of a bad IPC message.
- bool SetHostedVersionId(int64_t versions_id);
+ // Returns false if we have an active version or |version| is using a
+ // different process. That would be indicative of a bad IPC message.
+ bool SetHostedVersion(ServiceWorkerVersion* version);
// Returns a handler for a request, the handler may return NULL if
// the request doesn't require special handling.
@@ -175,20 +173,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
const base::string16& message,
const std::vector<TransferredMessagePort>& sent_message_ports);
- // Activates the WebContents associated with
- // { render_process_id_, route_id_ }.
- // Runs the |callback| with the updated ServiceWorkerClientInfo in parameter.
- void Focus(const GetClientInfoCallback& callback);
-
- // Asks the renderer to send back the document information.
- void GetWindowClientInfo(const GetClientInfoCallback& callback) const;
-
- // Same as above but has to be called from the UI thread.
- // It is taking the process and frame ids in parameter because |this| is meant
- // to live on the IO thread.
- static ServiceWorkerClientInfo GetWindowClientInfoOnUI(int render_process_id,
- int render_frame_id);
-
// Adds reference of this host's process to the |pattern|, the reference will
// be removed in destructor.
void AddScopedProcessReferenceToPattern(const GURL& pattern);
@@ -264,12 +248,18 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
Update_ElongatedScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
Update_EmptyScript);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
+ DispatchExtendableMessageEvent);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
+ DispatchExtendableMessageEvent_Fail);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateBefore24Hours);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateAfter24Hours);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateForceBypassCache);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ ServiceWorkerDataRequestAnnotation);
struct OneShotGetReadyCallback {
GetRegistrationForReadyCallback callback;
diff --git a/chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc b/chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc
index bd9844b327e..24f84342fed 100644
--- a/chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc
@@ -139,7 +139,6 @@ void ServiceWorkerReadFromCacheJob::StartAsync() {
http_info_io_buffer_.get(),
base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
weak_factory_.GetWeakPtr()));
- SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
}
const net::HttpResponseInfo* ServiceWorkerReadFromCacheJob::http_info() const {
@@ -161,7 +160,6 @@ void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
return;
}
DCHECK_GE(result, 0);
- SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
http_info_.reset(http_info_io_buffer_->http_info.release());
if (is_range_request())
SetupRangeResponse(http_info_io_buffer_->response_data_size);
diff --git a/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
index aa7508b7520..6cb1cbd28b4 100644
--- a/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/browser/fileapi/mock_url_request_delegate.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
@@ -20,6 +21,7 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -59,16 +61,23 @@ class ServiceWorkerReadFromCacheJobTest : public testing::Test {
kResourceSize),
imported_script_(kImportedScriptResourceId,
GURL("http://example.com/imported.js"),
- kResourceSize) {}
+ kResourceSize),
+ test_job_interceptor_(nullptr) {}
~ServiceWorkerReadFromCacheJobTest() override {}
void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
InitializeStorage();
- url_request_context_.reset(new net::URLRequestContext);
- url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
- url_request_context_->set_job_factory(url_request_job_factory_.get());
+ url_request_context_.reset(new net::TestURLRequestContext(true));
+
+ // The |test_job_factory_| takes ownership of the interceptor.
+ test_job_interceptor_ = new net::TestJobInterceptor();
+ EXPECT_TRUE(test_job_factory_.SetProtocolHandler(
+ url::kHttpScheme, make_scoped_ptr(test_job_interceptor_)));
+ url_request_context_->set_job_factory(&test_job_factory_);
+
+ url_request_context_->Init();
}
void InitializeStorage() {
@@ -145,9 +154,8 @@ class ServiceWorkerReadFromCacheJobTest : public testing::Test {
return status;
}
- void StartAndWaitForJob(
- const scoped_ptr<ServiceWorkerReadFromCacheJob>& job) {
- job->Start();
+ void StartAndWaitForRequest(net::URLRequest* request) {
+ request->Start();
// MockURLRequestDelegate quits the loop when the request is completed.
base::RunLoop().RunUntilIdle();
}
@@ -168,8 +176,11 @@ class ServiceWorkerReadFromCacheJobTest : public testing::Test {
ServiceWorkerDatabase::ResourceRecord main_script_;
ServiceWorkerDatabase::ResourceRecord imported_script_;
- scoped_ptr<net::URLRequestContext> url_request_context_;
- scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
+ // |test_job_interceptor_| is owned by |test_job_factory_|.
+ net::TestJobInterceptor* test_job_interceptor_;
+ net::URLRequestJobFactoryImpl test_job_factory_;
+
+ scoped_ptr<net::TestURLRequestContext> url_request_context_;
MockURLRequestDelegate delegate_;
};
@@ -177,12 +188,12 @@ TEST_F(ServiceWorkerReadFromCacheJobTest, ReadMainScript) {
// Read the main script from the diskcache.
scoped_ptr<net::URLRequest> request = url_request_context_->CreateRequest(
main_script_.url, net::DEFAULT_PRIORITY, &delegate_);
- scoped_ptr<ServiceWorkerReadFromCacheJob> job(
- new ServiceWorkerReadFromCacheJob(
+ test_job_interceptor_->set_main_intercept_job(
+ make_scoped_ptr(new ServiceWorkerReadFromCacheJob(
request.get(), nullptr /* NetworkDelegate */,
RESOURCE_TYPE_SERVICE_WORKER, context()->AsWeakPtr(), version_,
- main_script_.resource_id));
- StartAndWaitForJob(job);
+ main_script_.resource_id)));
+ StartAndWaitForRequest(request.get());
EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
EXPECT_EQ(0, request->status().error());
@@ -194,11 +205,11 @@ TEST_F(ServiceWorkerReadFromCacheJobTest, ReadImportedScript) {
// Read the imported script from the diskcache.
scoped_ptr<net::URLRequest> request = url_request_context_->CreateRequest(
imported_script_.url, net::DEFAULT_PRIORITY, &delegate_);
- scoped_ptr<ServiceWorkerReadFromCacheJob> job(
- new ServiceWorkerReadFromCacheJob(
+ test_job_interceptor_->set_main_intercept_job(
+ make_scoped_ptr(new ServiceWorkerReadFromCacheJob(
request.get(), nullptr /* NetworkDelegate */, RESOURCE_TYPE_SCRIPT,
- context()->AsWeakPtr(), version_, imported_script_.resource_id));
- StartAndWaitForJob(job);
+ context()->AsWeakPtr(), version_, imported_script_.resource_id)));
+ StartAndWaitForRequest(request.get());
EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
EXPECT_EQ(0, request->status().error());
@@ -214,12 +225,12 @@ TEST_F(ServiceWorkerReadFromCacheJobTest, ResourceNotFound) {
GURL("http://example.com/nonexistent"), net::DEFAULT_PRIORITY,
&delegate_);
const int64_t kNonexistentResourceId = 100;
- scoped_ptr<ServiceWorkerReadFromCacheJob> job(
- new ServiceWorkerReadFromCacheJob(
+ test_job_interceptor_->set_main_intercept_job(
+ make_scoped_ptr(new ServiceWorkerReadFromCacheJob(
request.get(), nullptr /* NetworkDelegate */,
RESOURCE_TYPE_SERVICE_WORKER, context()->AsWeakPtr(), version_,
- kNonexistentResourceId));
- StartAndWaitForJob(job);
+ kNonexistentResourceId)));
+ StartAndWaitForRequest(request.get());
EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status());
EXPECT_EQ(net::ERR_CACHE_MISS, request->status().error());
diff --git a/chromium/content/browser/service_worker/service_worker_register_job.cc b/chromium/content/browser/service_worker/service_worker_register_job.cc
index 69f5acdcb9c..0dfb0d5e64d 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_register_job.cc
@@ -6,8 +6,6 @@
#include <stdint.h>
-#include <vector>
-
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
@@ -16,6 +14,8 @@
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
@@ -87,7 +87,7 @@ void ServiceWorkerRegisterJob::AddCallback(
}
RunSoon(base::Bind(callback, promise_resolved_status_,
promise_resolved_status_message_,
- promise_resolved_registration_));
+ base::RetainedRef(promise_resolved_registration_)));
}
void ServiceWorkerRegisterJob::Start() {
@@ -344,36 +344,27 @@ void ServiceWorkerRegisterJob::UpdateAndContinue() {
set_new_version(new ServiceWorkerVersion(registration(), script_url_,
version_id, context_));
new_version()->set_force_bypass_cache_for_scripts(force_bypass_cache_);
- new_version()->set_skip_script_comparison(skip_script_comparison_);
+ if (registration()->has_installed_version() && !skip_script_comparison_) {
+ new_version()->set_pause_after_download(true);
+ new_version()->embedded_worker()->AddListener(this);
+ } else {
+ new_version()->set_pause_after_download(false);
+ }
new_version()->StartWorker(
+ ServiceWorkerMetrics::EventType::INSTALL,
base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished,
weak_factory_.GetWeakPtr()));
}
void ServiceWorkerRegisterJob::OnStartWorkerFinished(
ServiceWorkerStatusCode status) {
+ BumpLastUpdateCheckTimeIfNeeded();
+
if (status == SERVICE_WORKER_OK) {
InstallAndContinue();
return;
}
- // The updated worker is identical to the incumbent.
- if (status == SERVICE_WORKER_ERROR_EXISTS) {
- // Only bump the last check time when we've bypassed the browser cache.
- base::TimeDelta time_since_last_check =
- base::Time::Now() - registration()->last_update_check();
- if (time_since_last_check > base::TimeDelta::FromHours(
- kServiceWorkerScriptMaxCacheAgeInHours) ||
- new_version()->force_bypass_cache_for_scripts()) {
- registration()->set_last_update_check(base::Time::Now());
- context_->storage()->UpdateLastUpdateCheckTime(registration());
- }
-
- ResolvePromise(SERVICE_WORKER_OK, std::string(), registration());
- Complete(status, "The updated worker is identical to the incumbent.");
- return;
- }
-
// "If serviceWorker fails to start up..." then reject the promise with an
// error and abort.
if (status == SERVICE_WORKER_ERROR_TIMEOUT) {
@@ -411,7 +402,10 @@ void ServiceWorkerRegisterJob::InstallAndContinue() {
registration()->NotifyUpdateFound();
// "Fire an event named install..."
- new_version()->DispatchInstallEvent(
+ new_version()->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::INSTALL,
+ base::Bind(&ServiceWorkerRegisterJob::DispatchInstallEvent,
+ weak_factory_.GetWeakPtr()),
base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished,
weak_factory_.GetWeakPtr()));
@@ -422,18 +416,32 @@ void ServiceWorkerRegisterJob::InstallAndContinue() {
Complete(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
}
+void ServiceWorkerRegisterJob::DispatchInstallEvent() {
+ DCHECK_EQ(ServiceWorkerVersion::INSTALLING, new_version()->status())
+ << new_version()->status();
+ DCHECK_EQ(ServiceWorkerVersion::RUNNING, new_version()->running_status())
+ << "Worker stopped too soon after it was started.";
+ int request_id = new_version()->StartRequest(
+ ServiceWorkerMetrics::EventType::INSTALL,
+ base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished,
+ weak_factory_.GetWeakPtr()));
+ new_version()->DispatchSimpleEvent<ServiceWorkerHostMsg_InstallEventFinished>(
+ request_id, ServiceWorkerMsg_InstallEvent(request_id));
+}
+
void ServiceWorkerRegisterJob::OnInstallFinished(
ServiceWorkerStatusCode status) {
ServiceWorkerMetrics::RecordInstallEventStatus(status);
if (status != SERVICE_WORKER_OK) {
// "8. If installFailed is true, then:..."
- Complete(status);
+ Complete(status, std::string("ServiceWorker failed to install: ") +
+ ServiceWorkerStatusToString(status));
return;
}
SetPhase(STORE);
- registration()->set_last_update_check(base::Time::Now());
+ DCHECK(!registration()->last_update_check().is_null());
context_->storage()->StoreRegistration(
registration(),
new_version(),
@@ -486,6 +494,12 @@ void ServiceWorkerRegisterJob::CompleteInternal(
ServiceWorkerStatusCode status,
const std::string& status_message) {
SetPhase(COMPLETE);
+
+ if (new_version()) {
+ new_version()->set_pause_after_download(false);
+ new_version()->embedded_worker()->RemoveListener(this);
+ }
+
if (status != SERVICE_WORKER_OK) {
if (registration()) {
if (should_uninstall_on_failure_)
@@ -514,7 +528,7 @@ void ServiceWorkerRegisterJob::CompleteInternal(
if (registration()) {
context_->storage()->NotifyDoneInstallingRegistration(
registration(), new_version(), status);
- if (registration()->waiting_version() || registration()->active_version())
+ if (registration()->has_installed_version())
registration()->set_is_uninstalled(false);
}
}
@@ -553,4 +567,41 @@ void ServiceWorkerRegisterJob::AddRegistrationToMatchingProviderHosts(
}
}
+void ServiceWorkerRegisterJob::OnScriptLoaded() {
+ DCHECK(new_version()->pause_after_download());
+ new_version()->set_pause_after_download(false);
+ net::URLRequestStatus status =
+ new_version()->script_cache_map()->main_script_status();
+ if (!status.is_success()) {
+ // OnScriptLoaded signifies a successful network load, which translates into
+ // a script cache error only in the byte-for-byte identical case.
+ DCHECK_EQ(status.error(),
+ ServiceWorkerWriteToCacheJob::kIdenticalScriptError);
+
+ BumpLastUpdateCheckTimeIfNeeded();
+ ResolvePromise(SERVICE_WORKER_OK, std::string(), registration());
+ Complete(SERVICE_WORKER_ERROR_EXISTS,
+ "The updated worker is identical to the incumbent.");
+ return;
+ }
+
+ new_version()->embedded_worker()->ResumeAfterDownload();
+}
+
+void ServiceWorkerRegisterJob::BumpLastUpdateCheckTimeIfNeeded() {
+ // Bump the last update check time only when the register/update job fetched
+ // the version having bypassed the network cache. We assume that the
+ // BYPASS_CACHE flag evicts an existing cache entry, so even if the install
+ // ultimately failed for whatever reason, we know the version in the HTTP
+ // cache is not stale, so it's OK to bump the update check time.
+ if (new_version()->embedded_worker()->network_accessed_for_script() ||
+ new_version()->force_bypass_cache_for_scripts() ||
+ registration()->last_update_check().is_null()) {
+ registration()->set_last_update_check(base::Time::Now());
+
+ if (registration()->has_installed_version())
+ context_->storage()->UpdateLastUpdateCheckTime(registration());
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_register_job.h b/chromium/content/browser/service_worker/service_worker_register_job.h
index 15033bcc455..66c7822d62d 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.h
+++ b/chromium/content/browser/service_worker/service_worker_register_job.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_
+#include <string>
#include <vector>
#include "base/macros.h"
@@ -34,7 +35,8 @@ class ServiceWorkerStorage;
// - waiting for older ServiceWorkerVersions to deactivate
// - designating the new version to be the 'active' version
// - updating storage
-class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
+class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
+ public EmbeddedWorkerInstance::Listener {
public:
typedef base::Callback<void(ServiceWorkerStatusCode status,
const std::string& status_message,
@@ -120,6 +122,7 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
void OnStartWorkerFinished(ServiceWorkerStatusCode status);
void OnStoreRegistrationComplete(ServiceWorkerStatusCode status);
void InstallAndContinue();
+ void DispatchInstallEvent();
void OnInstallFinished(ServiceWorkerStatusCode status);
void Complete(ServiceWorkerStatusCode status);
void Complete(ServiceWorkerStatusCode status,
@@ -133,6 +136,11 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
void AddRegistrationToMatchingProviderHosts(
ServiceWorkerRegistration* registration);
+ // EmbeddedWorkerInstance::Listener implementation:
+ void OnScriptLoaded() override;
+
+ void BumpLastUpdateCheckTimeIfNeeded();
+
// The ServiceWorkerContextCore object should always outlive this.
base::WeakPtr<ServiceWorkerContextCore> context_;
diff --git a/chromium/content/browser/service_worker/service_worker_registration.cc b/chromium/content/browser/service_worker/service_worker_registration.cc
index 6689ca4eb8f..90aa7ffed3c 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration.cc
@@ -10,6 +10,7 @@
#include "content/browser/service_worker/service_worker_info.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_register_job.h"
+#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
@@ -35,7 +36,6 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(
is_uninstalling_(false),
is_uninstalled_(false),
should_activate_when_ready_(false),
- force_update_on_page_load_(false),
resources_total_size_bytes_(0),
context_(context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -92,8 +92,6 @@ ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
pattern(), registration_id_,
is_deleted_ ? ServiceWorkerRegistrationInfo::IS_DELETED
: ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
- force_update_on_page_load_ ? ServiceWorkerRegistrationInfo::IS_FORCED
- : ServiceWorkerRegistrationInfo::IS_NOT_FORCED,
GetVersionInfo(active_version_.get()),
GetVersionInfo(waiting_version_.get()),
GetVersionInfo(installing_version_.get()), resources_total_size_bytes_);
@@ -285,9 +283,12 @@ void ServiceWorkerRegistration::ActivateWaitingVersion() {
FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
// "10. Queue a task to fire an event named activate..."
- activating_version->DispatchActivateEvent(
- base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
- this, activating_version));
+ activating_version->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::ACTIVATE,
+ base::Bind(&ServiceWorkerRegistration::DispatchActivateEvent, this,
+ activating_version),
+ base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this,
+ activating_version));
}
void ServiceWorkerRegistration::DeleteVersion(
@@ -338,8 +339,27 @@ void ServiceWorkerRegistration::RegisterRegistrationFinishedCallback(
registration_finished_callbacks_.push_back(callback);
}
+void ServiceWorkerRegistration::DispatchActivateEvent(
+ const scoped_refptr<ServiceWorkerVersion>& activating_version) {
+ if (activating_version != active_version()) {
+ OnActivateEventFinished(activating_version, SERVICE_WORKER_ERROR_FAILED);
+ return;
+ }
+
+ DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status());
+ DCHECK_EQ(ServiceWorkerVersion::RUNNING, activating_version->running_status())
+ << "Worker stopped too soon after it was started.";
+ int request_id = activating_version->StartRequest(
+ ServiceWorkerMetrics::EventType::ACTIVATE,
+ base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this,
+ activating_version));
+ activating_version
+ ->DispatchSimpleEvent<ServiceWorkerHostMsg_ActivateEventFinished>(
+ request_id, ServiceWorkerMsg_ActivateEvent(request_id));
+}
+
void ServiceWorkerRegistration::OnActivateEventFinished(
- ServiceWorkerVersion* activating_version,
+ const scoped_refptr<ServiceWorkerVersion>& activating_version,
ServiceWorkerStatusCode status) {
if (!context_ || activating_version != active_version() ||
activating_version->status() != ServiceWorkerVersion::ACTIVATING)
diff --git a/chromium/content/browser/service_worker/service_worker_registration.h b/chromium/content/browser/service_worker/service_worker_registration.h
index dab20434ce5..3450bcded8f 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.h
+++ b/chromium/content/browser/service_worker/service_worker_registration.h
@@ -86,6 +86,10 @@ class CONTENT_EXPORT ServiceWorkerRegistration
return installing_version_.get();
}
+ bool has_installed_version() const {
+ return active_version() || waiting_version();
+ }
+
ServiceWorkerVersion* GetNewestVersion() const;
void AddListener(Listener* listener);
@@ -138,11 +142,6 @@ class CONTENT_EXPORT ServiceWorkerRegistration
void RegisterRegistrationFinishedCallback(const base::Closure& callback);
void NotifyRegistrationFinished();
- bool force_update_on_page_load() const { return force_update_on_page_load_; }
- void set_force_update_on_page_load(bool force_update_on_page_load) {
- force_update_on_page_load_ = force_update_on_page_load;
- }
-
private:
friend class base::RefCounted<ServiceWorkerRegistration>;
@@ -157,8 +156,10 @@ class CONTENT_EXPORT ServiceWorkerRegistration
// This method corresponds to the [[Activate]] algorithm.
void ActivateWaitingVersion();
+ void DispatchActivateEvent(
+ const scoped_refptr<ServiceWorkerVersion>& activating_version);
void OnActivateEventFinished(
- ServiceWorkerVersion* activating_version,
+ const scoped_refptr<ServiceWorkerVersion>& activating_version,
ServiceWorkerStatusCode status);
void OnDeleteFinished(ServiceWorkerStatusCode status);
@@ -175,7 +176,6 @@ class CONTENT_EXPORT ServiceWorkerRegistration
bool is_uninstalling_;
bool is_uninstalled_;
bool should_activate_when_ready_;
- bool force_update_on_page_load_;
base::Time last_update_check_;
int64_t resources_total_size_bytes_;
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler.cc b/chromium/content/browser/service_worker/service_worker_request_handler.cc
index 05984a1a34b..f8190e2aa2f 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.cc
@@ -22,7 +22,7 @@
#include "content/public/common/child_process_host.h"
#include "content/public/common/origin_util.h"
#include "ipc/ipc_message.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_interceptor.h"
#include "storage/browser/blob/blob_storage_context.h"
@@ -232,6 +232,13 @@ void ServiceWorkerRequestHandler::MaybeCompleteCrossSiteTransferInOldProcess(
CompleteCrossSiteTransfer(old_process_id_, old_provider_id_);
}
+bool ServiceWorkerRequestHandler::SanityCheckIsSameContext(
+ ServiceWorkerContextWrapper* wrapper) {
+ if (!wrapper)
+ return !context_;
+ return context_.get() == wrapper->context();
+}
+
ServiceWorkerRequestHandler::~ServiceWorkerRequestHandler() {
}
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler.h b/chromium/content/browser/service_worker/service_worker_request_handler.h
index 9f9c7eb40cf..e75a993efcd 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REQUEST_HANDLER_H_
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "base/time/time.h"
@@ -30,6 +31,7 @@ class BlobStorageContext;
namespace content {
class ResourceContext;
+class ResourceMessageFilter;
class ResourceRequestBody;
class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper;
@@ -109,6 +111,10 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
void MaybeCompleteCrossSiteTransferInOldProcess(
int old_process_id);
+ // Useful for detecting storage partition mismatches in the context of cross
+ // site transfer navigations.
+ bool SanityCheckIsSameContext(ServiceWorkerContextWrapper* wrapper);
+
protected:
ServiceWorkerRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
diff --git a/chromium/content/browser/service_worker/service_worker_storage.cc b/chromium/content/browser/service_worker/service_worker_storage.cc
index fff872684d5..ddb1e647c0c 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage.cc
@@ -96,6 +96,9 @@ DidDeleteRegistrationParams::DidDeleteRegistrationParams()
: registration_id(kInvalidServiceWorkerRegistrationId) {
}
+ServiceWorkerStorage::DidDeleteRegistrationParams::DidDeleteRegistrationParams(
+ const DidDeleteRegistrationParams& other) = default;
+
ServiceWorkerStorage::
DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
}
@@ -338,7 +341,7 @@ void ServiceWorkerStorage::GetRegistrationsForOrigin(
if (state_ != INITIALIZING) {
RunSoon(
FROM_HERE,
- base::Bind(callback,
+ base::Bind(callback, SERVICE_WORKER_ERROR_ABORT,
std::vector<scoped_refptr<ServiceWorkerRegistration>>()));
}
return;
@@ -364,8 +367,9 @@ void ServiceWorkerStorage::GetAllRegistrationsInfos(
base::Bind(&ServiceWorkerStorage::GetAllRegistrationsInfos,
weak_factory_.GetWeakPtr(), callback))) {
if (state_ != INITIALIZING) {
- RunSoon(FROM_HERE, base::Bind(
- callback, std::vector<ServiceWorkerRegistrationInfo>()));
+ RunSoon(FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_ABORT,
+ std::vector<ServiceWorkerRegistrationInfo>()));
}
return;
}
@@ -403,6 +407,7 @@ void ServiceWorkerStorage::StoreRegistration(
data.last_update_check = registration->last_update_check();
data.is_active = (version == registration->active_version());
data.foreign_fetch_scopes = version->foreign_fetch_scopes();
+ data.foreign_fetch_origins = version->foreign_fetch_origins();
ResourceList resources;
version->script_cache_map()->GetResources(&resources);
@@ -462,7 +467,6 @@ void ServiceWorkerStorage::UpdateToActiveState(
void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
ServiceWorkerRegistration* registration) {
DCHECK(registration);
-
DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
if (IsDisabled())
return;
@@ -516,24 +520,26 @@ void ServiceWorkerStorage::DeleteRegistration(int64_t registration_id,
scoped_ptr<ServiceWorkerResponseReader>
ServiceWorkerStorage::CreateResponseReader(int64_t resource_id) {
return make_scoped_ptr(
- new ServiceWorkerResponseReader(resource_id, disk_cache()));
+ new ServiceWorkerResponseReader(resource_id, disk_cache()->GetWeakPtr()));
}
scoped_ptr<ServiceWorkerResponseWriter>
ServiceWorkerStorage::CreateResponseWriter(int64_t resource_id) {
return make_scoped_ptr(
- new ServiceWorkerResponseWriter(resource_id, disk_cache()));
+ new ServiceWorkerResponseWriter(resource_id, disk_cache()->GetWeakPtr()));
}
scoped_ptr<ServiceWorkerResponseMetadataWriter>
ServiceWorkerStorage::CreateResponseMetadataWriter(int64_t resource_id) {
- return make_scoped_ptr(
- new ServiceWorkerResponseMetadataWriter(resource_id, disk_cache()));
+ return make_scoped_ptr(new ServiceWorkerResponseMetadataWriter(
+ resource_id, disk_cache()->GetWeakPtr()));
}
void ServiceWorkerStorage::StoreUncommittedResourceId(int64_t resource_id) {
DCHECK_NE(kInvalidServiceWorkerResourceId, resource_id);
- DCHECK_EQ(INITIALIZED, state_);
+ DCHECK(INITIALIZED == state_ || DISABLED == state_) << state_;
+ if (IsDisabled())
+ return;
if (!has_checked_for_stale_resources_)
DeleteStaleResources();
@@ -549,11 +555,18 @@ void ServiceWorkerStorage::StoreUncommittedResourceId(int64_t resource_id) {
void ServiceWorkerStorage::DoomUncommittedResource(int64_t resource_id) {
DCHECK_NE(kInvalidServiceWorkerResourceId, resource_id);
+ DCHECK(INITIALIZED == state_ || DISABLED == state_) << state_;
+ if (IsDisabled())
+ return;
DoomUncommittedResources(std::set<int64_t>(&resource_id, &resource_id + 1));
}
void ServiceWorkerStorage::DoomUncommittedResources(
const std::set<int64_t>& resource_ids) {
+ DCHECK(INITIALIZED == state_ || DISABLED == state_) << state_;
+ if (IsDisabled())
+ return;
+
PostTaskAndReplyWithResult(
database_task_manager_->GetTaskRunner(), FROM_HERE,
base::Bind(&ServiceWorkerDatabase::PurgeUncommittedResourceIds,
@@ -758,10 +771,6 @@ void ServiceWorkerStorage::Disable() {
disk_cache_->Disable();
}
-bool ServiceWorkerStorage::IsDisabled() const {
- return state_ == DISABLED;
-}
-
void ServiceWorkerStorage::PurgeResources(const ResourceList& resources) {
if (!has_checked_for_stale_resources_)
DeleteStaleResources();
@@ -971,7 +980,8 @@ void ServiceWorkerStorage::DidGetRegistrations(
if (status != ServiceWorkerDatabase::STATUS_OK &&
status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
ScheduleDeleteAndStartOver();
- callback.Run(std::vector<scoped_refptr<ServiceWorkerRegistration>>());
+ callback.Run(DatabaseStatusToStatusCode(status),
+ std::vector<scoped_refptr<ServiceWorkerRegistration>>());
return;
}
@@ -994,7 +1004,7 @@ void ServiceWorkerStorage::DidGetRegistrations(
}
}
- callback.Run(registrations);
+ callback.Run(SERVICE_WORKER_OK, registrations);
}
void ServiceWorkerStorage::DidGetRegistrationsInfos(
@@ -1006,7 +1016,8 @@ void ServiceWorkerStorage::DidGetRegistrationsInfos(
if (status != ServiceWorkerDatabase::STATUS_OK &&
status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
ScheduleDeleteAndStartOver();
- callback.Run(std::vector<ServiceWorkerRegistrationInfo>());
+ callback.Run(DatabaseStatusToStatusCode(status),
+ std::vector<ServiceWorkerRegistrationInfo>());
return;
}
@@ -1063,7 +1074,7 @@ void ServiceWorkerStorage::DidGetRegistrationsInfos(
}
}
- callback.Run(infos);
+ callback.Run(SERVICE_WORKER_OK, infos);
}
void ServiceWorkerStorage::DidStoreRegistration(
@@ -1228,6 +1239,7 @@ ServiceWorkerStorage::GetOrCreateRegistration(
ServiceWorkerVersion::ACTIVATED : ServiceWorkerVersion::INSTALLED);
version->script_cache_map()->SetResources(resources);
version->set_foreign_fetch_scopes(data.foreign_fetch_scopes);
+ version->set_foreign_fetch_origins(data.foreign_fetch_origins);
}
if (version->status() == ServiceWorkerVersion::ACTIVATED)
@@ -1274,12 +1286,16 @@ ServiceWorkerStorage::FindInstallingRegistrationForId(int64_t registration_id) {
}
ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
- DCHECK_EQ(INITIALIZED, state_);
+ DCHECK(INITIALIZED == state_ || DISABLED == state_) << state_;
if (disk_cache_)
return disk_cache_.get();
-
disk_cache_.reset(new ServiceWorkerDiskCache);
+ if (IsDisabled()) {
+ disk_cache_->Disable();
+ return disk_cache_.get();
+ }
+
base::FilePath path = GetDiskCachePath();
if (path.empty()) {
int rv = disk_cache_->InitWithMemBackend(kMaxMemDiskCacheSize,
@@ -1687,6 +1703,10 @@ void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB(
database->DeleteAllDataForOrigins(origins, &newly_purgeable_resources);
}
+bool ServiceWorkerStorage::IsDisabled() const {
+ return state_ == DISABLED;
+}
+
// TODO(nhiroki): The corruption recovery should not be scheduled if the error
// is transient and it can get healed soon (e.g. IO error). To do that, the
// database should not disable itself when an error occurs and the storage
diff --git a/chromium/content/browser/service_worker/service_worker_storage.h b/chromium/content/browser/service_worker/service_worker_storage.h
index 92042def120..c4dbe08cd76 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.h
+++ b/chromium/content/browser/service_worker/service_worker_storage.h
@@ -48,7 +48,9 @@ struct ServiceWorkerRegistrationInfo;
// This class provides an interface to store and retrieve ServiceWorker
// registration data. The lifetime is equal to ServiceWorkerContextCore that is
-// an owner of this class.
+// an owner of this class. When a storage operation fails, this is marked as
+// disabled and all subsequent requests are aborted until the context core is
+// restarted.
class CONTENT_EXPORT ServiceWorkerStorage
: NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
@@ -58,10 +60,14 @@ class CONTENT_EXPORT ServiceWorkerStorage
const scoped_refptr<ServiceWorkerRegistration>&
registration)> FindRegistrationCallback;
typedef base::Callback<void(
+ ServiceWorkerStatusCode status,
const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
- registrations)> GetRegistrationsCallback;
- typedef base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&
- registrations)> GetRegistrationsInfosCallback;
+ registrations)>
+ GetRegistrationsCallback;
+ typedef base::Callback<void(
+ ServiceWorkerStatusCode status,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations)>
+ GetRegistrationsInfosCallback;
typedef base::Callback<
void(const std::string& data, ServiceWorkerStatusCode status)>
GetUserDataCallback;
@@ -142,6 +148,8 @@ class CONTENT_EXPORT ServiceWorkerStorage
const GURL& origin,
const StatusCallback& callback);
+ // Creates a resource accessor. Never returns nullptr but an accessor may be
+ // associated with the disabled disk cache if the storage is disabled.
scoped_ptr<ServiceWorkerResponseReader> CreateResponseReader(
int64_t resource_id);
scoped_ptr<ServiceWorkerResponseWriter> CreateResponseWriter(
@@ -211,12 +219,12 @@ class CONTENT_EXPORT ServiceWorkerStorage
ServiceWorkerRegistration* registration);
void Disable();
- bool IsDisabled() const;
// |resources| must already be on the purgeable list.
void PurgeResources(const ResourceList& resources);
private:
+ friend class ServiceWorkerDispatcherHostTest;
friend class ServiceWorkerHandleTest;
friend class ServiceWorkerStorageTest;
friend class ServiceWorkerResourceStorageTest;
@@ -267,6 +275,7 @@ class CONTENT_EXPORT ServiceWorkerStorage
StatusCallback callback;
DidDeleteRegistrationParams();
+ DidDeleteRegistrationParams(const DidDeleteRegistrationParams& other);
~DidDeleteRegistrationParams();
};
@@ -481,6 +490,7 @@ class CONTENT_EXPORT ServiceWorkerStorage
ServiceWorkerDatabase* database,
const std::set<GURL>& origins);
+ bool IsDisabled() const;
void ScheduleDeleteAndStartOver();
void DidDeleteDatabase(
const StatusCallback& callback,
diff --git a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
index 6b757161d2f..a2a88ef0bd8 100644
--- a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -82,31 +82,39 @@ ServiceWorkerStorage::FindRegistrationCallback MakeFindCallback(
void GetAllCallback(
bool* was_called,
+ ServiceWorkerStatusCode* result,
std::vector<scoped_refptr<ServiceWorkerRegistration>>* all_out,
+ ServiceWorkerStatusCode status,
const std::vector<scoped_refptr<ServiceWorkerRegistration>>& all) {
*was_called = true;
+ *result = status;
*all_out = all;
}
void GetAllInfosCallback(
bool* was_called,
+ ServiceWorkerStatusCode* result,
std::vector<ServiceWorkerRegistrationInfo>* all_out,
+ ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& all) {
*was_called = true;
+ *result = status;
*all_out = all;
}
ServiceWorkerStorage::GetRegistrationsCallback MakeGetRegistrationsCallback(
bool* was_called,
+ ServiceWorkerStatusCode* status,
std::vector<scoped_refptr<ServiceWorkerRegistration>>* all) {
- return base::Bind(&GetAllCallback, was_called, all);
+ return base::Bind(&GetAllCallback, was_called, status, all);
}
ServiceWorkerStorage::GetRegistrationsInfosCallback
MakeGetRegistrationsInfosCallback(
bool* was_called,
+ ServiceWorkerStatusCode* status,
std::vector<ServiceWorkerRegistrationInfo>* all) {
- return base::Bind(&GetAllInfosCallback, was_called, all);
+ return base::Bind(&GetAllInfosCallback, was_called, status, all);
}
void GetUserDataCallback(
@@ -131,11 +139,11 @@ void GetUserDataForAllRegistrationsCallback(
*status_out = status;
}
-void WriteResponse(ServiceWorkerStorage* storage,
- int64_t id,
- const std::string& headers,
- IOBuffer* body,
- int length) {
+int WriteResponse(ServiceWorkerStorage* storage,
+ int64_t id,
+ const std::string& headers,
+ IOBuffer* body,
+ int length) {
scoped_ptr<ServiceWorkerResponseWriter> writer =
storage->CreateResponseWriter(id);
@@ -146,36 +154,45 @@ void WriteResponse(ServiceWorkerStorage* storage,
info->headers = new net::HttpResponseHeaders(headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer(info.release());
+ int rv = 0;
{
TestCompletionCallback cb;
writer->WriteInfo(info_buffer.get(), cb.callback());
- int rv = cb.WaitForResult();
- EXPECT_LT(0, rv);
+ rv = cb.WaitForResult();
+ if (rv < 0)
+ return rv;
}
{
TestCompletionCallback cb;
writer->WriteData(body, length, cb.callback());
- int rv = cb.WaitForResult();
- EXPECT_EQ(length, rv);
+ rv = cb.WaitForResult();
}
+ return rv;
}
-void WriteStringResponse(ServiceWorkerStorage* storage,
- int64_t id,
- const std::string& headers,
- const std::string& body) {
+int WriteStringResponse(ServiceWorkerStorage* storage,
+ int64_t id,
+ const std::string& headers,
+ const std::string& body) {
scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(body.data()));
- WriteResponse(storage, id, headers, body_buffer.get(), body.length());
+ return WriteResponse(storage, id, headers, body_buffer.get(), body.length());
}
-void WriteBasicResponse(ServiceWorkerStorage* storage, int64_t id) {
- scoped_ptr<ServiceWorkerResponseWriter> writer =
- storage->CreateResponseWriter(id);
-
+int WriteBasicResponse(ServiceWorkerStorage* storage, int64_t id) {
const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0Content-Length: 5\0\0";
const char kHttpBody[] = "Hello";
std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
- WriteStringResponse(storage, id, headers, std::string(kHttpBody));
+ return WriteStringResponse(storage, id, headers, std::string(kHttpBody));
+}
+
+int ReadResponseInfo(ServiceWorkerStorage* storage,
+ int64_t id,
+ HttpResponseInfoIOBuffer* info_buffer) {
+ scoped_ptr<ServiceWorkerResponseReader> reader =
+ storage->CreateResponseReader(id);
+ TestCompletionCallback cb;
+ reader->ReadInfo(info_buffer, cb.callback());
+ return cb.WaitForResult();
}
bool VerifyBasicResponse(ServiceWorkerStorage* storage,
@@ -186,28 +203,22 @@ bool VerifyBasicResponse(ServiceWorkerStorage* storage,
storage->CreateResponseReader(id);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer();
- {
- TestCompletionCallback cb;
- reader->ReadInfo(info_buffer.get(), cb.callback());
- int rv = cb.WaitForResult();
- if (expected_positive_result)
- EXPECT_LT(0, rv);
- if (rv <= 0)
- return false;
- }
+ int rv = ReadResponseInfo(storage, id, info_buffer.get());
+ if (expected_positive_result)
+ EXPECT_LT(0, rv);
+ if (rv <= 0)
+ return false;
std::string received_body;
- {
- const int kBigEnough = 512;
- scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough);
- TestCompletionCallback cb;
- reader->ReadData(buffer.get(), kBigEnough, cb.callback());
- int rv = cb.WaitForResult();
- EXPECT_EQ(static_cast<int>(kExpectedHttpBody.size()), rv);
- if (rv <= 0)
- return false;
- received_body.assign(buffer->data(), rv);
- }
+ const int kBigEnough = 512;
+ scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough);
+ TestCompletionCallback cb;
+ reader->ReadData(buffer.get(), kBigEnough, cb.callback());
+ rv = cb.WaitForResult();
+ EXPECT_EQ(static_cast<int>(kExpectedHttpBody.size()), rv);
+ if (rv <= 0)
+ return false;
+ received_body.assign(buffer->data(), rv);
bool status_match =
std::string("HONKYDORY") ==
@@ -321,7 +332,7 @@ class ServiceWorkerStorageTest : public testing::Test {
scoped_refptr<ServiceWorkerRegistration> registration,
scoped_refptr<ServiceWorkerVersion> version) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->StoreRegistration(registration.get(),
version.get(),
MakeStatusCallback(&was_called, &result));
@@ -334,7 +345,7 @@ class ServiceWorkerStorageTest : public testing::Test {
ServiceWorkerStatusCode DeleteRegistration(int64_t registration_id,
const GURL& origin) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->DeleteRegistration(
registration_id, origin, MakeStatusCallback(&was_called, &result));
EXPECT_FALSE(was_called); // always async
@@ -343,32 +354,37 @@ class ServiceWorkerStorageTest : public testing::Test {
return result;
}
- void GetAllRegistrationsInfos(
+ ServiceWorkerStatusCode GetAllRegistrationsInfos(
std::vector<ServiceWorkerRegistrationInfo>* registrations) {
bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->GetAllRegistrationsInfos(
- MakeGetRegistrationsInfosCallback(&was_called, registrations));
+ MakeGetRegistrationsInfosCallback(&was_called, &result, registrations));
EXPECT_FALSE(was_called); // always async
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
+ return result;
}
- void GetRegistrationsForOrigin(
+ ServiceWorkerStatusCode GetRegistrationsForOrigin(
const GURL& origin,
std::vector<scoped_refptr<ServiceWorkerRegistration>>* registrations) {
bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->GetRegistrationsForOrigin(
- origin, MakeGetRegistrationsCallback(&was_called, registrations));
+ origin,
+ MakeGetRegistrationsCallback(&was_called, &result, registrations));
EXPECT_FALSE(was_called); // always async
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
+ return result;
}
ServiceWorkerStatusCode GetUserData(int64_t registration_id,
const std::string& key,
std::string* data) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->GetUserData(
registration_id, key,
base::Bind(&GetUserDataCallback, &was_called, data, &result));
@@ -383,7 +399,7 @@ class ServiceWorkerStorageTest : public testing::Test {
const std::string& key,
const std::string& data) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->StoreUserData(
registration_id, origin, key, data,
MakeStatusCallback(&was_called, &result));
@@ -396,7 +412,7 @@ class ServiceWorkerStorageTest : public testing::Test {
ServiceWorkerStatusCode ClearUserData(int64_t registration_id,
const std::string& key) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->ClearUserData(
registration_id, key, MakeStatusCallback(&was_called, &result));
EXPECT_FALSE(was_called); // always async
@@ -409,7 +425,7 @@ class ServiceWorkerStorageTest : public testing::Test {
const std::string& key,
std::vector<std::pair<int64_t, std::string>>* data) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->GetUserDataForAllRegistrations(
key, base::Bind(&GetUserDataForAllRegistrationsCallback, &was_called,
data, &result));
@@ -420,9 +436,9 @@ class ServiceWorkerStorageTest : public testing::Test {
}
ServiceWorkerStatusCode UpdateToActiveState(
- scoped_refptr<ServiceWorkerRegistration> registration) {
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->UpdateToActiveState(registration.get(),
MakeStatusCallback(&was_called, &result));
EXPECT_FALSE(was_called); // always async
@@ -431,8 +447,9 @@ class ServiceWorkerStorageTest : public testing::Test {
return result;
}
- void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) {
- storage()->UpdateLastUpdateCheckTime(registration);
+ void UpdateLastUpdateCheckTime(
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ storage()->UpdateLastUpdateCheckTime(registration.get());
base::RunLoop().RunUntilIdle();
}
@@ -440,7 +457,7 @@ class ServiceWorkerStorageTest : public testing::Test {
const GURL& document_url,
scoped_refptr<ServiceWorkerRegistration>* registration) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->FindRegistrationForDocument(
document_url, MakeFindCallback(&was_called, &result, registration));
base::RunLoop().RunUntilIdle();
@@ -452,7 +469,7 @@ class ServiceWorkerStorageTest : public testing::Test {
const GURL& scope,
scoped_refptr<ServiceWorkerRegistration>* registration) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->FindRegistrationForPattern(
scope, MakeFindCallback(&was_called, &result, registration));
EXPECT_FALSE(was_called); // always async
@@ -466,7 +483,7 @@ class ServiceWorkerStorageTest : public testing::Test {
const GURL& origin,
scoped_refptr<ServiceWorkerRegistration>* registration) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->FindRegistrationForId(
registration_id, origin,
MakeFindCallback(&was_called, &result, registration));
@@ -479,7 +496,7 @@ class ServiceWorkerStorageTest : public testing::Test {
int64_t registration_id,
scoped_refptr<ServiceWorkerRegistration>* registration) {
bool was_called = false;
- ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->FindRegistrationForIdOnly(
registration_id, MakeFindCallback(&was_called, &result, registration));
base::RunLoop().RunUntilIdle();
@@ -493,6 +510,84 @@ class ServiceWorkerStorageTest : public testing::Test {
TestBrowserThreadBundle browser_thread_bundle_;
};
+TEST_F(ServiceWorkerStorageTest, DisabledStorage) {
+ const GURL kScope("http://www.example.com/scope/");
+ const GURL kScript("http://www.example.com/script.js");
+ const GURL kDocumentUrl("http://www.example.com/scope/document.html");
+ const int64_t kRegistrationId = 0;
+ const int64_t kVersionId = 0;
+ const int64_t kResourceId = 0;
+
+ LazyInitialize();
+ storage()->Disable();
+
+ scoped_refptr<ServiceWorkerRegistration> found_registration;
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ FindRegistrationForDocument(kDocumentUrl, &found_registration));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ FindRegistrationForPattern(kScope, &found_registration));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ FindRegistrationForId(kRegistrationId, kScope.GetOrigin(),
+ &found_registration));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ FindRegistrationForIdOnly(kRegistrationId, &found_registration));
+ EXPECT_FALSE(storage()->GetUninstallingRegistration(kScope.GetOrigin()));
+
+ std::vector<scoped_refptr<ServiceWorkerRegistration>> found_registrations;
+ EXPECT_EQ(
+ SERVICE_WORKER_ERROR_ABORT,
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &found_registrations));
+
+ std::vector<ServiceWorkerRegistrationInfo> all_registrations;
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ GetAllRegistrationsInfos(&all_registrations));
+
+ scoped_refptr<ServiceWorkerRegistration> live_registration =
+ new ServiceWorkerRegistration(kScope, kRegistrationId,
+ context()->AsWeakPtr());
+ scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
+ live_registration.get(), kScript, kVersionId, context()->AsWeakPtr());
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ StoreRegistration(live_registration, live_version));
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, UpdateToActiveState(live_registration));
+
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ DeleteRegistration(kRegistrationId, kScope.GetOrigin()));
+
+ // Response reader and writer created by the disabled storage should fail to
+ // access the disk cache.
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
+ new HttpResponseInfoIOBuffer();
+ EXPECT_EQ(net::ERR_CACHE_MISS,
+ ReadResponseInfo(storage(), kResourceId, info_buffer.get()));
+ EXPECT_EQ(net::ERR_FAILED, WriteBasicResponse(storage(), kResourceId));
+ EXPECT_EQ(net::ERR_FAILED,
+ WriteResponseMetadata(storage(), kResourceId, "foo"));
+
+ const std::string kUserDataKey = "key";
+ std::string user_data_out;
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ GetUserData(kRegistrationId, kUserDataKey, &user_data_out));
+ EXPECT_EQ(
+ SERVICE_WORKER_ERROR_ABORT,
+ StoreUserData(kRegistrationId, kScope.GetOrigin(), kUserDataKey, "foo"));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ ClearUserData(kRegistrationId, kUserDataKey));
+ std::vector<std::pair<int64_t, std::string>> data_list_out;
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT,
+ GetUserDataForAllRegistrations(kUserDataKey, &data_list_out));
+
+ EXPECT_FALSE(
+ storage()->OriginHasForeignFetchRegistrations(kScope.GetOrigin()));
+
+ // Next available ids should be invalid.
+ EXPECT_EQ(kInvalidServiceWorkerRegistrationId,
+ storage()->NewRegistrationId());
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, storage()->NewVersionId());
+ EXPECT_EQ(kInvalidServiceWorkerResourceId, storage()->NewRegistrationId());
+}
+
TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
const GURL kScope("http://www.test.not/scope/");
const GURL kScript("http://www.test.not/script.js");
@@ -504,6 +599,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
const int64_t kRegistrationId = 0;
const int64_t kVersionId = 0;
const GURL kForeignFetchScope("http://www.test.not/scope/ff/");
+ const url::Origin kForeignFetchOrigin(GURL("https://example.com/"));
const base::Time kToday = base::Time::Now();
const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
@@ -539,6 +635,8 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
live_version->script_cache_map()->SetResources(resources);
live_version->set_foreign_fetch_scopes(
std::vector<GURL>(1, kForeignFetchScope));
+ live_version->set_foreign_fetch_origins(
+ std::vector<url::Origin>(1, kForeignFetchOrigin));
live_registration->SetWaitingVersion(live_version);
live_registration->set_last_update_check(kYesterday);
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -592,7 +690,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(kResource1Size + kResource2Size,
found_registration->resources_total_size_bytes());
std::vector<ServiceWorkerRegistrationInfo> all_registrations;
- GetAllRegistrationsInfos(&all_registrations);
+ EXPECT_EQ(SERVICE_WORKER_OK, GetAllRegistrationsInfos(&all_registrations));
EXPECT_EQ(1u, all_registrations.size());
ServiceWorkerRegistrationInfo info = all_registrations[0];
EXPECT_EQ(kResource1Size + kResource2Size, info.stored_version_size_bytes);
@@ -601,12 +699,15 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
// Finding by origin should provide the same result if origin is kScope.
std::vector<scoped_refptr<ServiceWorkerRegistration>>
registrations_for_origin;
- GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+ EXPECT_EQ(
+ SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin));
EXPECT_EQ(1u, registrations_for_origin.size());
registrations_for_origin.clear();
- GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
- &registrations_for_origin);
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+ &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
found_registration = NULL;
@@ -629,6 +730,11 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
1u, found_registration->waiting_version()->foreign_fetch_scopes().size());
EXPECT_EQ(kForeignFetchScope,
found_registration->waiting_version()->foreign_fetch_scopes()[0]);
+ EXPECT_EQ(
+ 1u,
+ found_registration->waiting_version()->foreign_fetch_origins().size());
+ EXPECT_EQ(kForeignFetchOrigin,
+ found_registration->waiting_version()->foreign_fetch_origins()[0]);
// Update to active and update the last check time.
scoped_refptr<ServiceWorkerVersion> temp_version =
@@ -720,16 +826,19 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
EXPECT_FALSE(found_registration.get());
std::vector<ServiceWorkerRegistrationInfo> all_registrations;
- GetAllRegistrationsInfos(&all_registrations);
+ EXPECT_EQ(SERVICE_WORKER_OK, GetAllRegistrationsInfos(&all_registrations));
EXPECT_TRUE(all_registrations.empty());
std::vector<scoped_refptr<ServiceWorkerRegistration>>
registrations_for_origin;
- GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+ EXPECT_EQ(
+ SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
- GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
- &registrations_for_origin);
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+ &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
// Notify storage of it being installed.
@@ -757,17 +866,20 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
EXPECT_EQ(live_registration, found_registration);
found_registration = NULL;
- GetAllRegistrationsInfos(&all_registrations);
+ EXPECT_EQ(SERVICE_WORKER_OK, GetAllRegistrationsInfos(&all_registrations));
EXPECT_EQ(1u, all_registrations.size());
all_registrations.clear();
// Finding by origin should provide the same result if origin is kScope.
- GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+ EXPECT_EQ(
+ SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin));
EXPECT_EQ(1u, registrations_for_origin.size());
registrations_for_origin.clear();
- GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
- &registrations_for_origin);
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+ &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
// Notify storage of installation no longer happening.
@@ -792,14 +904,17 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
FindRegistrationForPattern(kScope, &found_registration));
EXPECT_FALSE(found_registration.get());
- GetAllRegistrationsInfos(&all_registrations);
+ EXPECT_EQ(SERVICE_WORKER_OK, GetAllRegistrationsInfos(&all_registrations));
EXPECT_TRUE(all_registrations.empty());
- GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+ EXPECT_EQ(
+ SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
- GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
- &registrations_for_origin);
+ EXPECT_EQ(SERVICE_WORKER_OK,
+ GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+ &registrations_for_origin));
EXPECT_TRUE(registrations_for_origin.empty());
}
@@ -1241,7 +1356,7 @@ TEST_F(ServiceWorkerResourceStorageDiskTest, DeleteAndStartOver) {
ASSERT_TRUE(base::DirectoryExists(storage()->GetDatabasePath()));
base::RunLoop run_loop;
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->DeleteAndStartOver(
base::Bind(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
run_loop.Run();
@@ -1266,7 +1381,7 @@ TEST_F(ServiceWorkerResourceStorageDiskTest,
ASSERT_TRUE(base::PathExists(file_path));
base::RunLoop run_loop;
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->DeleteAndStartOver(
base::Bind(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
run_loop.Run();
@@ -1292,7 +1407,7 @@ TEST_F(ServiceWorkerResourceStorageDiskTest,
ASSERT_TRUE(base::PathExists(file_path));
base::RunLoop run_loop;
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
storage()->DeleteAndStartOver(
base::Bind(&StatusAndQuitCallback, &status, run_loop.QuitClosure()));
run_loop.Run();
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.cc b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
index 44fab7f581a..47128f0c5c1 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
@@ -28,6 +28,7 @@
#include "content/browser/streams/stream_registry.h"
#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/blob_handle.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/service_worker_context.h"
@@ -115,10 +116,11 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
FetchRedirectMode redirect_mode,
- bool is_main_resource_load,
+ ResourceType resource_type,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBody> body,
+ ServiceWorkerFetchType fetch_type,
Delegate* delegate)
: net::URLRequestJob(request, network_delegate),
delegate_(delegate),
@@ -132,11 +134,12 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
request_mode_(request_mode),
credentials_mode_(credentials_mode),
redirect_mode_(redirect_mode),
- is_main_resource_load_(is_main_resource_load),
+ resource_type_(resource_type),
request_context_type_(request_context_type),
frame_type_(frame_type),
fall_back_required_(false),
body_(body),
+ fetch_type_(fetch_type),
weak_factory_(this) {
DCHECK(delegate_) << "ServiceWorkerURLRequestJob requires a delegate";
}
@@ -308,7 +311,8 @@ void ServiceWorkerURLRequestJob::OnBeforeNetworkStart(net::URLRequest* request,
void ServiceWorkerURLRequestJob::OnResponseStarted(net::URLRequest* request) {
// TODO(falken): Add Content-Length, Content-Type if they were not provided in
// the ServiceWorkerResponse.
- response_time_ = base::Time::Now();
+ if (response_time_.is_null())
+ response_time_ = base::Time::Now();
CommitResponseHeader();
}
@@ -429,7 +433,7 @@ void ServiceWorkerURLRequestJob::StartRequest() {
// Send a fetch event to the ServiceWorker associated to the
// provider_host.
fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
- CreateFetchRequest(), active_worker,
+ CreateFetchRequest(), active_worker, resource_type_,
base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent,
weak_factory_.GetWeakPtr()),
base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent,
@@ -446,11 +450,13 @@ scoped_ptr<ServiceWorkerFetchRequest>
ServiceWorkerURLRequestJob::CreateFetchRequest() {
std::string blob_uuid;
uint64_t blob_size = 0;
- CreateRequestBodyBlob(&blob_uuid, &blob_size);
+ // The upload data in URLRequest may have been cleared while handing redirect.
+ if (request_->has_upload())
+ CreateRequestBodyBlob(&blob_uuid, &blob_size);
scoped_ptr<ServiceWorkerFetchRequest> request(
new ServiceWorkerFetchRequest());
request->mode = request_mode_;
- request->is_main_resource_load = is_main_resource_load_;
+ request->is_main_resource_load = IsMainResourceLoad();
request->request_context_type = request_context_type_;
request->frame_type = frame_type_;
request->url = request_->url();
@@ -479,6 +485,7 @@ ServiceWorkerURLRequestJob::CreateFetchRequest() {
request->referrer =
Referrer(GURL(request_->referrer()), blink::WebReferrerPolicyDefault);
}
+ request->fetch_type = fetch_type_;
return request;
}
@@ -562,9 +569,9 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response,
- scoped_refptr<ServiceWorkerVersion> version) {
+ const scoped_refptr<ServiceWorkerVersion>& version) {
fetch_dispatcher_.reset();
- ServiceWorkerMetrics::RecordFetchEventStatus(is_main_resource_load_, status);
+ ServiceWorkerMetrics::RecordFetchEventStatus(IsMainResourceLoad(), status);
// Check if we're not orphaned.
if (!request()) {
@@ -582,7 +589,7 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
if (status != SERVICE_WORKER_OK) {
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_FETCH_EVENT_DISPATCH);
- if (is_main_resource_load_) {
+ if (IsMainResourceLoad()) {
// Using the service worker failed, so fallback to network.
delegate_->MainResourceLoadFailed();
response_type_ = FALLBACK_TO_NETWORK;
@@ -602,7 +609,8 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
// we returns a fall_back_required response to the renderer.
if ((request_mode_ == FETCH_REQUEST_MODE_CORS ||
request_mode_ == FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT) &&
- delegate_->GetRequestingOrigin() != request()->url().GetOrigin()) {
+ !request()->initiator().IsSameOriginWith(
+ url::Origin(request()->url()))) {
fall_back_required_ = true;
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_FOR_CORS);
CreateResponseHeader(
@@ -657,6 +665,7 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
streaming_version_->AddStreamingURLRequestJob(this);
response_url_ = response.url;
service_worker_response_type_ = response.response_type;
+ response_time_ = response.response_time;
CreateResponseHeader(
response.status_code, response.status_text, response.headers);
load_timing_info_.receive_headers_end = base::TimeTicks::Now();
@@ -694,6 +703,9 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
response_url_ = response.url;
service_worker_response_type_ = response.response_type;
+ response_time_ = response.response_time;
+ response_is_in_cache_storage_ = response.is_in_cache_storage;
+ response_cache_storage_cache_name_ = response.cache_storage_cache_name;
CreateResponseHeader(
response.status_code, response.status_text, response.headers);
load_timing_info_.receive_headers_end = base::TimeTicks::Now();
@@ -762,8 +774,7 @@ void ServiceWorkerURLRequestJob::RecordResult(
return;
}
did_record_result_ = true;
- ServiceWorkerMetrics::RecordURLRequestJobResult(is_main_resource_load_,
- result);
+ ServiceWorkerMetrics::RecordURLRequestJobResult(IsMainResourceLoad(), result);
if (request())
request()->net_log().AddEvent(RequestJobResultToNetEventType(result));
}
@@ -777,7 +788,7 @@ void ServiceWorkerURLRequestJob::RecordStatusZeroResponseError(
return;
}
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_RESPONSE_STATUS_ZERO);
- ServiceWorkerMetrics::RecordStatusZeroResponseError(is_main_resource_load_,
+ ServiceWorkerMetrics::RecordStatusZeroResponseError(IsMainResourceLoad(),
error);
}
@@ -823,13 +834,20 @@ void ServiceWorkerURLRequestJob::OnStartCompleted() const {
GURL() /* original_url_via_service_worker */,
blink::WebServiceWorkerResponseTypeDefault,
base::TimeTicks() /* service_worker_start_time */,
- base::TimeTicks() /* service_worker_ready_time */);
+ base::TimeTicks() /* service_worker_ready_time */,
+ false /* respons_is_in_cache_storage */,
+ std::string() /* response_cache_storage_cache_name */);
return;
}
delegate_->OnStartCompleted(true /* was_fetched_via_service_worker */,
fall_back_required_, response_url_,
service_worker_response_type_, worker_start_time_,
- worker_ready_time_);
+ worker_ready_time_, response_is_in_cache_storage_,
+ response_cache_storage_cache_name_);
+}
+
+bool ServiceWorkerURLRequestJob::IsMainResourceLoad() const {
+ return ServiceWorkerUtils::IsMainResourceType(resource_type_);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.h b/chromium/content/browser/service_worker/service_worker_url_request_job.h
index 8f9946d4547..9c4101f5d3d 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job.h
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job.h
@@ -75,7 +75,9 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks worker_start_time,
- base::TimeTicks service_worker_ready_time) = 0;
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) = 0;
// Returns the ServiceWorkerVersion fetch events for this request job should
// be dispatched to. If no appropriate worker can be determined, returns
@@ -92,9 +94,6 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// Called to signal that loading failed, and that the resource being loaded
// was a main resource.
virtual void MainResourceLoadFailed() {}
-
- // Returns the origin of the page/context which initiated this request.
- virtual GURL GetRequestingOrigin() = 0;
};
ServiceWorkerURLRequestJob(
@@ -106,10 +105,11 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
FetchRedirectMode redirect_mode,
- bool is_main_resource_load,
+ ResourceType resource_type,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
scoped_refptr<ResourceRequestBody> body,
+ ServiceWorkerFetchType fetch_type,
Delegate* delegate);
~ServiceWorkerURLRequestJob() override;
@@ -190,10 +190,11 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// For FORWARD_TO_SERVICE_WORKER case.
void DidPrepareFetchEvent();
- void DidDispatchFetchEvent(ServiceWorkerStatusCode status,
- ServiceWorkerFetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
- scoped_refptr<ServiceWorkerVersion> version);
+ void DidDispatchFetchEvent(
+ ServiceWorkerStatusCode status,
+ ServiceWorkerFetchEventResult fetch_result,
+ const ServiceWorkerResponse& response,
+ const scoped_refptr<ServiceWorkerVersion>& version);
// Populates |http_response_headers_|.
void CreateResponseHeader(int status_code,
@@ -228,6 +229,8 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// calls it.
void OnStartCompleted() const;
+ bool IsMainResourceLoad() const;
+
// Not owned.
Delegate* delegate_;
@@ -262,7 +265,7 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
FetchRequestMode request_mode_;
FetchCredentialsMode credentials_mode_;
FetchRedirectMode redirect_mode_;
- const bool is_main_resource_load_;
+ const ResourceType resource_type_;
RequestContextType request_context_type_;
RequestContextFrameType frame_type_;
bool fall_back_required_;
@@ -271,10 +274,14 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
scoped_refptr<ResourceRequestBody> body_;
scoped_ptr<storage::BlobDataHandle> request_body_blob_data_handle_;
scoped_refptr<ServiceWorkerVersion> streaming_version_;
+ ServiceWorkerFetchType fetch_type_;
ResponseBodyType response_body_type_ = UNKNOWN;
bool did_record_result_ = false;
+ bool response_is_in_cache_storage_ = false;
+ std::string response_cache_storage_cache_name_;
+
base::WeakPtrFactory<ServiceWorkerURLRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJob);
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 80c5bd39390..6440dd12c2a 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -72,7 +72,9 @@ class TestCallbackTracker {
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks service_worker_start_time,
- base::TimeTicks service_worker_ready_time) {
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) {
++times_on_start_completed_invoked_;
was_fetched_via_service_worker_ = was_fetched_via_service_worker;
@@ -82,6 +84,8 @@ class TestCallbackTracker {
blink::WebServiceWorkerResponseTypeDefault;
service_worker_start_time_ = service_worker_start_time;
service_worker_ready_time_ = service_worker_ready_time;
+ response_is_in_cache_storage_ = response_is_in_cache_storage;
+ response_cache_storage_cache_name_ = response_cache_storage_cache_name;
}
void OnPrepareToRestart(base::TimeTicks service_worker_start_time,
@@ -127,6 +131,14 @@ class TestCallbackTracker {
return service_worker_ready_time_;
}
+ bool response_is_in_cache_storage() const {
+ return response_is_in_cache_storage_;
+ }
+
+ const std::string& response_cache_storage_cache_name() const {
+ return response_cache_storage_cache_name_;
+ }
+
private:
int times_on_start_completed_invoked_ = 0;
int times_prepare_to_restart_invoked_ = 0;
@@ -140,6 +152,8 @@ class TestCallbackTracker {
blink::WebServiceWorkerResponseTypeDefault;
base::TimeTicks service_worker_start_time_;
base::TimeTicks service_worker_ready_time_;
+ bool response_is_in_cache_storage_ = false;
+ std::string response_cache_storage_cache_name_;
DISALLOW_COPY_AND_ASSIGN(TestCallbackTracker);
};
@@ -174,9 +188,10 @@ class MockHttpProtocolHandler
request, network_delegate, provider_host_->client_uuid(),
blob_storage_context_, resource_context_, FETCH_REQUEST_MODE_NO_CORS,
FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE,
- true /* is_main_resource_load */, REQUEST_CONTEXT_TYPE_HYPERLINK,
+ RESOURCE_TYPE_MAIN_FRAME, REQUEST_CONTEXT_TYPE_HYPERLINK,
REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
- scoped_refptr<ResourceRequestBody>(), delegate_);
+ scoped_refptr<ResourceRequestBody>(), ServiceWorkerFetchType::FETCH,
+ delegate_);
job_->ForwardToServiceWorker();
return job_;
}
@@ -346,11 +361,14 @@ class ServiceWorkerURLRequestJobTest
const GURL& original_url_via_service_worker,
blink::WebServiceWorkerResponseType response_type_via_service_worker,
base::TimeTicks worker_start_time,
- base::TimeTicks service_worker_ready_time) override {
+ base::TimeTicks service_worker_ready_time,
+ bool response_is_in_cache_storage,
+ const std::string& response_cache_storage_cache_name) override {
callback_tracker_.OnStartCompleted(
was_fetched_via_service_worker, was_fallback_required,
original_url_via_service_worker, response_type_via_service_worker,
- worker_start_time, service_worker_ready_time);
+ worker_start_time, service_worker_ready_time,
+ response_is_in_cache_storage, response_cache_storage_cache_name);
}
ServiceWorkerVersion* GetServiceWorkerVersion(
@@ -381,11 +399,6 @@ class ServiceWorkerURLRequestJobTest
provider_host_->NotifyControllerLost();
}
- GURL GetRequestingOrigin() override {
- CHECK(provider_host_);
- return provider_host_->document_url().GetOrigin();
- }
-
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestBrowserContext> browser_context_;
@@ -420,6 +433,9 @@ TEST_F(ServiceWorkerURLRequestJobTest, Simple) {
callback_tracker_.response_type_via_service_worker());
EXPECT_FALSE(callback_tracker_.service_worker_start_time().is_null());
EXPECT_FALSE(callback_tracker_.service_worker_ready_time().is_null());
+ EXPECT_FALSE(callback_tracker_.response_is_in_cache_storage());
+ EXPECT_EQ(std::string(),
+ callback_tracker_.response_cache_storage_cache_name());
}
class ProviderDeleteHelper : public EmbeddedWorkerTestHelper {
@@ -438,7 +454,9 @@ class ProviderDeleteHelper : public EmbeddedWorkerTestHelper {
ServiceWorkerResponse(
GURL(), 200, "OK", blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(), std::string(), 0, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown)));
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time(),
+ false /* response_is_in_cache_storage */,
+ std::string() /* response_cache_storage_cache_name */)));
}
private:
@@ -510,7 +528,9 @@ class BlobResponder : public EmbeddedWorkerTestHelper {
ServiceWorkerResponse(
GURL(), 200, "OK", blink::WebServiceWorkerResponseTypeDefault,
ServiceWorkerHeaderMap(), blob_uuid_, blob_size_, GURL(),
- blink::WebServiceWorkerResponseErrorUnknown)));
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time(),
+ false /* response_is_in_cache_storage */,
+ std::string() /* response_cache_storage_cache_name */)));
}
std::string blob_uuid_;
@@ -579,10 +599,12 @@ class StreamResponder : public EmbeddedWorkerTestHelper {
SimulateSend(new ServiceWorkerHostMsg_FetchEventFinished(
embedded_worker_id, request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
- ServiceWorkerResponse(GURL(), 200, "OK",
- blink::WebServiceWorkerResponseTypeDefault,
- ServiceWorkerHeaderMap(), "", 0, stream_url_,
- blink::WebServiceWorkerResponseErrorUnknown)));
+ ServiceWorkerResponse(
+ GURL(), 200, "OK", blink::WebServiceWorkerResponseTypeDefault,
+ ServiceWorkerHeaderMap(), "", 0, stream_url_,
+ blink::WebServiceWorkerResponseErrorUnknown, base::Time(),
+ false /* response_is_in_cache_storage */,
+ std::string() /* response_cache_storage_cache_name */)));
}
const GURL stream_url_;
diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc
index 54268049a22..cf3c209d330 100644
--- a/chromium/content/browser/service_worker/service_worker_version.cc
+++ b/chromium/content/browser/service_worker/service_worker_version.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <limits>
#include <map>
#include <string>
@@ -32,6 +33,7 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_type_converters.h"
#include "content/common/service_worker/service_worker_utils.h"
@@ -62,10 +64,6 @@ const int kUpdateDelaySeconds = 1;
// Timeout for waiting for a response to a ping.
const int kPingTimeoutSeconds = 30;
-// If the SW was destructed while starting up, how many seconds it
-// had to start up for this to be considered a timeout occurrence.
-const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5;
-
const char kClaimClientsStateErrorMesage[] =
"Only the active worker can claim clients.";
@@ -87,29 +85,6 @@ void RunCallbacks(ServiceWorkerVersion* version,
callback.Run(arg);
}
-template <typename IDMAP, typename... Params>
-void RunIDMapCallbacks(IDMAP* requests, const Params&... params) {
- typename IDMAP::iterator iter(requests);
- while (!iter.IsAtEnd()) {
- iter.GetCurrentValue()->callback.Run(params...);
- iter.Advance();
- }
- requests->Clear();
-}
-
-template <typename CallbackType, typename... Params>
-bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* requests,
- int request_id,
- const Params&... params) {
- CallbackType* request = requests->Lookup(request_id);
- if (!request)
- return false;
-
- request->callback.Run(params...);
- requests->Remove(request_id);
- return true;
-}
-
void RunStartWorkerCallback(
const StatusCallback& callback,
scoped_refptr<ServiceWorkerRegistration> protect,
@@ -139,13 +114,6 @@ void RunTaskAfterStartWorker(
task.Run();
}
-void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
- ServiceWorkerStatusCode status) {
- callback.Run(status,
- SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
- ServiceWorkerResponse());
-}
-
void RunErrorMessageCallback(
const std::vector<TransferredMessagePort>& sent_message_ports,
const ServiceWorkerVersion::StatusCallback& callback,
@@ -202,6 +170,38 @@ bool IsInstalled(ServiceWorkerVersion::Status status) {
return false;
}
+std::string VersionStatusToString(ServiceWorkerVersion::Status status) {
+ switch (status) {
+ case ServiceWorkerVersion::NEW:
+ return "new";
+ case ServiceWorkerVersion::INSTALLING:
+ return "installing";
+ case ServiceWorkerVersion::INSTALLED:
+ return "installed";
+ case ServiceWorkerVersion::ACTIVATING:
+ return "activating";
+ case ServiceWorkerVersion::ACTIVATED:
+ return "activated";
+ case ServiceWorkerVersion::REDUNDANT:
+ return "redundant";
+ }
+ NOTREACHED() << status;
+ return std::string();
+}
+
+const int kInvalidTraceId = -1;
+
+int NextTraceId() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ static int trace_id = 0;
+ if (trace_id == std::numeric_limits<int>::max())
+ trace_id = 0;
+ else
+ ++trace_id;
+ DCHECK_NE(kInvalidTraceId, trace_id);
+ return trace_id;
+}
+
} // namespace
const int ServiceWorkerVersion::kTimeoutTimerDelaySeconds = 30;
@@ -324,13 +324,13 @@ ServiceWorkerVersion::ServiceWorkerVersion(
ServiceWorkerVersion::~ServiceWorkerVersion() {
in_dtor_ = true;
- // The user may have closed the tab waiting for SW to start up.
- if (GetTickDuration(start_time_) >
- base::TimeDelta::FromSeconds(
- kDestructedStartingWorkerTimeoutThresholdSeconds)) {
- DCHECK(timeout_timer_.IsRunning());
- DCHECK(!embedded_worker_->devtools_attached());
- RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
+ // Record UMA if the worker was trying to start. One way we get here is if the
+ // user closed the tab before the SW could start up.
+ if (!start_callbacks_.empty()) {
+ // RecordStartWorkerResult must be the first element of start_callbacks_.
+ StatusCallback record_start_worker_result = start_callbacks_[0];
+ start_callbacks_.clear();
+ record_start_worker_result.Run(SERVICE_WORKER_ERROR_ABORT);
}
if (context_)
@@ -388,46 +388,64 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
return info;
}
-void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
+void ServiceWorkerVersion::StartWorker(ServiceWorkerMetrics::EventType purpose,
+ const StatusCallback& callback) {
+ TRACE_EVENT_INSTANT2(
+ "ServiceWorker", "ServiceWorkerVersion::StartWorker (instant)",
+ TRACE_EVENT_SCOPE_THREAD, "Script", script_url_.spec(), "Purpose",
+ ServiceWorkerMetrics::EventTypeToString(purpose));
+
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ const bool is_browser_startup_complete =
+ GetContentClient()->browser()->IsBrowserStartupComplete();
if (!context_) {
- RecordStartWorkerResult(SERVICE_WORKER_ERROR_ABORT);
+ RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
+ is_browser_startup_complete,
+ SERVICE_WORKER_ERROR_ABORT);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
return;
}
if (is_redundant()) {
- RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT);
+ RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
+ is_browser_startup_complete,
+ SERVICE_WORKER_ERROR_REDUNDANT);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_REDUNDANT));
return;
}
+
// Check that the worker is allowed to start on the given scope. Since this
// worker might not be used for a specific frame/process, use -1.
// resource_context() can return null in unit tests.
if (context_->wrapper()->resource_context() &&
!GetContentClient()->browser()->AllowServiceWorker(
scope_, scope_, context_->wrapper()->resource_context(), -1, -1)) {
- RecordStartWorkerResult(SERVICE_WORKER_ERROR_DISALLOWED);
+ RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
+ is_browser_startup_complete,
+ SERVICE_WORKER_ERROR_DISALLOWED);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_DISALLOWED));
return;
}
- prestart_status_ = status_;
-
// Ensure the live registration during starting worker so that the worker can
// get associated with it in SWDispatcherHost::OnSetHostedVersionId().
context_->storage()->FindRegistrationForId(
- registration_id_,
- scope_.GetOrigin(),
+ registration_id_, scope_.GetOrigin(),
base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
- weak_factory_.GetWeakPtr(),
- callback));
+ weak_factory_.GetWeakPtr(), purpose, status_,
+ is_browser_startup_complete, callback));
}
void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
+ TRACE_EVENT_INSTANT2("ServiceWorker",
+ "ServiceWorkerVersion::StopWorker (instant)",
+ TRACE_EVENT_SCOPE_THREAD, "Script", script_url_.spec(),
+ "Status", VersionStatusToString(status_));
+
if (running_status() == STOPPED) {
RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
return;
}
+
if (stop_callbacks_.empty()) {
ServiceWorkerStatusCode status = embedded_worker_->Stop();
if (status != SERVICE_WORKER_OK) {
@@ -475,11 +493,9 @@ void ServiceWorkerVersion::DeferScheduledUpdate() {
int ServiceWorkerVersion::StartRequest(
ServiceWorkerMetrics::EventType event_type,
const StatusCallback& error_callback) {
- OnBeginEvent();
- DCHECK_EQ(RUNNING, running_status())
- << "Can only start a request with a running worker.";
- return AddRequest(error_callback, &custom_requests_, REQUEST_CUSTOM,
- event_type);
+ return StartRequestWithCustomTimeout(
+ event_type, error_callback,
+ base::TimeDelta::FromMinutes(kRequestTimeoutMinutes), KILL_ON_TIMEOUT);
}
int ServiceWorkerVersion::StartRequestWithCustomTimeout(
@@ -490,25 +506,58 @@ int ServiceWorkerVersion::StartRequestWithCustomTimeout(
OnBeginEvent();
DCHECK_EQ(RUNNING, running_status())
<< "Can only start a request with a running worker.";
- return AddRequestWithExpiration(
- error_callback, &custom_requests_, REQUEST_CUSTOM, event_type,
- base::TimeTicks::Now() + timeout, timeout_behavior);
+ DCHECK(event_type == ServiceWorkerMetrics::EventType::INSTALL ||
+ event_type == ServiceWorkerMetrics::EventType::ACTIVATE ||
+ event_type == ServiceWorkerMetrics::EventType::MESSAGE ||
+ status() == ACTIVATED)
+ << "Event of type " << static_cast<int>(event_type)
+ << " can only be dispatched to an active worker: " << status();
+
+ PendingRequest<StatusCallback>* request = new PendingRequest<StatusCallback>(
+ error_callback, base::TimeTicks::Now(), event_type);
+ int request_id = custom_requests_.Add(request);
+ TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::Request",
+ request, "Request id", request_id, "Event type",
+ ServiceWorkerMetrics::EventTypeToString(event_type));
+ base::TimeTicks expiration_time = base::TimeTicks::Now() + timeout;
+ requests_.push(
+ RequestInfo(request_id, event_type, expiration_time, timeout_behavior));
+ return request_id;
}
-bool ServiceWorkerVersion::FinishRequest(int request_id) {
+bool ServiceWorkerVersion::FinishRequest(int request_id, bool was_handled) {
PendingRequest<StatusCallback>* request = custom_requests_.Lookup(request_id);
if (!request)
return false;
+ // TODO(kinuko): Record other event statuses too.
+ metrics_->RecordEventHandledStatus(request->event_type, was_handled);
ServiceWorkerMetrics::RecordEventDuration(
- request->event_type, base::TimeTicks::Now() - request->start_time);
- RemoveCallbackAndStopIfRedundant(&custom_requests_, request_id);
+ request->event_type, base::TimeTicks::Now() - request->start_time,
+ was_handled);
+
+ RestartTick(&idle_time_);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
+ request, "Handled", was_handled);
+ custom_requests_.Remove(request_id);
+ if (is_redundant()) {
+ // The stop should be already scheduled, but try to stop immediately, in
+ // order to release worker resources soon.
+ StopWorkerIfIdle();
+ }
return true;
}
void ServiceWorkerVersion::RunAfterStartWorker(
- const StatusCallback& error_callback,
- const base::Closure& task) {
- StartWorker(base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
+ ServiceWorkerMetrics::EventType purpose,
+ const base::Closure& task,
+ const StatusCallback& error_callback) {
+ if (running_status() == RUNNING) {
+ DCHECK(start_callbacks_.empty());
+ task.Run();
+ return;
+ }
+ StartWorker(purpose,
+ base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
error_callback, task));
}
@@ -530,12 +579,13 @@ void ServiceWorkerVersion::DispatchMessageEventInternal(
OnBeginEvent();
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
- StartWorker(base::Bind(
- &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
- base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
- base::Bind(&self::DispatchMessageEventInternal,
- weak_factory_.GetWeakPtr(), message, sent_message_ports,
- callback)));
+ StartWorker(ServiceWorkerMetrics::EventType::MESSAGE,
+ base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
+ base::Bind(&RunErrorMessageCallback,
+ sent_message_ports, callback),
+ base::Bind(&self::DispatchMessageEventInternal,
+ weak_factory_.GetWeakPtr(), message,
+ sent_message_ports, callback)));
return;
}
@@ -553,164 +603,6 @@ void ServiceWorkerVersion::DispatchMessageEventInternal(
RunSoon(base::Bind(callback, status));
}
-void ServiceWorkerVersion::DispatchInstallEvent(
- const StatusCallback& callback) {
- OnBeginEvent();
- DCHECK_EQ(INSTALLING, status()) << status();
-
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(
- base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(),
- callback,
- base::Bind(&self::DispatchInstallEventAfterStartWorker,
- weak_factory_.GetWeakPtr(),
- callback)));
- } else {
- DispatchInstallEventAfterStartWorker(callback);
- }
-}
-
-void ServiceWorkerVersion::DispatchActivateEvent(
- const StatusCallback& callback) {
- OnBeginEvent();
- DCHECK_EQ(ACTIVATING, status()) << status();
-
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(
- base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(),
- callback,
- base::Bind(&self::DispatchActivateEventAfterStartWorker,
- weak_factory_.GetWeakPtr(),
- callback)));
- } else {
- DispatchActivateEventAfterStartWorker(callback);
- }
-}
-
-void ServiceWorkerVersion::DispatchFetchEvent(
- const ServiceWorkerFetchRequest& request,
- const base::Closure& prepare_callback,
- const FetchCallback& fetch_callback) {
- OnBeginEvent();
- DCHECK_EQ(ACTIVATED, status()) << status();
-
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(),
- base::Bind(&RunErrorFetchCallback, fetch_callback),
- base::Bind(&self::DispatchFetchEvent,
- weak_factory_.GetWeakPtr(),
- request,
- prepare_callback,
- fetch_callback)));
- return;
- }
-
- prepare_callback.Run();
-
- int request_id = AddRequest(fetch_callback, &fetch_requests_, REQUEST_FETCH,
- ServiceWorkerMetrics::EventType::FETCH);
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_FetchEvent(request_id, request));
- if (status != SERVICE_WORKER_OK) {
- fetch_requests_.Remove(request_id);
- RunSoon(base::Bind(&RunErrorFetchCallback,
- fetch_callback,
- SERVICE_WORKER_ERROR_FAILED));
- }
-}
-
-void ServiceWorkerVersion::DispatchNotificationClickEvent(
- const StatusCallback& callback,
- int64_t persistent_notification_id,
- const PlatformNotificationData& notification_data,
- int action_index) {
- OnBeginEvent();
- DCHECK_EQ(ACTIVATED, status()) << status();
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(base::Bind(
- &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(), callback,
- base::Bind(&self::DispatchNotificationClickEvent,
- weak_factory_.GetWeakPtr(), callback,
- persistent_notification_id, notification_data,
- action_index)));
- return;
- }
-
- int request_id = AddRequest(
- callback, &notification_click_requests_, REQUEST_NOTIFICATION_CLICK,
- ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK);
- ServiceWorkerStatusCode status =
- embedded_worker_->SendMessage(ServiceWorkerMsg_NotificationClickEvent(
- request_id, persistent_notification_id, notification_data,
- action_index));
- if (status != SERVICE_WORKER_OK) {
- notification_click_requests_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
- }
-}
-
-void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
- const std::string& data) {
- OnBeginEvent();
- DCHECK_EQ(ACTIVATED, status()) << status();
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(), callback,
- base::Bind(&self::DispatchPushEvent,
- weak_factory_.GetWeakPtr(),
- callback, data)));
- return;
- }
-
- int request_id = AddRequest(callback, &push_requests_, REQUEST_PUSH,
- ServiceWorkerMetrics::EventType::PUSH);
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_PushEvent(request_id, data));
- if (status != SERVICE_WORKER_OK) {
- push_requests_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
- }
-}
-
-void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
- const NavigatorConnectClient& client,
- const base::string16& message,
- const std::vector<TransferredMessagePort>& sent_message_ports,
- const StatusCallback& callback) {
- OnBeginEvent();
- // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
- // have already put all the sent message ports on hold. So no need to do that
- // here again.
-
- if (running_status() != RUNNING) {
- // Schedule calling this method after starting the worker.
- StartWorker(base::Bind(
- &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
- base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
- base::Bind(&self::DispatchCrossOriginMessageEvent,
- weak_factory_.GetWeakPtr(), client, message,
- sent_message_ports, callback)));
- return;
- }
-
- MessagePortMessageFilter* filter =
- embedded_worker_->message_port_message_filter();
- std::vector<int> new_routing_ids;
- filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
- ServiceWorkerStatusCode status =
- embedded_worker_->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
- client, message, sent_message_ports, new_routing_ids));
- RunSoon(base::Bind(callback, status));
-}
-
void ServiceWorkerVersion::AddControllee(
ServiceWorkerProviderHost* provider_host) {
const std::string& uuid = provider_host->client_uuid();
@@ -831,12 +723,10 @@ ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
ServiceWorkerVersion::RequestInfo::RequestInfo(
int id,
- RequestType type,
ServiceWorkerMetrics::EventType event_type,
const base::TimeTicks& expiration,
TimeoutBehavior timeout_behavior)
: id(id),
- type(type),
event_type(event_type),
expiration(expiration),
timeout_behavior(timeout_behavior) {}
@@ -867,6 +757,8 @@ ServiceWorkerVersion::BaseMojoServiceWrapper::~BaseMojoServiceWrapper() {
while (!iter.IsAtEnd()) {
PendingRequest<StatusCallback>* request = iter.GetCurrentValue();
if (request->mojo_service == service_name_) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
+ request, "Error", "Service Disconnected");
request->callback.Run(SERVICE_WORKER_ERROR_FAILED);
worker_->custom_requests_.Remove(iter.GetCurrentKey());
}
@@ -875,8 +767,6 @@ ServiceWorkerVersion::BaseMojoServiceWrapper::~BaseMojoServiceWrapper() {
}
void ServiceWorkerVersion::OnThreadStarted() {
- if (running_status() == STOPPING)
- return;
DCHECK_EQ(STARTING, running_status());
// Activate ping/pong now that JavaScript execution will start.
ping_controller_->Activate();
@@ -899,6 +789,10 @@ void ServiceWorkerVersion::OnStarted() {
void ServiceWorkerVersion::OnStopping() {
DCHECK(stop_time_.is_null());
RestartTick(&stop_time_);
+ TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::StopWorker",
+ stop_time_.ToInternalValue(), "Script",
+ script_url_.spec(), "Version Status",
+ VersionStatusToString(status_));
// Shorten the interval so stalling in stopped can be fixed quickly. Once the
// worker stops, the timer is disabled. The interval will be reset to normal
@@ -969,18 +863,9 @@ void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClient, OnGetClient)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
OnGetClients)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
- OnActivateEventFinished)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
- OnInstallEventFinished)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
- OnFetchEventFinished)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
- OnNotificationClickEventFinished)
- IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
- OnPushEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
OnOpenWindow)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
@@ -1013,34 +898,39 @@ void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
}
}
-void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
- const StatusCallback& callback) {
- DCHECK_EQ(RUNNING, running_status())
- << "Worker stopped too soon after it was started.";
-
- int request_id = AddRequest(callback, &install_requests_, REQUEST_INSTALL,
- ServiceWorkerMetrics::EventType::INSTALL);
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_InstallEvent(request_id));
- if (status != SERVICE_WORKER_OK) {
- install_requests_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
+void ServiceWorkerVersion::OnGetClient(int request_id,
+ const std::string& client_uuid) {
+ if (!context_)
+ return;
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker", "ServiceWorkerVersion::OnGetClient",
+ request_id, "client_uuid", client_uuid);
+ ServiceWorkerProviderHost* provider_host =
+ context_->GetProviderHostByClientID(client_uuid);
+ if (!provider_host ||
+ provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
+ // The promise will be resolved to 'undefined'.
+ OnGetClientFinished(request_id, ServiceWorkerClientInfo());
+ return;
}
+ service_worker_client_utils::GetClient(
+ provider_host, base::Bind(&ServiceWorkerVersion::OnGetClientFinished,
+ weak_factory_.GetWeakPtr(), request_id));
}
-void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
- const StatusCallback& callback) {
- DCHECK_EQ(RUNNING, running_status())
- << "Worker stopped too soon after it was started.";
+void ServiceWorkerVersion::OnGetClientFinished(
+ int request_id,
+ const ServiceWorkerClientInfo& client_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClient",
+ request_id, "client_type", client_info.client_type);
- int request_id = AddRequest(callback, &activate_requests_, REQUEST_ACTIVATE,
- ServiceWorkerMetrics::EventType::ACTIVATE);
- ServiceWorkerStatusCode status =
- embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
- if (status != SERVICE_WORKER_OK) {
- activate_requests_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
- }
+ // When Clients.get() is called on the script evaluation phase, the running
+ // status can be STARTING here.
+ if (running_status() != STARTING && running_status() != RUNNING)
+ return;
+
+ embedded_worker_->SendMessage(
+ ServiceWorkerMsg_DidGetClient(request_id, client_info));
}
void ServiceWorkerVersion::OnGetClients(
@@ -1071,126 +961,21 @@ void ServiceWorkerVersion::OnGetClientsFinished(int request_id,
ServiceWorkerMsg_DidGetClients(request_id, *clients));
}
-void ServiceWorkerVersion::OnActivateEventFinished(
- int request_id,
- blink::WebServiceWorkerEventResult result) {
- DCHECK(ACTIVATING == status() ||
- REDUNDANT == status()) << status();
- TRACE_EVENT0("ServiceWorker",
- "ServiceWorkerVersion::OnActivateEventFinished");
-
- PendingRequest<StatusCallback>* request =
- activate_requests_.Lookup(request_id);
- if (!request) {
- NOTREACHED() << "Got unexpected message: " << request_id;
- return;
- }
- ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
- if (result == blink::WebServiceWorkerEventResultRejected)
- rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
-
- ServiceWorkerMetrics::RecordEventDuration(
- request->event_type, base::TimeTicks::Now() - request->start_time);
-
- scoped_refptr<ServiceWorkerVersion> protect(this);
- request->callback.Run(rv);
- RemoveCallbackAndStopIfRedundant(&activate_requests_, request_id);
-}
-
-void ServiceWorkerVersion::OnInstallEventFinished(
+void ServiceWorkerVersion::OnSimpleEventResponse(
int request_id,
blink::WebServiceWorkerEventResult result) {
- // Status is REDUNDANT if the worker was doomed while handling the install
- // event, and finished handling before being terminated.
- DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
- TRACE_EVENT0("ServiceWorker",
- "ServiceWorkerVersion::OnInstallEventFinished");
-
- PendingRequest<StatusCallback>* request =
- install_requests_.Lookup(request_id);
- if (!request) {
- NOTREACHED() << "Got unexpected message: " << request_id;
- return;
- }
- ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
- if (result == blink::WebServiceWorkerEventResultRejected)
- status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
-
- ServiceWorkerMetrics::RecordEventDuration(
- request->event_type, base::TimeTicks::Now() - request->start_time);
-
- scoped_refptr<ServiceWorkerVersion> protect(this);
- request->callback.Run(status);
- RemoveCallbackAndStopIfRedundant(&install_requests_, request_id);
-}
-
-void ServiceWorkerVersion::OnFetchEventFinished(
- int request_id,
- ServiceWorkerFetchEventResult result,
- const ServiceWorkerResponse& response) {
- TRACE_EVENT1("ServiceWorker",
- "ServiceWorkerVersion::OnFetchEventFinished",
- "Request id", request_id);
- PendingRequest<FetchCallback>* request = fetch_requests_.Lookup(request_id);
- if (!request) {
- NOTREACHED() << "Got unexpected message: " << request_id;
- return;
- }
-
- // TODO(kinuko): Record other event statuses too.
- const bool handled = (result == SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE);
- metrics_->RecordEventHandledStatus(ServiceWorkerMetrics::EventType::FETCH,
- handled);
-
- ServiceWorkerMetrics::RecordFetchEventTime(
- result, base::TimeTicks::Now() - request->start_time);
-
- scoped_refptr<ServiceWorkerVersion> protect(this);
- request->callback.Run(SERVICE_WORKER_OK, result, response);
- RemoveCallbackAndStopIfRedundant(&fetch_requests_, request_id);
-}
-
-void ServiceWorkerVersion::OnNotificationClickEventFinished(
- int request_id) {
- TRACE_EVENT1("ServiceWorker",
- "ServiceWorkerVersion::OnNotificationClickEventFinished",
- "Request id", request_id);
- PendingRequest<StatusCallback>* request =
- notification_click_requests_.Lookup(request_id);
- if (!request) {
- NOTREACHED() << "Got unexpected message: " << request_id;
- return;
- }
-
- ServiceWorkerMetrics::RecordEventDuration(
- request->event_type, base::TimeTicks::Now() - request->start_time);
+ // Copy error callback before calling FinishRequest.
+ PendingRequest<StatusCallback>* request = custom_requests_.Lookup(request_id);
+ DCHECK(request) << "Invalid request id";
+ StatusCallback callback = request->callback;
- scoped_refptr<ServiceWorkerVersion> protect(this);
- request->callback.Run(SERVICE_WORKER_OK);
- RemoveCallbackAndStopIfRedundant(&notification_click_requests_, request_id);
-}
+ FinishRequest(request_id,
+ result == blink::WebServiceWorkerEventResultCompleted);
-void ServiceWorkerVersion::OnPushEventFinished(
- int request_id,
- blink::WebServiceWorkerEventResult result) {
- TRACE_EVENT1("ServiceWorker",
- "ServiceWorkerVersion::OnPushEventFinished",
- "Request id", request_id);
- PendingRequest<StatusCallback>* request = push_requests_.Lookup(request_id);
- if (!request) {
- NOTREACHED() << "Got unexpected message: " << request_id;
- return;
- }
ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
if (result == blink::WebServiceWorkerEventResultRejected)
status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
-
- ServiceWorkerMetrics::RecordEventDuration(
- request->event_type, base::TimeTicks::Now() - request->start_time);
-
- scoped_refptr<ServiceWorkerVersion> protect(this);
- request->callback.Run(status);
- RemoveCallbackAndStopIfRedundant(&push_requests_, request_id);
+ callback.Run(status);
}
void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
@@ -1232,7 +1017,6 @@ void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
void ServiceWorkerVersion::OnOpenWindowFinished(
int request_id,
ServiceWorkerStatusCode status,
- const std::string& client_uuid,
const ServiceWorkerClientInfo& client_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -1245,16 +1029,8 @@ void ServiceWorkerVersion::OnOpenWindowFinished(
return;
}
- ServiceWorkerClientInfo client(client_info);
-
- // If the |client_info| is empty, it means that the opened window wasn't
- // controlled but the action still succeeded. The renderer process is
- // expecting an empty client in such case.
- if (!client.IsEmpty())
- client.client_uuid = client_uuid;
-
- embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
- request_id, client));
+ embedded_worker_->SendMessage(
+ ServiceWorkerMsg_OpenWindowResponse(request_id, client_info));
}
void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
@@ -1336,25 +1112,27 @@ void ServiceWorkerVersion::OnFocusClient(int request_id,
// possibly due to timing issue or bad message.
return;
}
- provider_host->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
- weak_factory_.GetWeakPtr(), request_id,
- client_uuid));
+ if (provider_host->client_type() != blink::WebServiceWorkerClientTypeWindow) {
+ // focus() should be called only for WindowClient. This may happen due to
+ // bad message.
+ return;
+ }
+
+ service_worker_client_utils::FocusWindowClient(
+ provider_host, base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
+ weak_factory_.GetWeakPtr(), request_id));
}
void ServiceWorkerVersion::OnFocusClientFinished(
int request_id,
- const std::string& client_uuid,
- const ServiceWorkerClientInfo& client) {
+ const ServiceWorkerClientInfo& client_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (running_status() != RUNNING)
return;
- ServiceWorkerClientInfo client_info(client);
- client_info.client_uuid = client_uuid;
-
- embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
- request_id, client_info));
+ embedded_worker_->SendMessage(
+ ServiceWorkerMsg_FocusClientResponse(request_id, client_info));
}
void ServiceWorkerVersion::OnNavigateClient(int request_id,
@@ -1403,7 +1181,6 @@ void ServiceWorkerVersion::OnNavigateClient(int request_id,
void ServiceWorkerVersion::OnNavigateClientFinished(
int request_id,
ServiceWorkerStatusCode status,
- const std::string& client_uuid,
const ServiceWorkerClientInfo& client_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -1416,16 +1193,8 @@ void ServiceWorkerVersion::OnNavigateClientFinished(
return;
}
- ServiceWorkerClientInfo client(client_info);
-
- // If the |client_info| is empty, it means that the navigated client wasn't
- // controlled but the action still succeeded. The renderer process is
- // expecting an empty client in such case.
- if (!client.IsEmpty())
- client.client_uuid = client_uuid;
-
embedded_worker_->SendMessage(
- ServiceWorkerMsg_NavigateClientResponse(request_id, client));
+ ServiceWorkerMsg_NavigateClientResponse(request_id, client_info));
}
void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
@@ -1476,7 +1245,8 @@ void ServiceWorkerVersion::OnPongFromWorker() {
}
void ServiceWorkerVersion::OnRegisterForeignFetchScopes(
- const std::vector<GURL>& sub_scopes) {
+ const std::vector<GURL>& sub_scopes,
+ const std::vector<url::Origin>& origins) {
DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
// Renderer should have already verified all these urls are inside the
// worker's scope, but verify again here on the browser process side.
@@ -1494,11 +1264,24 @@ void ServiceWorkerVersion::OnRegisterForeignFetchScopes(
return;
}
}
- foreign_fetch_scopes_.insert(foreign_fetch_scopes_.end(), sub_scopes.begin(),
- sub_scopes.end());
+ for (const url::Origin& url : origins) {
+ if (url.unique()) {
+ DVLOG(1) << "Received unexpected unique origin from renderer process.";
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&KillEmbeddedWorkerProcess, embedded_worker_->process_id(),
+ RESULT_CODE_KILLED_BAD_MESSAGE));
+ return;
+ }
+ }
+ set_foreign_fetch_scopes(sub_scopes);
+ set_foreign_fetch_origins(origins);
}
void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
+ ServiceWorkerMetrics::EventType purpose,
+ Status prestart_status,
+ bool is_browser_startup_complete,
const StatusCallback& callback,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
@@ -1515,12 +1298,15 @@ void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
}
}
if (status != SERVICE_WORKER_OK) {
- RecordStartWorkerResult(status);
+ RecordStartWorkerResult(purpose, prestart_status, kInvalidTraceId,
+ is_browser_startup_complete, status);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
return;
}
if (is_redundant()) {
- RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT);
+ RecordStartWorkerResult(purpose, prestart_status, kInvalidTraceId,
+ is_browser_startup_complete,
+ SERVICE_WORKER_ERROR_REDUNDANT);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_REDUNDANT));
return;
}
@@ -1531,34 +1317,54 @@ void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
case RUNNING:
RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
return;
+ case STARTING:
+ DCHECK(!start_callbacks_.empty());
+ break;
case STOPPING:
case STOPPED:
- case STARTING:
if (start_callbacks_.empty()) {
+ int trace_id = NextTraceId();
+ TRACE_EVENT_ASYNC_BEGIN2(
+ "ServiceWorker", "ServiceWorkerVersion::StartWorker", trace_id,
+ "Script", script_url_.spec(), "Purpose",
+ ServiceWorkerMetrics::EventTypeToString(purpose));
start_callbacks_.push_back(
base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
- weak_factory_.GetWeakPtr()));
+ weak_factory_.GetWeakPtr(), purpose, prestart_status,
+ trace_id, is_browser_startup_complete));
}
- // Keep the live registration while starting the worker.
- start_callbacks_.push_back(
- base::Bind(&RunStartWorkerCallback, callback, protect));
- StartWorkerInternal();
- return;
+ break;
}
+
+ // Keep the live registration while starting the worker.
+ start_callbacks_.push_back(
+ base::Bind(&RunStartWorkerCallback, callback, protect));
+
+ if (running_status() == STOPPED)
+ StartWorkerInternal();
+ DCHECK(timeout_timer_.IsRunning());
}
void ServiceWorkerVersion::StartWorkerInternal() {
- if (!metrics_)
- metrics_.reset(new Metrics(this));
+ DCHECK_EQ(STOPPED, running_status());
- if (!timeout_timer_.IsRunning())
- StartTimeoutTimer();
- if (running_status() == STOPPED) {
- embedded_worker_->Start(
- version_id_, scope_, script_url_,
- base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
- weak_factory_.GetWeakPtr()));
- }
+ DCHECK(!metrics_);
+ metrics_.reset(new Metrics(this));
+
+ StartTimeoutTimer();
+
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
+ new EmbeddedWorkerMsg_StartWorker_Params());
+ params->service_worker_version_id = version_id_;
+ params->scope = scope_;
+ params->script_url = script_url_;
+ params->is_installed = IsInstalled(status_);
+ params->pause_after_download = pause_after_download_;
+
+ embedded_worker_->Start(
+ std::move(params),
+ base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
+ weak_factory_.GetWeakPtr()));
}
void ServiceWorkerVersion::StartTimeoutTimer() {
@@ -1719,24 +1525,35 @@ void ServiceWorkerVersion::StopWorkerIfIdle() {
}
bool ServiceWorkerVersion::HasInflightRequests() const {
- return !activate_requests_.IsEmpty() || !install_requests_.IsEmpty() ||
- !fetch_requests_.IsEmpty() ||
- !notification_click_requests_.IsEmpty() || !push_requests_.IsEmpty() ||
- !custom_requests_.IsEmpty() || !streaming_url_request_jobs_.empty();
+ return !custom_requests_.IsEmpty() || !streaming_url_request_jobs_.empty();
}
void ServiceWorkerVersion::RecordStartWorkerResult(
+ ServiceWorkerMetrics::EventType purpose,
+ Status prestart_status,
+ int trace_id,
+ bool is_browser_startup_complete,
ServiceWorkerStatusCode status) {
+ if (trace_id != kInvalidTraceId) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::StartWorker",
+ trace_id, "Status",
+ ServiceWorkerStatusToString(status));
+ }
base::TimeTicks start_time = start_time_;
ClearTick(&start_time_);
- ServiceWorkerMetrics::RecordStartWorkerStatus(status,
- IsInstalled(prestart_status_));
+ if (context_)
+ context_->UpdateVersionFailureCount(version_id_, status);
+
+ ServiceWorkerMetrics::RecordStartWorkerStatus(status, purpose,
+ IsInstalled(prestart_status));
if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
!skip_recording_startup_time_) {
- ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time),
- IsInstalled(prestart_status_));
+ ServiceWorkerMetrics::RecordStartWorkerTime(
+ GetTickDuration(start_time), IsInstalled(prestart_status),
+ ServiceWorkerMetrics::GetStartSituation(
+ is_browser_startup_complete, embedded_worker_->is_new_process()));
}
if (status != SERVICE_WORKER_ERROR_TIMEOUT)
@@ -1763,73 +1580,16 @@ void ServiceWorkerVersion::RecordStartWorkerResult(
EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
}
-template <typename IDMAP>
-void ServiceWorkerVersion::RemoveCallbackAndStopIfRedundant(IDMAP* callbacks,
- int request_id) {
- RestartTick(&idle_time_);
- callbacks->Remove(request_id);
- if (is_redundant()) {
- // The stop should be already scheduled, but try to stop immediately, in
- // order to release worker resources soon.
- StopWorkerIfIdle();
- }
-}
-
-template <typename CallbackType>
-int ServiceWorkerVersion::AddRequest(
- const CallbackType& callback,
- IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map,
- RequestType request_type,
- ServiceWorkerMetrics::EventType event_type) {
- base::TimeTicks expiration_time =
- base::TimeTicks::Now() +
- base::TimeDelta::FromMinutes(kRequestTimeoutMinutes);
- return AddRequestWithExpiration(callback, callback_map, request_type,
- event_type, expiration_time, KILL_ON_TIMEOUT);
-}
-
-template <typename CallbackType>
-int ServiceWorkerVersion::AddRequestWithExpiration(
- const CallbackType& callback,
- IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map,
- RequestType request_type,
- ServiceWorkerMetrics::EventType event_type,
- base::TimeTicks expiration,
- TimeoutBehavior timeout_behavior) {
- int request_id = callback_map->Add(new PendingRequest<CallbackType>(
- callback, base::TimeTicks::Now(), event_type));
- requests_.push(RequestInfo(request_id, request_type, event_type, expiration,
- timeout_behavior));
- return request_id;
-}
-
bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) {
- switch (info.type) {
- case REQUEST_ACTIVATE:
- return RunIDMapCallback(&activate_requests_, info.id,
- SERVICE_WORKER_ERROR_TIMEOUT);
- case REQUEST_INSTALL:
- return RunIDMapCallback(&install_requests_, info.id,
- SERVICE_WORKER_ERROR_TIMEOUT);
- case REQUEST_FETCH:
- return RunIDMapCallback(
- &fetch_requests_, info.id, SERVICE_WORKER_ERROR_TIMEOUT,
- /* The other args are ignored for non-OK status. */
- SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse());
- case REQUEST_NOTIFICATION_CLICK:
- return RunIDMapCallback(&notification_click_requests_, info.id,
- SERVICE_WORKER_ERROR_TIMEOUT);
- case REQUEST_PUSH:
- return RunIDMapCallback(&push_requests_, info.id,
- SERVICE_WORKER_ERROR_TIMEOUT);
- case REQUEST_CUSTOM:
- return RunIDMapCallback(&custom_requests_, info.id,
- SERVICE_WORKER_ERROR_TIMEOUT);
- case NUM_REQUEST_TYPES:
- break;
- }
- NOTREACHED() << "Got unexpected request type: " << info.type;
- return false;
+ PendingRequest<StatusCallback>* request = custom_requests_.Lookup(info.id);
+ if (!request)
+ return false;
+
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
+ request, "Error", "Timeout");
+ request->callback.Run(SERVICE_WORKER_ERROR_TIMEOUT);
+ custom_requests_.Remove(info.id);
+ return true;
}
void ServiceWorkerVersion::SetAllRequestExpirations(
@@ -1917,7 +1677,12 @@ void ServiceWorkerVersion::OnStoppedInternal(
(old_status != EmbeddedWorkerInstance::STARTING) &&
!in_dtor_ && !ping_controller_->IsTimedOut();
- ClearTick(&stop_time_);
+ if (!stop_time_.is_null()) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::StopWorker",
+ stop_time_.ToInternalValue(), "Restart",
+ should_restart);
+ ClearTick(&stop_time_);
+ }
StopTimeoutTimer();
// Fire all stop callbacks.
@@ -1933,16 +1698,15 @@ void ServiceWorkerVersion::OnStoppedInternal(
// Let all message callbacks fail (this will also fire and clear all
// callbacks for events).
// TODO(kinuko): Consider if we want to add queue+resend mechanism here.
- RunIDMapCallbacks(&activate_requests_,
- SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
- RunIDMapCallbacks(&install_requests_,
- SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
- RunIDMapCallbacks(&fetch_requests_, SERVICE_WORKER_ERROR_FAILED,
- SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
- ServiceWorkerResponse());
- RunIDMapCallbacks(&notification_click_requests_, SERVICE_WORKER_ERROR_FAILED);
- RunIDMapCallbacks(&push_requests_, SERVICE_WORKER_ERROR_FAILED);
- RunIDMapCallbacks(&custom_requests_, SERVICE_WORKER_ERROR_FAILED);
+ IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer>::iterator iter(
+ &custom_requests_);
+ while (!iter.IsAtEnd()) {
+ TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
+ iter.GetCurrentValue(), "Error", "Worker Stopped");
+ iter.GetCurrentValue()->callback.Run(SERVICE_WORKER_ERROR_FAILED);
+ iter.Advance();
+ }
+ custom_requests_.Clear();
// Close all mojo services. This will also fire and clear all callbacks
// for messages that are still outstanding for those services.
diff --git a/chromium/content/browser/service_worker/service_worker_version.h b/chromium/content/browser/service_worker/service_worker_version.h
index 96c54453043..b9517507545 100644
--- a/chromium/content/browser/service_worker/service_worker_version.h
+++ b/chromium/content/browser/service_worker/service_worker_version.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <functional>
#include <map>
#include <queue>
#include <set>
@@ -32,14 +33,14 @@
#include "content/public/common/service_registry.h"
#include "ipc/ipc_message.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerEventResult.h"
+#include "url/gurl.h"
+#include "url/origin.h"
// Windows headers will redefine SendMessage.
#ifdef SendMessage
#undef SendMessage
#endif
-class GURL;
-
namespace net {
class HttpResponseInfo;
}
@@ -51,8 +52,6 @@ class ServiceWorkerContextCore;
class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
class ServiceWorkerURLRequestJob;
-struct NavigatorConnectClient;
-struct PlatformNotificationData;
struct ServiceWorkerClientInfo;
struct ServiceWorkerVersionInfo;
struct TransferredMessagePort;
@@ -67,9 +66,6 @@ class CONTENT_EXPORT ServiceWorkerVersion
public EmbeddedWorkerInstance::Listener {
public:
typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
- typedef base::Callback<void(ServiceWorkerStatusCode,
- ServiceWorkerFetchEventResult,
- const ServiceWorkerResponse&)> FetchCallback;
enum RunningStatus {
STOPPED = EmbeddedWorkerInstance::STOPPED,
@@ -149,6 +145,13 @@ class CONTENT_EXPORT ServiceWorkerVersion
foreign_fetch_scopes_ = scopes;
}
+ const std::vector<url::Origin>& foreign_fetch_origins() const {
+ return foreign_fetch_origins_;
+ }
+ void set_foreign_fetch_origins(const std::vector<url::Origin>& origins) {
+ foreign_fetch_origins_ = origins;
+ }
+
// This sets the new status and also run status change callbacks
// if there're any (see RegisterStatusChangeCallback).
void SetStatus(Status status);
@@ -160,7 +163,9 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Starts an embedded worker for this version.
// This returns OK (success) if the worker is already running.
- void StartWorker(const StatusCallback& callback);
+ // |purpose| is recorded in UMA.
+ void StartWorker(ServiceWorkerMetrics::EventType purpose,
+ const StatusCallback& callback);
// Stops an embedded worker for this version.
// This returns OK (success) if the worker is already stopped.
@@ -178,8 +183,12 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Starts the worker if it isn't already running, and calls |task| when the
// worker is running, or |error_callback| if starting the worker failed.
- void RunAfterStartWorker(const StatusCallback& error_callback,
- const base::Closure& task);
+ // If the worker is already running, |task| is executed synchronously (before
+ // this method returns).
+ // |purpose| is used for UMA.
+ void RunAfterStartWorker(ServiceWorkerMetrics::EventType purpose,
+ const base::Closure& task,
+ const StatusCallback& error_callback);
// Call this while the worker is running before dispatching an event to the
// worker. This informs ServiceWorkerVersion about the event in progress.
@@ -201,7 +210,10 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Informs ServiceWorkerVersion that an event has finished being dispatched.
// Returns false if no pending requests with the provided id exist, for
// example if the request has already timed out.
- bool FinishRequest(int request_id);
+ // Pass the result of the event to |was_handled|, which is used to record
+ // statistics based on the event status.
+ // TODO(mek): Use something other than a bool for event status.
+ bool FinishRequest(int request_id, bool was_handled);
// Connects to a specific mojo service exposed by the (running) service
// worker. If a connection to a service for the same Interface already exists
@@ -224,74 +236,23 @@ class CONTENT_EXPORT ServiceWorkerVersion
const IPC::Message& message,
const ResponseCallbackType& callback);
+ // For simple events where the full functionality of DispatchEvent is not
+ // needed, this method can be used instead. The ResponseMessage must consist
+ // of just a request_id and a blink::WebServiceWorkerEventResult field. The
+ // result is converted to a ServiceWorkerStatusCode and passed to the error
+ // handler associated with the request. Additionally this methods calls
+ // FinishRequest before passing the reply to the callback.
+ template <typename ResponseMessage>
+ void DispatchSimpleEvent(int request_id, const IPC::Message& message);
+
// Sends a message event to the associated embedded worker.
+ // TODO(nhiroki): Remove this after ExtendableMessageEvent is enabled by
+ // default (crbug.com/543198).
void DispatchMessageEvent(
const base::string16& message,
const std::vector<TransferredMessagePort>& sent_message_ports,
const StatusCallback& callback);
- // Sends install event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets a response from the worker
- // to notify install completion.
- //
- // This must be called when the status() is NEW. Calling this changes
- // the version's status to INSTALLING.
- // Upon completion, the version's status will be changed to INSTALLED
- // on success, or back to NEW on failure.
- void DispatchInstallEvent(const StatusCallback& callback);
-
- // Sends activate event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets a response from the worker
- // to notify activation completion.
- //
- // This must be called when the status() is INSTALLED. Calling this changes
- // the version's status to ACTIVATING.
- // Upon completion, the version's status will be changed to ACTIVATED
- // on success, or back to INSTALLED on failure.
- void DispatchActivateEvent(const StatusCallback& callback);
-
- // Sends fetch event to the associated embedded worker and calls
- // |callback| with the response from the worker.
- //
- // This must be called when the status() is ACTIVATED. Calling this in other
- // statuses will result in an error SERVICE_WORKER_ERROR_FAILED.
- void DispatchFetchEvent(const ServiceWorkerFetchRequest& request,
- const base::Closure& prepare_callback,
- const FetchCallback& fetch_callback);
-
- // Sends notificationclick event to the associated embedded worker and
- // asynchronously calls |callback| when it errors out or it gets a response
- // from the worker to notify completion.
- //
- // This must be called when the status() is ACTIVATED.
- void DispatchNotificationClickEvent(
- const StatusCallback& callback,
- int64_t persistent_notification_id,
- const PlatformNotificationData& notification_data,
- int action_index);
-
- // Sends push event to the associated embedded worker and asynchronously calls
- // |callback| when it errors out or it gets a response from the worker to
- // notify completion.
- //
- // This must be called when the status() is ACTIVATED.
- void DispatchPushEvent(const StatusCallback& callback,
- const std::string& data);
-
- // Sends a cross origin message event to the associated embedded worker and
- // asynchronously calls |callback| when the message was sent (or failed to
- // sent).
- // It is the responsibility of the code calling this method to make sure that
- // any transferred message ports are put on hold while potentially a process
- // for the service worker is spun up.
- //
- // This must be called when the status() is ACTIVATED.
- void DispatchCrossOriginMessageEvent(
- const NavigatorConnectClient& client,
- const base::string16& message,
- const std::vector<TransferredMessagePort>& sent_message_ports,
- const StatusCallback& callback);
-
// Adds and removes |provider_host| as a controllee of this ServiceWorker.
// A potential controllee is a host having the version as its .installing
// or .waiting version.
@@ -342,9 +303,9 @@ class CONTENT_EXPORT ServiceWorkerVersion
force_bypass_cache_for_scripts_ = force_bypass_cache_for_scripts;
}
- bool skip_script_comparison() const { return skip_script_comparison_; }
- void set_skip_script_comparison(bool skip_script_comparison) {
- skip_script_comparison_ = skip_script_comparison;
+ bool pause_after_download() const { return pause_after_download_; }
+ void set_pause_after_download(bool pause_after_download) {
+ pause_after_download_ = pause_after_download;
}
void SetDevToolsAttached(bool attached);
@@ -379,7 +340,6 @@ class CONTENT_EXPORT ServiceWorkerVersion
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, StaleUpdate_RunningWorker);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest,
StaleUpdate_DoNotDeferTimer);
- FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWaitForeverInFetchTest, RequestTimeout);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, RequestTimeout);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerFailToStartTest, Timeout);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest,
@@ -393,32 +353,19 @@ class CONTENT_EXPORT ServiceWorkerVersion
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, RequestCustomizedTimeout);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest,
RequestCustomizedTimeoutKill);
- FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWaitForeverInFetchTest,
- MixedRequestTimeouts);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, MixedRequestTimeouts);
class Metrics;
class PingController;
- enum RequestType {
- REQUEST_ACTIVATE,
- REQUEST_INSTALL,
- REQUEST_FETCH,
- REQUEST_NOTIFICATION_CLICK,
- REQUEST_PUSH,
- REQUEST_CUSTOM,
- NUM_REQUEST_TYPES
- };
-
struct RequestInfo {
RequestInfo(int id,
- RequestType type,
ServiceWorkerMetrics::EventType event_type,
const base::TimeTicks& expiration,
TimeoutBehavior timeout_behavior);
~RequestInfo();
bool operator>(const RequestInfo& other) const;
int id;
- RequestType type;
ServiceWorkerMetrics::EventType event_type;
base::TimeTicks expiration;
TimeoutBehavior timeout_behavior;
@@ -494,17 +441,20 @@ class CONTENT_EXPORT ServiceWorkerVersion
template <typename ResponseMessage, typename CallbackType>
class EventResponseHandler : public EmbeddedWorkerInstance::Listener {
public:
- EventResponseHandler(EmbeddedWorkerInstance* worker,
+ EventResponseHandler(const base::WeakPtr<EmbeddedWorkerInstance>& worker,
int request_id,
const CallbackType& callback)
: worker_(worker), request_id_(request_id), callback_(callback) {
worker_->AddListener(this);
}
- ~EventResponseHandler() override { worker_->RemoveListener(this); }
+ ~EventResponseHandler() override {
+ if (worker_)
+ worker_->RemoveListener(this);
+ }
bool OnMessageReceived(const IPC::Message& message) override;
private:
- EmbeddedWorkerInstance* const worker_;
+ base::WeakPtr<EmbeddedWorkerInstance> const worker_;
const int request_id_;
const CallbackType callback_;
};
@@ -544,9 +494,6 @@ class CONTENT_EXPORT ServiceWorkerVersion
void OnStartSentAndScriptEvaluated(ServiceWorkerStatusCode status);
- void DispatchInstallEventAfterStartWorker(const StatusCallback& callback);
- void DispatchActivateEventAfterStartWorker(const StatusCallback& callback);
-
void DispatchMessageEventInternal(
const base::string16& message,
const std::vector<TransferredMessagePort>& sent_message_ports,
@@ -554,24 +501,18 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Message handlers.
+ // This corresponds to the spec's get(id) steps.
+ void OnGetClient(int request_id, const std::string& client_uuid);
+
// This corresponds to the spec's matchAll(options) steps.
void OnGetClients(int request_id,
const ServiceWorkerClientQueryOptions& options);
- void OnActivateEventFinished(int request_id,
- blink::WebServiceWorkerEventResult result);
- void OnInstallEventFinished(int request_id,
- blink::WebServiceWorkerEventResult result);
- void OnFetchEventFinished(int request_id,
- ServiceWorkerFetchEventResult result,
- const ServiceWorkerResponse& response);
- void OnNotificationClickEventFinished(int request_id);
- void OnPushEventFinished(int request_id,
- blink::WebServiceWorkerEventResult result);
+ void OnSimpleEventResponse(int request_id,
+ blink::WebServiceWorkerEventResult result);
void OnOpenWindow(int request_id, GURL url);
void OnOpenWindowFinished(int request_id,
ServiceWorkerStatusCode status,
- const std::string& client_uuid,
const ServiceWorkerClientInfo& client_info);
void OnSetCachedMetadata(const GURL& url, const std::vector<char>& data);
@@ -589,19 +530,21 @@ class CONTENT_EXPORT ServiceWorkerVersion
const GURL& url);
void OnNavigateClientFinished(int request_id,
ServiceWorkerStatusCode status,
- const std::string& client_uuid,
- const ServiceWorkerClientInfo& client);
+ const ServiceWorkerClientInfo& client_info);
void OnSkipWaiting(int request_id);
void OnClaimClients(int request_id);
void OnPongFromWorker();
void OnFocusClientFinished(int request_id,
- const std::string& client_uuid,
- const ServiceWorkerClientInfo& client);
+ const ServiceWorkerClientInfo& client_info);
- void OnRegisterForeignFetchScopes(const std::vector<GURL>& sub_scopes);
+ void OnRegisterForeignFetchScopes(const std::vector<GURL>& sub_scopes,
+ const std::vector<url::Origin>& origins);
void DidEnsureLiveRegistrationForStartWorker(
+ ServiceWorkerMetrics::EventType purpose,
+ Status prestart_status,
+ bool is_browser_startup_complete,
const StatusCallback& callback,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
@@ -609,6 +552,9 @@ class CONTENT_EXPORT ServiceWorkerVersion
void DidSkipWaiting(int request_id);
+ void OnGetClientFinished(int request_id,
+ const ServiceWorkerClientInfo& client_info);
+
void OnGetClientsFinished(int request_id, ServiceWorkerClients* clients);
// The timeout timer periodically calls OnTimeoutTimer, which stops the worker
@@ -629,26 +575,11 @@ class CONTENT_EXPORT ServiceWorkerVersion
// RecordStartWorkerResult is added as a start callback by StartTimeoutTimer
// and records metrics about startup.
- void RecordStartWorkerResult(ServiceWorkerStatusCode status);
-
- template <typename IDMAP>
- void RemoveCallbackAndStopIfRedundant(IDMAP* callbacks, int request_id);
-
- template <typename CallbackType>
- int AddRequest(
- const CallbackType& callback,
- IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map,
- RequestType request_type,
- ServiceWorkerMetrics::EventType event_type);
-
- template <typename CallbackType>
- int AddRequestWithExpiration(
- const CallbackType& callback,
- IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map,
- RequestType request_type,
- ServiceWorkerMetrics::EventType event_type,
- base::TimeTicks expiration,
- TimeoutBehavior timeout_behavior);
+ void RecordStartWorkerResult(ServiceWorkerMetrics::EventType purpose,
+ Status prestart_status,
+ int trace_id,
+ bool is_browser_startup_complete,
+ ServiceWorkerStatusCode status);
bool MaybeTimeOutRequest(const RequestInfo& info);
void SetAllRequestExpirations(const base::TimeTicks& expiration);
@@ -682,6 +613,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
const GURL script_url_;
const GURL scope_;
std::vector<GURL> foreign_fetch_scopes_;
+ std::vector<url::Origin> foreign_fetch_origins_;
Status status_ = NEW;
scoped_ptr<EmbeddedWorkerInstance> embedded_worker_;
@@ -691,12 +623,6 @@ class CONTENT_EXPORT ServiceWorkerVersion
// Message callbacks. (Update HasInflightRequests() too when you update this
// list.)
- IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer> activate_requests_;
- IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer> install_requests_;
- IDMap<PendingRequest<FetchCallback>, IDMapOwnPointer> fetch_requests_;
- IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer>
- notification_click_requests_;
- IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer> push_requests_;
IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer> custom_requests_;
// Stores all open connections to mojo services. Maps the service name to
@@ -722,7 +648,8 @@ class CONTENT_EXPORT ServiceWorkerVersion
base::TimeTicks idle_time_;
// Holds the time that the outstanding StartWorker() request started.
base::TimeTicks start_time_;
- // Holds the time the worker entered STOPPING status.
+ // Holds the time the worker entered STOPPING status. This is also used as a
+ // trace event id.
base::TimeTicks stop_time_;
// Holds the time the worker was detected as stale and needs updating. We try
// to update once the worker stops, but will also update if it stays alive too
@@ -739,15 +666,13 @@ class CONTENT_EXPORT ServiceWorkerVersion
bool skip_waiting_ = false;
bool skip_recording_startup_time_ = false;
bool force_bypass_cache_for_scripts_ = false;
- bool skip_script_comparison_ = false;
+ bool pause_after_download_ = false;
bool is_update_scheduled_ = false;
bool in_dtor_ = false;
std::vector<int> pending_skip_waiting_requests_;
scoped_ptr<net::HttpResponseInfo> main_script_http_info_;
- // The status when StartWorker was invoked. Used for UMA.
- Status prestart_status_ = NEW;
// If not OK, the reason that StartWorker failed. Used for
// running |start_callbacks_|.
ServiceWorkerStatusCode start_worker_status_ = SERVICE_WORKER_OK;
@@ -804,10 +729,18 @@ void ServiceWorkerVersion::DispatchEvent(int request_id,
} else {
request->listener.reset(
new EventResponseHandler<ResponseMessage, ResponseCallbackType>(
- embedded_worker(), request_id, callback));
+ embedded_worker()->AsWeakPtr(), request_id, callback));
}
}
+template <typename ResponseMessage>
+void ServiceWorkerVersion::DispatchSimpleEvent(int request_id,
+ const IPC::Message& message) {
+ DispatchEvent<ResponseMessage>(
+ request_id, message,
+ base::Bind(&ServiceWorkerVersion::OnSimpleEventResponse, this));
+}
+
template <typename ResponseMessage, typename CallbackType>
bool ServiceWorkerVersion::EventResponseHandler<ResponseMessage, CallbackType>::
OnMessageReceived(const IPC::Message& message) {
@@ -818,12 +751,16 @@ bool ServiceWorkerVersion::EventResponseHandler<ResponseMessage, CallbackType>::
if (!result || received_request_id != request_id_)
return false;
+ CallbackType protect(callback_);
// Essentially same code as what IPC_MESSAGE_FORWARD expands to.
void* param = nullptr;
if (!ResponseMessage::Dispatch(&message, &callback_, this, param,
&CallbackType::Run))
message.set_dispatch_error();
+ // At this point |this| can have been deleted, so don't do anything other
+ // than returning.
+
return true;
}
diff --git a/chromium/content/browser/service_worker/service_worker_version_unittest.cc b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
index f3d1aeb8f70..49a86ea1f85 100644
--- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
@@ -33,6 +33,12 @@ IPC_MESSAGE_ROUTED1(TestMsg_MessageFromWorker, int)
IPC_MESSAGE_CONTROL1(TestMsg_TestEvent, int)
IPC_MESSAGE_ROUTED2(TestMsg_TestEventResult, int, std::string)
+IPC_MESSAGE_ROUTED2(TestMsg_TestSimpleEventResult,
+ int,
+ blink::WebServiceWorkerEventResult)
+
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebServiceWorkerEventResult,
+ blink::WebServiceWorkerEventResultLast)
// ---------------------------------------------------------------------------
@@ -74,6 +80,13 @@ class MessageReceiver : public EmbeddedWorkerTestHelper {
new TestMsg_TestEventResult(embedded_worker_id, request_id, reply));
}
+ void SimulateSendSimpleEventResult(int embedded_worker_id,
+ int request_id,
+ blink::WebServiceWorkerEventResult reply) {
+ SimulateSend(new TestMsg_TestSimpleEventResult(embedded_worker_id,
+ request_id, reply));
+ }
+
private:
void OnMessage() {
// Do nothing.
@@ -94,13 +107,6 @@ void ObserveStatusChanges(ServiceWorkerVersion* version,
base::Bind(&ObserveStatusChanges, base::Unretained(version), statuses));
}
-void ReceiveFetchResult(ServiceWorkerStatusCode* status,
- ServiceWorkerStatusCode actual_status,
- ServiceWorkerFetchEventResult actual_result,
- const ServiceWorkerResponse& response) {
- *status = actual_status;
-}
-
void ReceiveTestEventResult(int* request_id,
std::string* data,
const base::Closure& callback,
@@ -156,9 +162,9 @@ base::Time GetYesterday() {
base::TimeDelta::FromSeconds(1);
}
-class TestMojoServiceImpl : public TestMojoService {
+class TestMojoServiceImpl : public mojom::TestMojoService {
public:
- static void Create(mojo::InterfaceRequest<TestMojoService> request) {
+ static void Create(mojo::InterfaceRequest<mojom::TestMojoService> request) {
new TestMojoServiceImpl(std::move(request));
}
@@ -166,15 +172,16 @@ class TestMojoServiceImpl : public TestMojoService {
callback.Run();
}
- void GetRequestorURL(const GetRequestorURLCallback& callback) override {
+ void GetRequestorName(const GetRequestorNameCallback& callback) override {
callback.Run(mojo::String(""));
}
private:
- explicit TestMojoServiceImpl(mojo::InterfaceRequest<TestMojoService> request)
+ explicit TestMojoServiceImpl(
+ mojo::InterfaceRequest<mojom::TestMojoService> request)
: binding_(this, std::move(request)) {}
- mojo::StrongBinding<TestMojoService> binding_;
+ mojo::StrongBinding<mojom::TestMojoService> binding_;
};
} // namespace
@@ -240,6 +247,29 @@ class ServiceWorkerVersionTest : public testing::Test {
helper_.reset();
}
+ void SimulateDispatchEvent(ServiceWorkerMetrics::EventType event_type) {
+ ServiceWorkerStatusCode status =
+ SERVICE_WORKER_ERROR_MAX_VALUE; // dummy value
+
+ // Make sure worker is running.
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner);
+ version_->RunAfterStartWorker(event_type, runner->QuitClosure(),
+ CreateReceiverOnCurrentThread(&status));
+ runner->Run();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+
+ // Start request, as if an event is being dispatched.
+ int request_id = version_->StartRequest(
+ event_type, CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // And finish request, as if a response to the event was received.
+ EXPECT_TRUE(version_->FinishRequest(request_id, true));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_MAX_VALUE, status);
+ }
+
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<MessageReceiver> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
@@ -256,14 +286,31 @@ class MessageReceiverDisallowStart : public MessageReceiver {
: MessageReceiver() {}
~MessageReceiverDisallowStart() override {}
+ enum class StartMode { STALL, FAIL, SUCCEED };
+
void OnStartWorker(int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
- const GURL& script_url) override {
- // Do nothing.
+ const GURL& script_url,
+ bool pause_after_download) override {
+ switch (mode_) {
+ case StartMode::STALL:
+ break; // Do nothing.
+ case StartMode::FAIL:
+ OnStopWorker(embedded_worker_id);
+ break;
+ case StartMode::SUCCEED:
+ MessageReceiver::OnStartWorker(embedded_worker_id,
+ service_worker_version_id, scope,
+ script_url, pause_after_download);
+ break;
+ }
}
+ void set_start_mode(StartMode mode) { mode_ = mode; }
+
private:
+ StartMode mode_ = StartMode::STALL;
DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowStart);
};
@@ -272,6 +319,12 @@ class ServiceWorkerFailToStartTest : public ServiceWorkerVersionTest {
ServiceWorkerFailToStartTest()
: ServiceWorkerVersionTest() {}
+ void set_start_mode(MessageReceiverDisallowStart::StartMode mode) {
+ MessageReceiverDisallowStart* helper =
+ static_cast<MessageReceiverDisallowStart*>(helper_.get());
+ helper->set_start_mode(mode);
+ }
+
scoped_ptr<MessageReceiver> GetMessageReceiver() override {
return make_scoped_ptr(new MessageReceiverDisallowStart());
}
@@ -305,33 +358,6 @@ class ServiceWorkerStallInStoppingTest : public ServiceWorkerVersionTest {
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerStallInStoppingTest);
};
-class MessageReceiverDisallowFetch : public MessageReceiver {
- public:
- MessageReceiverDisallowFetch() : MessageReceiver() {}
- ~MessageReceiverDisallowFetch() override {}
-
- void OnFetchEvent(int embedded_worker_id,
- int request_id,
- const ServiceWorkerFetchRequest& request) override {
- // Do nothing.
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowFetch);
-};
-
-class ServiceWorkerWaitForeverInFetchTest : public ServiceWorkerVersionTest {
- protected:
- ServiceWorkerWaitForeverInFetchTest() : ServiceWorkerVersionTest() {}
-
- scoped_ptr<MessageReceiver> GetMessageReceiver() override {
- return make_scoped_ptr(new MessageReceiverDisallowFetch());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWaitForeverInFetchTest);
-};
-
class MessageReceiverMojoTestService : public MessageReceiver {
public:
MessageReceiverMojoTestService() : MessageReceiver() {}
@@ -362,15 +388,18 @@ TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
ServiceWorkerStatusCode status1 = SERVICE_WORKER_ERROR_FAILED;
ServiceWorkerStatusCode status2 = SERVICE_WORKER_ERROR_FAILED;
ServiceWorkerStatusCode status3 = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status1));
- version_->StartWorker(CreateReceiverOnCurrentThread(&status2));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status1));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status2));
EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
// Call StartWorker() after it's started.
- version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status3));
base::RunLoop().RunUntilIdle();
// All should just succeed.
@@ -397,7 +426,8 @@ TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
status2 = SERVICE_WORKER_ERROR_FAILED;
status3 = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status1));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status1));
EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
base::RunLoop().RunUntilIdle();
@@ -408,7 +438,8 @@ TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
version_->StopWorker(CreateReceiverOnCurrentThread(&status2));
// And try calling StartWorker while StopWorker is in queue.
- version_->StartWorker(CreateReceiverOnCurrentThread(&status3));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status3));
EXPECT_EQ(ServiceWorkerVersion::STOPPING, version_->running_status());
base::RunLoop().RunUntilIdle();
@@ -424,27 +455,18 @@ TEST_F(ServiceWorkerVersionTest, DispatchEventToStoppedWorker) {
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
// Dispatch an event without starting the worker.
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
- version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
// The worker should be now started.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
// Stop the worker, and then dispatch an event immediately after that.
- status = SERVICE_WORKER_ERROR_FAILED;
ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
- version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
- // Dispatch an event should return SERVICE_WORKER_OK since the worker
- // should have been restarted to dispatch the event.
- EXPECT_EQ(SERVICE_WORKER_OK, status);
-
// The worker should be now started again.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
}
@@ -452,7 +474,8 @@ TEST_F(ServiceWorkerVersionTest, DispatchEventToStoppedWorker) {
TEST_F(ServiceWorkerVersionTest, StartUnregisteredButStillLiveWorker) {
// Start the worker.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -476,14 +499,7 @@ TEST_F(ServiceWorkerVersionTest, StartUnregisteredButStillLiveWorker) {
// Dispatch an event on the unregistered and stopped but still live worker.
status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
- base::Bind(&base::DoNothing),
- base::Bind(&ReceiveFetchResult, &status));
- base::RunLoop().RunUntilIdle();
-
- // Dispatch an event should return SERVICE_WORKER_OK since the worker
- // should have been restarted to dispatch the event.
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME);
// The worker should be now started again.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -492,7 +508,8 @@ TEST_F(ServiceWorkerVersionTest, StartUnregisteredButStillLiveWorker) {
TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
// Start worker.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -515,39 +532,36 @@ TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
- // Dispatch an install event.
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
-
// Wait for the completion.
bool status_change_called = false;
version_->RegisterStatusChangeCallback(
base::Bind(&VerifyCalled, &status_change_called));
- base::RunLoop().RunUntilIdle();
+ // Dispatch an install event.
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
// Version's status must not have changed during installation.
- EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_FALSE(status_change_called);
EXPECT_EQ(ServiceWorkerVersion::INSTALLING, version_->status());
}
TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
- version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ // TODO(mek): This test (and the one above for the install event) made more
+ // sense back when ServiceWorkerVersion was responsible for updating the
+ // status. Now a better version of this test should probably be added to
+ // ServiceWorkerRegistrationTest instead.
- // Dispatch an activate event.
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
// Wait for the completion.
bool status_change_called = false;
version_->RegisterStatusChangeCallback(
base::Bind(&VerifyCalled, &status_change_called));
- base::RunLoop().RunUntilIdle();
+ // Dispatch an activate event.
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::ACTIVATE);
// Version's status must not have changed during activation.
- EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_FALSE(status_change_called);
EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
}
@@ -557,8 +571,8 @@ TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
// Repeatedly observe status changes (the callback re-registers itself).
std::vector<ServiceWorkerVersion::Status> statuses;
- version_->RegisterStatusChangeCallback(
- base::Bind(&ObserveStatusChanges, version_, &statuses));
+ version_->RegisterStatusChangeCallback(base::Bind(
+ &ObserveStatusChanges, base::RetainedRef(version_), &statuses));
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->SetStatus(ServiceWorkerVersion::INSTALLED);
@@ -586,7 +600,8 @@ TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
// Verify the timer is running after the worker is started.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_TRUE(version_->timeout_timer_.IsRunning());
@@ -601,7 +616,8 @@ TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_TRUE(version_->timeout_timer_.IsRunning());
@@ -619,15 +635,9 @@ TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
EXPECT_LT(idle_time, version_->idle_time_);
// Completing an event resets the idle time.
- status = SERVICE_WORKER_ERROR_FAILED;
version_->idle_time_ -= kOneSecond;
idle_time = version_->idle_time_;
- version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
- base::Bind(&base::DoNothing),
- base::Bind(&ReceiveFetchResult, &status));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME);
EXPECT_LT(idle_time, version_->idle_time_);
// Starting and finishing a request resets the idle time.
@@ -636,7 +646,7 @@ TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
int request_id =
version_->StartRequest(ServiceWorkerMetrics::EventType::SYNC,
CreateReceiverOnCurrentThread(&status));
- EXPECT_TRUE(version_->FinishRequest(request_id));
+ EXPECT_TRUE(version_->FinishRequest(request_id, true));
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_LT(idle_time, version_->idle_time_);
@@ -658,7 +668,8 @@ TEST_F(ServiceWorkerVersionTest, IdleTimeout) {
TEST_F(ServiceWorkerVersionTest, SetDevToolsAttached) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
ASSERT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
@@ -690,7 +701,8 @@ TEST_F(ServiceWorkerVersionTest, StoppingBeforeDestruct) {
version_->AddListener(&listener);
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -702,31 +714,22 @@ TEST_F(ServiceWorkerVersionTest, StoppingBeforeDestruct) {
// Test that update isn't triggered for a non-stale worker.
TEST_F(ServiceWorkerVersionTest, StaleUpdate_FreshWorker) {
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
registration_->SetActiveVersion(version_);
registration_->set_last_update_check(base::Time::Now());
- version_->DispatchPushEvent(CreateReceiverOnCurrentThread(&status),
- std::string());
- base::RunLoop().RunUntilIdle();
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
- EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_TRUE(version_->stale_time_.is_null());
EXPECT_FALSE(version_->update_timer_.IsRunning());
}
// Test that update isn't triggered for a non-active worker.
TEST_F(ServiceWorkerVersionTest, StaleUpdate_NonActiveWorker) {
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
registration_->SetInstallingVersion(version_);
registration_->set_last_update_check(GetYesterday());
- version_->DispatchInstallEvent(CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
- EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_TRUE(version_->stale_time_.is_null());
EXPECT_FALSE(version_->update_timer_.IsRunning());
}
@@ -739,10 +742,7 @@ TEST_F(ServiceWorkerVersionTest, StaleUpdate_StartWorker) {
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
registration_->SetActiveVersion(version_);
registration_->set_last_update_check(GetYesterday());
- version_->DispatchPushEvent(CreateReceiverOnCurrentThread(&status),
- std::string());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
EXPECT_FALSE(version_->stale_time_.is_null());
EXPECT_FALSE(version_->update_timer_.IsRunning());
@@ -756,16 +756,11 @@ TEST_F(ServiceWorkerVersionTest, StaleUpdate_StartWorker) {
// Test that staleness is detected on a running worker.
TEST_F(ServiceWorkerVersionTest, StaleUpdate_RunningWorker) {
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-
// Start a fresh worker.
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
registration_->SetActiveVersion(version_);
registration_->set_last_update_check(base::Time::Now());
- version_->DispatchPushEvent(CreateReceiverOnCurrentThread(&status),
- std::string());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_OK, status);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
EXPECT_TRUE(version_->stale_time_.is_null());
// Simulate it running for a day. It will be marked stale.
@@ -798,10 +793,13 @@ TEST_F(ServiceWorkerVersionTest, StaleUpdate_DoNotDeferTimer) {
version_->stale_time_ = stale_time;
// Stale time is not deferred.
- version_->DispatchPushEvent(
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback), std::string());
- version_->DispatchPushEvent(
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback), std::string());
+ version_->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::UNKNOWN, base::Bind(&base::DoNothing),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ version_->RunAfterStartWorker(
+ ServiceWorkerMetrics::EventType::UNKNOWN, base::Bind(&base::DoNothing),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(stale_time, version_->stale_time_);
// Timeout triggers the update.
@@ -811,24 +809,26 @@ TEST_F(ServiceWorkerVersionTest, StaleUpdate_DoNotDeferTimer) {
// Update timer is not deferred.
base::TimeTicks run_time = version_->update_timer_.desired_run_time();
- version_->DispatchPushEvent(
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback), std::string());
- version_->DispatchPushEvent(
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback), std::string());
- version_->DispatchPushEvent(
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback), std::string());
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(version_->stale_time_.is_null());
EXPECT_EQ(run_time, version_->update_timer_.desired_run_time());
}
-TEST_F(ServiceWorkerWaitForeverInFetchTest, RequestTimeout) {
+TEST_F(ServiceWorkerVersionTest, RequestTimeout) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
-
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
- base::Bind(&base::DoNothing),
- base::Bind(&ReceiveFetchResult, &status));
+
+ version_->StartWorker(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ base::RunLoop().RunUntilIdle();
+
+ // Create a request.
+ int request_id =
+ version_->StartRequest(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
// Callback has not completed yet.
@@ -842,13 +842,15 @@ TEST_F(ServiceWorkerWaitForeverInFetchTest, RequestTimeout) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
+ EXPECT_FALSE(version_->FinishRequest(request_id, true));
}
TEST_F(ServiceWorkerVersionTest, RequestCustomizedTimeout) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
base::RunLoop().RunUntilIdle();
// Create a request that should expire Now().
@@ -863,7 +865,7 @@ TEST_F(ServiceWorkerVersionTest, RequestCustomizedTimeout) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
- EXPECT_FALSE(version_->FinishRequest(request_id));
+ EXPECT_FALSE(version_->FinishRequest(request_id, true));
// CONTINUE_ON_TIMEOUT timeouts don't stop the service worker.
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -873,7 +875,8 @@ TEST_F(ServiceWorkerVersionTest, RequestCustomizedTimeoutKill) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
base::RunLoop().RunUntilIdle();
// Create a request that should expire Now().
@@ -888,28 +891,29 @@ TEST_F(ServiceWorkerVersionTest, RequestCustomizedTimeoutKill) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
- EXPECT_FALSE(version_->FinishRequest(request_id));
+ EXPECT_FALSE(version_->FinishRequest(request_id, true));
// KILL_ON_TIMEOUT timeouts should stop the service worker.
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
}
-TEST_F(ServiceWorkerWaitForeverInFetchTest, MixedRequestTimeouts) {
+TEST_F(ServiceWorkerVersionTest, MixedRequestTimeouts) {
ServiceWorkerStatusCode sync_status =
SERVICE_WORKER_ERROR_NETWORK; // dummy value
ServiceWorkerStatusCode fetch_status =
SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
base::RunLoop().RunUntilIdle();
// Create a fetch request that should expire sometime later.
- version_->DispatchFetchEvent(ServiceWorkerFetchRequest(),
- base::Bind(&base::DoNothing),
- base::Bind(&ReceiveFetchResult, &fetch_status));
+ int fetch_request_id =
+ version_->StartRequest(ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME,
+ CreateReceiverOnCurrentThread(&fetch_status));
// Create a request that should expire Now().
- int request_id = version_->StartRequestWithCustomTimeout(
+ int sync_request_id = version_->StartRequestWithCustomTimeout(
ServiceWorkerMetrics::EventType::SYNC,
CreateReceiverOnCurrentThread(&sync_status), base::TimeDelta(),
ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
@@ -927,7 +931,7 @@ TEST_F(ServiceWorkerWaitForeverInFetchTest, MixedRequestTimeouts) {
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
// Gracefully handle the sync event finishing after the timeout.
- EXPECT_FALSE(version_->FinishRequest(request_id));
+ EXPECT_FALSE(version_->FinishRequest(sync_request_id, true));
// Verify that the fetch times out later.
version_->SetAllRequestExpirations(base::TimeTicks::Now());
@@ -935,43 +939,17 @@ TEST_F(ServiceWorkerWaitForeverInFetchTest, MixedRequestTimeouts) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, fetch_status);
- // Other timeouts do stop the service worker.
- EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
-}
-
-TEST_F(ServiceWorkerVersionTest, RequestTimeout) {
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
-
- version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
- base::RunLoop().RunUntilIdle();
- int request_id =
- version_->StartRequest(ServiceWorkerMetrics::EventType::SYNC,
- CreateReceiverOnCurrentThread(&status));
- base::RunLoop().RunUntilIdle();
-
- // Callback has not completed yet.
- EXPECT_EQ(SERVICE_WORKER_ERROR_NETWORK, status);
- EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+ // Fetch request should no longer exist.
+ EXPECT_FALSE(version_->FinishRequest(fetch_request_id, true));
- // Simulate timeout.
- EXPECT_TRUE(version_->timeout_timer_.IsRunning());
- version_->SetAllRequestExpirations(
- base::TimeTicks::Now() -
- base::TimeDelta::FromMinutes(
- ServiceWorkerVersion::kRequestTimeoutMinutes + 1));
- version_->timeout_timer_.user_task().Run();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
+ // Other timeouts do stop the service worker.
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
-
- EXPECT_FALSE(version_->FinishRequest(request_id));
}
TEST_F(ServiceWorkerFailToStartTest, RendererCrash) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
- version_->StartWorker(
- CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
// Callback has not completed yet.
@@ -994,10 +972,9 @@ TEST_F(ServiceWorkerFailToStartTest, RendererCrash) {
TEST_F(ServiceWorkerFailToStartTest, Timeout) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
- // We could just call StartWorker but make it interesting and test
- // starting the worker as part of dispatching an event.
- version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
- version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
+ // Start starting the worker.
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
// Callback has not completed yet.
@@ -1021,7 +998,8 @@ TEST_F(ServiceWorkerFailToStartTest, Timeout) {
TEST_F(ServiceWorkerStallInStoppingTest, DetachThenStart) {
// Start a worker.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1050,7 +1028,8 @@ TEST_F(ServiceWorkerStallInStoppingTest, DetachThenStart) {
// Try to start the worker again. It should work.
status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1067,7 +1046,8 @@ TEST_F(ServiceWorkerStallInStoppingTest, DetachThenStart) {
TEST_F(ServiceWorkerStallInStoppingTest, DetachThenRestart) {
// Start a worker.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1079,7 +1059,8 @@ TEST_F(ServiceWorkerStallInStoppingTest, DetachThenRestart) {
// Worker is now stalled in stopping. Add a start worker requset.
ServiceWorkerStatusCode start_status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&start_status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&start_status));
// Simulate timeout. The worker should stop and get restarted.
EXPECT_TRUE(version_->timeout_timer_.IsRunning());
@@ -1098,56 +1079,84 @@ TEST_F(ServiceWorkerVersionTest, RegisterForeignFetchScopes) {
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
// Start a worker.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
EXPECT_EQ(0, helper_->mock_render_process_host()->bad_msg_count());
- // Invalid URL, should kill worker (but in tests will only increase bad
+ GURL valid_scope_1("http://www.example.com/test/subscope");
+ GURL valid_scope_2("http://www.example.com/test/othersubscope");
+ std::vector<GURL> valid_scopes;
+ valid_scopes.push_back(valid_scope_1);
+ valid_scopes.push_back(valid_scope_2);
+
+ std::vector<url::Origin> all_origins;
+ url::Origin valid_origin(GURL("https://chromium.org/"));
+ std::vector<url::Origin> valid_origin_list(1, valid_origin);
+
+ // Invalid subscope, should kill worker (but in tests will only increase bad
// message count).
- version_->OnRegisterForeignFetchScopes(std::vector<GURL>(1, GURL()));
+ version_->OnRegisterForeignFetchScopes(std::vector<GURL>(1, GURL()),
+ valid_origin_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, helper_->mock_render_process_host()->bad_msg_count());
EXPECT_EQ(0u, version_->foreign_fetch_scopes_.size());
+ EXPECT_EQ(0u, version_->foreign_fetch_origins_.size());
- // URL outside the scope of the worker.
+ // Subscope outside the scope of the worker.
version_->OnRegisterForeignFetchScopes(
- std::vector<GURL>(1, GURL("http://www.example.com/wrong")));
+ std::vector<GURL>(1, GURL("http://www.example.com/wrong")),
+ valid_origin_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, helper_->mock_render_process_host()->bad_msg_count());
EXPECT_EQ(0u, version_->foreign_fetch_scopes_.size());
+ EXPECT_EQ(0u, version_->foreign_fetch_origins_.size());
- // URL on wrong origin.
+ // Subscope on wrong origin.
version_->OnRegisterForeignFetchScopes(
- std::vector<GURL>(1, GURL("http://example.com/test/")));
+ std::vector<GURL>(1, GURL("http://example.com/test/")),
+ valid_origin_list);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, helper_->mock_render_process_host()->bad_msg_count());
EXPECT_EQ(0u, version_->foreign_fetch_scopes_.size());
+ EXPECT_EQ(0u, version_->foreign_fetch_origins_.size());
- // Valid URL 1.
- GURL valid_scope_1("http://www.example.com/test/subscope");
- version_->OnRegisterForeignFetchScopes(std::vector<GURL>(1, valid_scope_1));
+ // Invalid origin.
+ version_->OnRegisterForeignFetchScopes(
+ valid_scopes, std::vector<url::Origin>(1, url::Origin()));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(3, helper_->mock_render_process_host()->bad_msg_count());
+ EXPECT_EQ(4, helper_->mock_render_process_host()->bad_msg_count());
+ EXPECT_EQ(0u, version_->foreign_fetch_scopes_.size());
+ EXPECT_EQ(0u, version_->foreign_fetch_origins_.size());
+
+ // Valid subscope, no origins.
+ version_->OnRegisterForeignFetchScopes(std::vector<GURL>(1, valid_scope_1),
+ all_origins);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(4, helper_->mock_render_process_host()->bad_msg_count());
EXPECT_EQ(1u, version_->foreign_fetch_scopes_.size());
EXPECT_EQ(valid_scope_1, version_->foreign_fetch_scopes_[0]);
+ EXPECT_EQ(0u, version_->foreign_fetch_origins_.size());
- // Valid URL 2.
- GURL valid_scope_2("http://www.example.com/test/subscope");
- version_->OnRegisterForeignFetchScopes(std::vector<GURL>(1, valid_scope_2));
+ // Valid subscope, explicit origins.
+ version_->OnRegisterForeignFetchScopes(valid_scopes, valid_origin_list);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(3, helper_->mock_render_process_host()->bad_msg_count());
+ EXPECT_EQ(4, helper_->mock_render_process_host()->bad_msg_count());
EXPECT_EQ(2u, version_->foreign_fetch_scopes_.size());
EXPECT_EQ(valid_scope_1, version_->foreign_fetch_scopes_[0]);
EXPECT_EQ(valid_scope_2, version_->foreign_fetch_scopes_[1]);
+ EXPECT_EQ(1u, version_->foreign_fetch_origins_.size());
+ EXPECT_EQ(valid_origin, version_->foreign_fetch_origins_[0]);
}
TEST_F(ServiceWorkerVersionTest, RendererCrashDuringEvent) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1173,14 +1182,15 @@ TEST_F(ServiceWorkerVersionTest, RendererCrashDuringEvent) {
EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
// Request already failed, calling finsh should return false.
- EXPECT_FALSE(version_->FinishRequest(request_id));
+ EXPECT_FALSE(version_->FinishRequest(request_id, true));
}
TEST_F(ServiceWorkerVersionWithMojoTest, MojoService) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1189,22 +1199,23 @@ TEST_F(ServiceWorkerVersionWithMojoTest, MojoService) {
int request_id = version_->StartRequest(
ServiceWorkerMetrics::EventType::SYNC,
CreateReceiverOnCurrentThread(&status, runner->QuitClosure()));
- base::WeakPtr<TestMojoService> service =
- version_->GetMojoServiceForRequest<TestMojoService>(request_id);
+ base::WeakPtr<mojom::TestMojoService> service =
+ version_->GetMojoServiceForRequest<mojom::TestMojoService>(request_id);
service->DoSomething(runner->QuitClosure());
runner->Run();
// Mojo service does exist in worker, so error callback should not have been
// called and FinishRequest should return true.
EXPECT_EQ(SERVICE_WORKER_OK, status);
- EXPECT_TRUE(version_->FinishRequest(request_id));
+ EXPECT_TRUE(version_->FinishRequest(request_id, true));
}
TEST_F(ServiceWorkerVersionTest, NonExistentMojoService) {
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1213,15 +1224,15 @@ TEST_F(ServiceWorkerVersionTest, NonExistentMojoService) {
int request_id = version_->StartRequest(
ServiceWorkerMetrics::EventType::SYNC,
CreateReceiverOnCurrentThread(&status, runner->QuitClosure()));
- base::WeakPtr<TestMojoService> service =
- version_->GetMojoServiceForRequest<TestMojoService>(request_id);
+ base::WeakPtr<mojom::TestMojoService> service =
+ version_->GetMojoServiceForRequest<mojom::TestMojoService>(request_id);
service->DoSomething(runner->QuitClosure());
runner->Run();
// Mojo service doesn't exist in worker, so error callback should have been
// called and FinishRequest should return false.
EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, status);
- EXPECT_FALSE(version_->FinishRequest(request_id));
+ EXPECT_FALSE(version_->FinishRequest(request_id, true));
}
TEST_F(ServiceWorkerVersionTest, DispatchEvent) {
@@ -1229,7 +1240,8 @@ TEST_F(ServiceWorkerVersionTest, DispatchEvent) {
// Activate and start worker.
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1265,7 +1277,65 @@ TEST_F(ServiceWorkerVersionTest, DispatchEvent) {
// Should not have timed out, so error callback should not have been
// called and FinishRequest should return true.
EXPECT_EQ(SERVICE_WORKER_OK, status);
- EXPECT_TRUE(version_->FinishRequest(request_id));
+ EXPECT_TRUE(version_->FinishRequest(request_id, true));
+}
+
+TEST_F(ServiceWorkerFailToStartTest, FailingWorkerUsesNewRendererProcess) {
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+
+ helper_->SimulateAddProcessToPattern(pattern_,
+ helper_->new_render_process_id());
+ ServiceWorkerContextCore* context = helper_->context();
+ int64_t id = version_->version_id();
+
+ // Start once. It should choose the "existing process".
+ set_start_mode(MessageReceiverDisallowStart::StartMode::SUCCEED);
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(helper_->mock_render_process_id(),
+ version_->embedded_worker()->process_id());
+ version_->StopWorker(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Fail once.
+ set_start_mode(MessageReceiverDisallowStart::StartMode::FAIL);
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
+ EXPECT_EQ(1, context->GetVersionFailureCount(id));
+
+ // Fail again.
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
+ EXPECT_EQ(2, context->GetVersionFailureCount(id));
+
+ // Succeed. It should choose the "new process".
+ set_start_mode(MessageReceiverDisallowStart::StartMode::SUCCEED);
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(helper_->new_render_process_id(),
+ version_->embedded_worker()->process_id());
+ EXPECT_EQ(0, context->GetVersionFailureCount(id));
+ version_->StopWorker(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Start again. It should choose the "existing process" again as we no longer
+ // force creation of a new process.
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(helper_->mock_render_process_id(),
+ version_->embedded_worker()->process_id());
+ version_->StopWorker(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
}
TEST_F(ServiceWorkerVersionTest, DispatchConcurrentEvent) {
@@ -1273,7 +1343,8 @@ TEST_F(ServiceWorkerVersionTest, DispatchConcurrentEvent) {
// Activate and start worker.
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
- version_->StartWorker(CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
@@ -1328,7 +1399,7 @@ TEST_F(ServiceWorkerVersionTest, DispatchConcurrentEvent) {
EXPECT_EQ(request_id2, received_request_id2);
EXPECT_EQ(reply2, received_data2);
EXPECT_EQ(SERVICE_WORKER_OK, status2);
- EXPECT_TRUE(version_->FinishRequest(request_id2));
+ EXPECT_TRUE(version_->FinishRequest(request_id2, true));
// Reply to first event.
std::string reply1("hello world");
@@ -1341,7 +1412,81 @@ TEST_F(ServiceWorkerVersionTest, DispatchConcurrentEvent) {
EXPECT_EQ(request_id2, received_request_id2);
EXPECT_EQ(reply1, received_data1);
EXPECT_EQ(SERVICE_WORKER_OK, status1);
- EXPECT_TRUE(version_->FinishRequest(request_id1));
+ EXPECT_TRUE(version_->FinishRequest(request_id1, true));
+}
+
+TEST_F(ServiceWorkerVersionTest, DispatchSimpleEvent_Completed) {
+ ServiceWorkerStatusCode status =
+ SERVICE_WORKER_ERROR_MAX_VALUE; // dummy value
+
+ // Activate and start worker.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+
+ // Start request and dispatch test event.
+ status = SERVICE_WORKER_ERROR_MAX_VALUE; // dummy value
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner);
+ int request_id = version_->StartRequest(
+ ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status, runner->QuitClosure()));
+ version_->DispatchSimpleEvent<TestMsg_TestSimpleEventResult>(
+ request_id, TestMsg_TestEvent(request_id));
+
+ // Verify event got dispatched to worker.
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(1u, helper_->inner_ipc_sink()->message_count());
+ const IPC::Message* msg = helper_->inner_ipc_sink()->GetMessageAt(0);
+ EXPECT_EQ(TestMsg_TestEvent::ID, msg->type());
+
+ // Simulate sending reply to event.
+ helper_->SimulateSendSimpleEventResult(
+ version_->embedded_worker()->embedded_worker_id(), request_id,
+ blink::WebServiceWorkerEventResultCompleted);
+ runner->Run();
+
+ // Verify callback was called with correct status.
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+}
+
+TEST_F(ServiceWorkerVersionTest, DispatchSimpleEvent_Rejected) {
+ ServiceWorkerStatusCode status =
+ SERVICE_WORKER_ERROR_MAX_VALUE; // dummy value
+
+ // Activate and start worker.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->StartWorker(ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
+
+ // Start request and dispatch test event.
+ status = SERVICE_WORKER_ERROR_MAX_VALUE; // dummy value
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner);
+ int request_id = version_->StartRequest(
+ ServiceWorkerMetrics::EventType::SYNC,
+ CreateReceiverOnCurrentThread(&status, runner->QuitClosure()));
+ version_->DispatchSimpleEvent<TestMsg_TestSimpleEventResult>(
+ request_id, TestMsg_TestEvent(request_id));
+
+ // Verify event got dispatched to worker.
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(1u, helper_->inner_ipc_sink()->message_count());
+ const IPC::Message* msg = helper_->inner_ipc_sink()->GetMessageAt(0);
+ EXPECT_EQ(TestMsg_TestEvent::ID, msg->type());
+
+ // Simulate sending reply to event.
+ helper_->SimulateSendSimpleEventResult(
+ version_->embedded_worker()->embedded_worker_id(), request_id,
+ blink::WebServiceWorkerEventResultRejected);
+ runner->Run();
+
+ // Verify callback was called with correct status.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED, status);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
index f878812996b..96e9e8f6a71 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -13,6 +13,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
#include "content/browser/service_worker/service_worker_metrics.h"
+#include "content/common/net/url_request_service_worker_data.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "net/base/io_buffer.h"
@@ -41,17 +42,11 @@ const char kRedirectError[] =
"The script resource is behind a redirect, which is disallowed.";
const char kServiceWorkerAllowed[] = "Service-Worker-Allowed";
-// The net error code used when the job fails the update attempt because the new
-// script is byte-by-byte identical to the incumbent script. This error is shown
-// in DevTools and in netlog, so we want something obscure enough that it won't
-// conflict with a legitimate network error, and not too alarming if seen by
-// developers.
-// TODO(falken): Redesign this class so we don't have to fail at the network
-// stack layer just to cancel the update.
-const net::Error kIdenticalScriptError = net::ERR_FILE_EXISTS;
-
} // namespace
+const net::Error ServiceWorkerWriteToCacheJob::kIdenticalScriptError =
+ net::ERR_FILE_EXISTS;
+
ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
@@ -190,6 +185,8 @@ void ServiceWorkerWriteToCacheJob::InitNetRequest(
request()->first_party_for_cookies());
net_request_->set_initiator(request()->initiator());
net_request_->SetReferrer(request()->referrer());
+ net_request_->SetUserData(URLRequestServiceWorkerData::kUserDataKey,
+ new URLRequestServiceWorkerData());
if (extra_load_flags)
net_request_->SetLoadFlags(net_request_->load_flags() | extra_load_flags);
@@ -337,8 +334,10 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
version_->SetMainScriptHttpResponseInfo(net_request_->response_info());
}
- if (net_request_->response_info().network_accessed)
+ if (net_request_->response_info().network_accessed &&
+ !(net_request_->response_info().was_cached)) {
version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
+ }
http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
@@ -361,12 +360,10 @@ void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(net::Error error) {
NotifyStartError(net::URLRequestStatus::FromError(error));
return;
}
- SetStatus(net::URLRequestStatus());
NotifyHeadersComplete();
}
void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(net::Error error) {
- SetStatus(net::URLRequestStatus::FromError(error));
DCHECK_NE(net::ERR_IO_PENDING, error);
if (io_buffer_bytes_ == 0)
error = NotifyFinishedCaching(net::URLRequestStatus::FromError(error), "");
@@ -448,7 +445,6 @@ void ServiceWorkerWriteToCacheJob::NotifyStartErrorHelper(
net::URLRequestStatus reported_status = status;
std::string reported_status_message = status_message;
- SetStatus(reported_status);
NotifyStartError(reported_status);
}
@@ -469,8 +465,7 @@ net::Error ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
// exists.
if (status.status() == net::URLRequestStatus::SUCCESS &&
!cache_writer_->did_replace()) {
- result = kIdenticalScriptError;
- status = net::URLRequestStatus::FromError(result);
+ status = net::URLRequestStatus::FromError(kIdenticalScriptError);
version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
std::string());
@@ -486,7 +481,7 @@ net::Error ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
scoped_ptr<ServiceWorkerResponseReader>
ServiceWorkerWriteToCacheJob::CreateCacheResponseReader() {
if (incumbent_resource_id_ == kInvalidServiceWorkerResourceId ||
- version_->skip_script_comparison()) {
+ !version_->pause_after_download()) {
return nullptr;
}
return context_->storage()->CreateResponseReader(incumbent_resource_id_);
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.h b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.h
index 8cb483cb41c..314fcb2ad08 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.h
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.h
@@ -40,8 +40,9 @@ class ServiceWorkerVersions;
// incumbent script is detected. The incumbent script is progressively compared
// with the new script as it is read from network. Once a change is detected,
// everything that matched is copied to disk, and from then on the script is
-// written as it continues to be read from network. If the scripts were
-// identical, the job fails so the worker can be discarded.
+// written as it continues to be read from network. If the scripts are
+// identical, the resulting ServiceWorkerScriptCacheMap's main script status is
+// set to kIdenticalScriptError.
class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
: public net::URLRequestJob,
public net::URLRequest::Delegate {
@@ -55,6 +56,10 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
int64_t resource_id,
int64_t incumbent_resource_id);
+ // The error code used when update fails because the new
+ // script is byte-by-byte identical to the incumbent script.
+ const static net::Error kIdenticalScriptError;
+
private:
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateBefore24Hours);
@@ -62,6 +67,8 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
UpdateAfter24Hours);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
UpdateForceBypassCache);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ ServiceWorkerDataRequestAnnotation);
~ServiceWorkerWriteToCacheJob() override;
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index 43881d790d2..7b9873d2858 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -379,6 +379,7 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
scoped_refptr<ServiceWorkerVersion> new_version =
new ServiceWorkerVersion(registration_.get(), script_url_,
NextVersionId(), context()->AsWeakPtr());
+ new_version->set_pause_after_download(true);
CreateHostForVersion(helper_->mock_render_process_id(), provider_id,
new_version);
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.cc b/chromium/content/browser/shared_worker/shared_worker_host.cc
index 8aefff131ee..e98be02d575 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_host.cc
@@ -89,6 +89,7 @@ void SharedWorkerHost::Start(bool pause_on_start) {
params.name = instance_->name();
params.content_security_policy = instance_->content_security_policy();
params.security_policy_type = instance_->security_policy_type();
+ params.creation_address_space = instance_->creation_address_space();
params.pause_on_start = pause_on_start;
params.route_id = worker_route_id_;
Send(new WorkerProcessMsg_CreateWorker(params));
@@ -181,22 +182,6 @@ void SharedWorkerHost::WorkerConnected(int message_port_id) {
}
}
-void SharedWorkerHost::AllowDatabase(const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result) {
- if (!instance_)
- return;
- *result = GetContentClient()->browser()->AllowWorkerDatabase(
- url,
- name,
- display_name,
- estimated_size,
- instance_->resource_context(),
- GetRenderFrameIDsForWorker());
-}
-
void SharedWorkerHost::AllowFileSystem(const GURL& url,
scoped_ptr<IPC::Message> reply_msg) {
if (!instance_)
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.h b/chromium/content/browser/shared_worker/shared_worker_host.h
index 9fb9ca3550a..621c69bb93c 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.h
+++ b/chromium/content/browser/shared_worker/shared_worker_host.h
@@ -62,11 +62,6 @@ class SharedWorkerHost {
void WorkerScriptLoadFailed();
void WorkerConnected(int message_port_id);
void WorkerContextDestroyed();
- void AllowDatabase(const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result);
void AllowFileSystem(const GURL& url, scoped_ptr<IPC::Message> reply_msg);
void AllowIndexedDB(const GURL& url,
const base::string16& name,
diff --git a/chromium/content/browser/shared_worker/shared_worker_instance.cc b/chromium/content/browser/shared_worker/shared_worker_instance.cc
index caa3876e63d..282cf190515 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_instance.cc
@@ -13,6 +13,7 @@ SharedWorkerInstance::SharedWorkerInstance(
const base::string16& name,
const base::string16& content_security_policy,
blink::WebContentSecurityPolicyType security_policy_type,
+ blink::WebAddressSpace creation_address_space,
ResourceContext* resource_context,
const WorkerStoragePartitionId& partition_id,
blink::WebSharedWorkerCreationContextType creation_context_type)
@@ -20,6 +21,7 @@ SharedWorkerInstance::SharedWorkerInstance(
name_(name),
content_security_policy_(content_security_policy),
security_policy_type_(security_policy_type),
+ creation_address_space_(creation_address_space),
resource_context_(resource_context),
partition_id_(partition_id),
creation_context_type_(creation_context_type) {
@@ -31,6 +33,7 @@ SharedWorkerInstance::SharedWorkerInstance(const SharedWorkerInstance& other)
name_(other.name_),
content_security_policy_(other.content_security_policy_),
security_policy_type_(other.security_policy_type_),
+ creation_address_space_(other.creation_address_space_),
resource_context_(other.resource_context_),
partition_id_(other.partition_id_),
creation_context_type_(other.creation_context_type_) {}
diff --git a/chromium/content/browser/shared_worker/shared_worker_instance.h b/chromium/content/browser/shared_worker/shared_worker_instance.h
index 025da9b8008..947621e1261 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance.h
+++ b/chromium/content/browser/shared_worker/shared_worker_instance.h
@@ -9,6 +9,7 @@
#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebAddressSpace.h"
#include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h"
#include "url/gurl.h"
@@ -25,6 +26,7 @@ class CONTENT_EXPORT SharedWorkerInstance {
const base::string16& name,
const base::string16& content_security_policy,
blink::WebContentSecurityPolicyType security_policy_type,
+ blink::WebAddressSpace creation_address_space,
ResourceContext* resource_context,
const WorkerStoragePartitionId& partition_id,
blink::WebSharedWorkerCreationContextType creation_context_type);
@@ -52,6 +54,9 @@ class CONTENT_EXPORT SharedWorkerInstance {
blink::WebContentSecurityPolicyType security_policy_type() const {
return security_policy_type_;
}
+ blink::WebAddressSpace creation_address_space() const {
+ return creation_address_space_;
+ }
ResourceContext* resource_context() const {
return resource_context_;
}
@@ -65,6 +70,7 @@ class CONTENT_EXPORT SharedWorkerInstance {
const base::string16 name_;
const base::string16 content_security_policy_;
const blink::WebContentSecurityPolicyType security_policy_type_;
+ const blink::WebAddressSpace creation_address_space_;
ResourceContext* const resource_context_;
const WorkerStoragePartitionId partition_id_;
const blink::WebSharedWorkerCreationContextType creation_context_type_;
diff --git a/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc b/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc
index c78cb1fe0a5..9e773f71472 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc
@@ -49,7 +49,7 @@ class SharedWorkerInstanceTest : public testing::Test {
TEST_F(SharedWorkerInstanceTest, MatchesTest) {
SharedWorkerInstance instance1(
GURL("http://example.com/w.js"), base::string16(), base::string16(),
- blink::WebContentSecurityPolicyTypeReport,
+ blink::WebContentSecurityPolicyTypeReport, blink::WebAddressSpacePublic,
browser_context_->GetResourceContext(), partition_id_,
blink::WebSharedWorkerCreationContextTypeNonsecure);
EXPECT_TRUE(Matches(instance1, "http://example.com/w.js", ""));
@@ -64,8 +64,8 @@ TEST_F(SharedWorkerInstanceTest, MatchesTest) {
SharedWorkerInstance instance2(
GURL("http://example.com/w.js"), base::ASCIIToUTF16("name"),
base::string16(), blink::WebContentSecurityPolicyTypeReport,
- browser_context_->GetResourceContext(), partition_id_,
- blink::WebSharedWorkerCreationContextTypeNonsecure);
+ blink::WebAddressSpacePublic, browser_context_->GetResourceContext(),
+ partition_id_, blink::WebSharedWorkerCreationContextTypeNonsecure);
EXPECT_FALSE(Matches(instance2, "http://example.com/w.js", ""));
EXPECT_FALSE(Matches(instance2, "http://example.com/w2.js", ""));
EXPECT_FALSE(Matches(instance2, "http://example.net/w.js", ""));
@@ -80,4 +80,17 @@ TEST_F(SharedWorkerInstanceTest, MatchesTest) {
EXPECT_FALSE(Matches(instance2, "http://example.net/w2.js", "name2"));
}
+TEST_F(SharedWorkerInstanceTest, AddressSpace) {
+ for (int i = 0; i < static_cast<int>(blink::WebAddressSpaceLast); i++) {
+ SharedWorkerInstance instance(
+ GURL("http://example.com/w.js"), base::ASCIIToUTF16("name"),
+ base::string16(), blink::WebContentSecurityPolicyTypeReport,
+ static_cast<blink::WebAddressSpace>(i),
+ browser_context_->GetResourceContext(), partition_id_,
+ blink::WebSharedWorkerCreationContextTypeNonsecure);
+ EXPECT_EQ(static_cast<blink::WebAddressSpace>(i),
+ instance.creation_address_space());
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/shared_worker/shared_worker_message_filter.cc b/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
index 47902dbdfe6..d6ca6a15ead 100644
--- a/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
@@ -73,7 +73,6 @@ bool SharedWorkerMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnWorkerScriptLoadFailed)
IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerConnected,
OnWorkerConnected)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
WorkerProcessHostMsg_RequestFileSystemAccessSync,
OnRequestFileSystemAccess)
@@ -143,22 +142,6 @@ void SharedWorkerMessageFilter::OnWorkerConnected(int message_port_id,
this);
}
-void SharedWorkerMessageFilter::OnAllowDatabase(
- int worker_route_id,
- const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result) {
- SharedWorkerServiceImpl::GetInstance()->AllowDatabase(worker_route_id,
- url,
- name,
- display_name,
- estimated_size,
- result,
- this);
-}
-
void SharedWorkerMessageFilter::OnRequestFileSystemAccess(
int worker_route_id,
const GURL& url,
diff --git a/chromium/content/browser/shared_worker/shared_worker_message_filter.h b/chromium/content/browser/shared_worker/shared_worker_message_filter.h
index da0d32ca8ad..b6845e7faef 100644
--- a/chromium/content/browser/shared_worker/shared_worker_message_filter.h
+++ b/chromium/content/browser/shared_worker/shared_worker_message_filter.h
@@ -55,12 +55,6 @@ class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
void OnWorkerScriptLoaded(int worker_route_id);
void OnWorkerScriptLoadFailed(int worker_route_id);
void OnWorkerConnected(int message_port_id, int worker_route_id);
- void OnAllowDatabase(int worker_route_id,
- const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result);
void OnRequestFileSystemAccess(int worker_route_id,
const GURL& url,
IPC::Message* reply_msg);
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
index 653eb11146b..31443a39da9 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -292,8 +292,8 @@ void SharedWorkerServiceImpl::CreateWorker(
*creation_error = blink::WebWorkerCreationErrorNone;
scoped_ptr<SharedWorkerInstance> instance(new SharedWorkerInstance(
params.url, params.name, params.content_security_policy,
- params.security_policy_type, resource_context, partition_id,
- params.creation_context_type));
+ params.security_policy_type, params.creation_address_space,
+ resource_context, partition_id, params.creation_context_type));
scoped_ptr<SharedWorkerPendingInstance::SharedWorkerPendingRequest> request(
new SharedWorkerPendingInstance::SharedWorkerPendingRequest(
filter,
@@ -396,20 +396,6 @@ void SharedWorkerServiceImpl::WorkerConnected(
host->WorkerConnected(message_port_id);
}
-void SharedWorkerServiceImpl::AllowDatabase(
- int worker_route_id,
- const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result,
- SharedWorkerMessageFilter* filter) {
- if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
- host->AllowDatabase(url, name, display_name, estimated_size, result);
- else
- *result = false;
-}
-
void SharedWorkerServiceImpl::AllowFileSystem(
int worker_route_id,
const GURL& url,
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl.h b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
index 7b6bf85f03c..4af3bbf2537 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "content/public/browser/notification_observer.h"
@@ -70,13 +71,6 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
void WorkerConnected(int message_port_id,
int worker_route_id,
SharedWorkerMessageFilter* filter);
- void AllowDatabase(int worker_route_id,
- const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result,
- SharedWorkerMessageFilter* filter);
void AllowFileSystem(int worker_route_id,
const GURL& url,
IPC::Message* reply_msg,
diff --git a/chromium/content/browser/shared_worker/worker_browsertest.cc b/chromium/content/browser/shared_worker/worker_browsertest.cc
index 553d129916b..278d0eb877a 100644
--- a/chromium/content/browser/shared_worker/worker_browsertest.cc
+++ b/chromium/content/browser/shared_worker/worker_browsertest.cc
@@ -172,7 +172,8 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerTlsClientAuth) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory("content/test/data");
net::SSLServerConfig ssl_config;
- ssl_config.require_client_cert = true;
+ ssl_config.client_cert_type =
+ net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
ASSERT_TRUE(https_server.Start());
@@ -192,7 +193,8 @@ IN_PROC_BROWSER_TEST_F(WorkerTest, SharedWorkerTlsClientAuth) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory("content/test/data");
net::SSLServerConfig ssl_config;
- ssl_config.require_client_cert = true;
+ ssl_config.client_cert_type =
+ net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
ASSERT_TRUE(https_server.Start());
diff --git a/chromium/content/browser/site_instance_impl.cc b/chromium/content/browser/site_instance_impl.cc
index 9f88bafc19e..40271d4354f 100644
--- a/chromium/content/browser/site_instance_impl.cc
+++ b/chromium/content/browser/site_instance_impl.cc
@@ -27,8 +27,9 @@ SiteInstanceImpl::SiteInstanceImpl(BrowsingInstance* browsing_instance)
: id_(next_site_instance_id_++),
active_frame_count_(0),
browsing_instance_(browsing_instance),
- process_(NULL),
- has_site_(false) {
+ process_(nullptr),
+ has_site_(false),
+ is_default_subframe_site_instance_(false) {
DCHECK(browsing_instance);
}
@@ -42,8 +43,22 @@ SiteInstanceImpl::~SiteInstanceImpl() {
// the BrowsingInstance. Any future visits to a page from this site
// (within the same BrowsingInstance) can safely create a new SiteInstance.
if (has_site_)
- browsing_instance_->UnregisterSiteInstance(
- static_cast<SiteInstance*>(this));
+ browsing_instance_->UnregisterSiteInstance(this);
+}
+
+scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::Create(
+ BrowserContext* browser_context) {
+ return make_scoped_refptr(
+ new SiteInstanceImpl(new BrowsingInstance(browser_context)));
+}
+
+scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForURL(
+ BrowserContext* browser_context,
+ const GURL& url) {
+ // This will create a new SiteInstance and BrowsingInstance.
+ scoped_refptr<BrowsingInstance> instance(
+ new BrowsingInstance(browser_context));
+ return instance->GetSiteInstanceForURL(url);
}
int32_t SiteInstanceImpl::GetId() {
@@ -177,7 +192,8 @@ bool SiteInstanceImpl::HasRelatedSiteInstance(const GURL& url) {
return browsing_instance_->HasSiteInstance(url);
}
-SiteInstance* SiteInstanceImpl::GetRelatedSiteInstance(const GURL& url) {
+scoped_refptr<SiteInstance> SiteInstanceImpl::GetRelatedSiteInstance(
+ const GURL& url) {
return browsing_instance_->GetSiteInstanceForURL(url);
}
@@ -211,11 +227,16 @@ bool SiteInstanceImpl::HasWrongProcessForURL(const GURL& url) {
GetProcess(), browsing_instance_->browser_context(), site_url);
}
+scoped_refptr<SiteInstanceImpl>
+SiteInstanceImpl::GetDefaultSubframeSiteInstance() {
+ return browsing_instance_->GetDefaultSubframeSiteInstance();
+}
+
bool SiteInstanceImpl::RequiresDedicatedProcess() {
if (!has_site_)
return false;
- return SiteInstanceImpl::DoesSiteRequireDedicatedProcess(GetBrowserContext(),
- site_);
+
+ return DoesSiteRequireDedicatedProcess(GetBrowserContext(), site_);
}
void SiteInstanceImpl::IncrementActiveFrameCount() {
@@ -253,17 +274,16 @@ BrowserContext* SiteInstanceImpl::GetBrowserContext() const {
}
// static
-SiteInstance* SiteInstance::Create(BrowserContext* browser_context) {
- return new SiteInstanceImpl(new BrowsingInstance(browser_context));
+scoped_refptr<SiteInstance> SiteInstance::Create(
+ BrowserContext* browser_context) {
+ return SiteInstanceImpl::Create(browser_context);
}
// static
-SiteInstance* SiteInstance::CreateForURL(BrowserContext* browser_context,
- const GURL& url) {
- // This will create a new SiteInstance and BrowsingInstance.
- scoped_refptr<BrowsingInstance> instance(
- new BrowsingInstance(browser_context));
- return instance->GetSiteInstanceForURL(url);
+scoped_refptr<SiteInstance> SiteInstance::CreateForURL(
+ BrowserContext* browser_context,
+ const GURL& url) {
+ return SiteInstanceImpl::CreateForURL(browser_context, url);
}
// static
@@ -379,7 +399,7 @@ bool SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
void SiteInstanceImpl::RenderProcessHostDestroyed(RenderProcessHost* host) {
DCHECK_EQ(process_, host);
process_->RemoveObserver(this);
- process_ = NULL;
+ process_ = nullptr;
}
void SiteInstanceImpl::RenderProcessWillExit(RenderProcessHost* host) {
diff --git a/chromium/content/browser/site_instance_impl.h b/chromium/content/browser/site_instance_impl.h
index b54de7f5886..9089a02ab89 100644
--- a/chromium/content/browser/site_instance_impl.h
+++ b/chromium/content/browser/site_instance_impl.h
@@ -20,30 +20,42 @@ namespace content {
class BrowsingInstance;
class RenderProcessHostFactory;
-class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
- public RenderProcessHostObserver {
+class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
+ public RenderProcessHostObserver {
public:
- class Observer {
+ class CONTENT_EXPORT Observer {
public:
// Called when this SiteInstance transitions to having no active frames,
// as measured by active_frame_count().
- virtual void ActiveFrameCountIsZero(SiteInstanceImpl* site_instance) = 0;
+ virtual void ActiveFrameCountIsZero(SiteInstanceImpl* site_instance) {}
// Called when the renderer process of this SiteInstance has exited.
virtual void RenderProcessGone(SiteInstanceImpl* site_instance) = 0;
};
+ static scoped_refptr<SiteInstanceImpl> Create(
+ BrowserContext* browser_context);
+ static scoped_refptr<SiteInstanceImpl> CreateForURL(
+ BrowserContext* browser_context,
+ const GURL& url);
+
// SiteInstance interface overrides.
int32_t GetId() override;
bool HasProcess() const override;
RenderProcessHost* GetProcess() override;
BrowserContext* GetBrowserContext() const override;
const GURL& GetSiteURL() const override;
- SiteInstance* GetRelatedSiteInstance(const GURL& url) override;
+ scoped_refptr<SiteInstance> GetRelatedSiteInstance(const GURL& url) override;
bool IsRelatedSiteInstance(const SiteInstance* instance) override;
size_t GetRelatedActiveContentsCount() override;
bool RequiresDedicatedProcess() override;
+ // Returns the SiteInstance, related to this one, that should be used
+ // for subframes when an oopif is required, but a dedicated process is not.
+ // This SiteInstance will be created if it doesn't already exist. There is
+ // at most one of these per BrowsingInstance.
+ scoped_refptr<SiteInstanceImpl> GetDefaultSubframeSiteInstance();
+
// Set the web site that this SiteInstance is rendering pages for.
// This includes the scheme and registered domain, but not the port. If the
// URL does not have a valid registered domain, then the full hostname is
@@ -88,6 +100,10 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
+ bool is_default_subframe_site_instance() {
+ return is_default_subframe_site_instance_;
+ }
+
// Sets the global factory used to create new RenderProcessHosts. It may be
// NULL, in which case the default RenderProcessHost will be created (this is
// the behavior if you don't call this function). The factory must be set
@@ -113,19 +129,16 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
static bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
const GURL& effective_url);
- protected:
+ private:
friend class BrowsingInstance;
- friend class SiteInstance;
-
- // Virtual to allow tests to extend it.
- ~SiteInstanceImpl() override;
+ friend class SiteInstanceTestBrowserClient;
- // Create a new SiteInstance. Protected to give access to BrowsingInstance
- // and tests; most callers should use Create or GetRelatedSiteInstance
- // instead.
+ // Create a new SiteInstance. Only BrowsingInstance should call this
+ // directly; clients should use Create() or GetRelatedSiteInstance() instead.
explicit SiteInstanceImpl(BrowsingInstance* browsing_instance);
- private:
+ ~SiteInstanceImpl() override;
+
// RenderProcessHostObserver implementation.
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
void RenderProcessWillExit(RenderProcessHost* host) override;
@@ -136,6 +149,10 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
// Used to restrict a process' origin access rights.
void LockToOrigin();
+ void set_is_default_subframe_site_instance() {
+ is_default_subframe_site_instance_ = true;
+ }
+
// An object used to construct RenderProcessHosts.
static const RenderProcessHostFactory* g_render_process_host_factory_;
@@ -163,6 +180,11 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
// Whether SetSite has been called.
bool has_site_;
+ // Whether this SiteInstance is the default subframe SiteInstance for its
+ // BrowsingInstance. Only one SiteInstance per BrowsingInstance can have this
+ // be true.
+ bool is_default_subframe_site_instance_;
+
base::ObserverList<Observer, true> observers_;
DISALLOW_COPY_AND_ASSIGN(SiteInstanceImpl);
diff --git a/chromium/content/browser/site_instance_impl_unittest.cc b/chromium/content/browser/site_instance_impl_unittest.cc
index b632d74a19b..18cf06fa0f7 100644
--- a/chromium/content/browser/site_instance_impl_unittest.cc
+++ b/chromium/content/browser/site_instance_impl_unittest.cc
@@ -34,14 +34,15 @@
#include "url/url_util.h"
namespace content {
-namespace {
const char kPrivilegedScheme[] = "privileged";
class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
public:
- SiteInstanceTestBrowserClient()
- : privileged_process_id_(-1) {
+ explicit SiteInstanceTestBrowserClient()
+ : privileged_process_id_(-1),
+ site_instance_delete_count_(0),
+ browsing_instance_delete_count_(0) {
WebUIControllerFactory::RegisterFactory(
ContentWebUIControllerFactory::GetInstance());
}
@@ -61,8 +62,32 @@ class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
privileged_process_id_ = process_id;
}
+ void SiteInstanceDeleting(content::SiteInstance* site_instance) override {
+ site_instance_delete_count_++;
+ // Infer deletion of the browsing instance.
+ if (static_cast<SiteInstanceImpl*>(site_instance)
+ ->browsing_instance_->HasOneRef()) {
+ browsing_instance_delete_count_++;
+ }
+ }
+
+ int GetAndClearSiteInstanceDeleteCount() {
+ int result = site_instance_delete_count_;
+ site_instance_delete_count_ = 0;
+ return result;
+ }
+
+ int GetAndClearBrowsingInstanceDeleteCount() {
+ int result = browsing_instance_delete_count_;
+ browsing_instance_delete_count_ = 0;
+ return result;
+ }
+
private:
int privileged_process_id_;
+
+ int site_instance_delete_count_;
+ int browsing_instance_delete_count_;
};
class SiteInstanceTest : public testing::Test {
@@ -72,8 +97,7 @@ class SiteInstanceTest : public testing::Test {
file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING,
&message_loop_),
io_thread_(BrowserThread::IO, &message_loop_),
- old_browser_client_(NULL) {
- }
+ old_browser_client_(nullptr) {}
void SetUp() override {
old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
@@ -88,7 +112,7 @@ class SiteInstanceTest : public testing::Test {
EXPECT_TRUE(RenderProcessHost::AllHostsIterator().IsAtEnd());
SetBrowserClientForTesting(old_browser_client_);
- SiteInstanceImpl::set_render_process_host_factory(NULL);
+ SiteInstanceImpl::set_render_process_host_factory(nullptr);
// http://crbug.com/143565 found SiteInstanceTest leaking an
// AppCacheDatabase. This happens because some part of the test indirectly
@@ -114,6 +138,8 @@ class SiteInstanceTest : public testing::Test {
message_loop_.RunUntilIdle();
}
+ SiteInstanceTestBrowserClient* browser_client() { return &browser_client_; }
+
private:
base::MessageLoopForUI message_loop_;
TestBrowserThread ui_thread_;
@@ -125,64 +151,16 @@ class SiteInstanceTest : public testing::Test {
MockRenderProcessHostFactory rph_factory_;
};
-// Subclass of BrowsingInstance that updates a counter when deleted and
-// returns TestSiteInstances from GetSiteInstanceForURL.
-class TestBrowsingInstance : public BrowsingInstance {
- public:
- TestBrowsingInstance(BrowserContext* browser_context, int* delete_counter)
- : BrowsingInstance(browser_context),
- delete_counter_(delete_counter) {
- }
-
- // Make a few methods public for tests.
- using BrowsingInstance::browser_context;
- using BrowsingInstance::HasSiteInstance;
- using BrowsingInstance::GetSiteInstanceForURL;
- using BrowsingInstance::RegisterSiteInstance;
- using BrowsingInstance::UnregisterSiteInstance;
-
- private:
- ~TestBrowsingInstance() override { (*delete_counter_)++; }
-
- int* delete_counter_;
-};
-
-// Subclass of SiteInstanceImpl that updates a counter when deleted.
-class TestSiteInstance : public SiteInstanceImpl {
- public:
- static TestSiteInstance* CreateTestSiteInstance(
- BrowserContext* browser_context,
- int* site_delete_counter,
- int* browsing_delete_counter) {
- TestBrowsingInstance* browsing_instance =
- new TestBrowsingInstance(browser_context, browsing_delete_counter);
- return new TestSiteInstance(browsing_instance, site_delete_counter);
- }
-
- private:
- TestSiteInstance(BrowsingInstance* browsing_instance, int* delete_counter)
- : SiteInstanceImpl(browsing_instance), delete_counter_(delete_counter) {}
- ~TestSiteInstance() override { (*delete_counter_)++; }
-
- int* delete_counter_;
-};
-
-} // namespace
-
// Test to ensure no memory leaks for SiteInstance objects.
TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
// The existence of this object will cause WebContentsImpl to create our
// test one instead of the real one.
RenderViewHostTestEnabler rvh_test_enabler;
- int site_delete_counter = 0;
- int browsing_delete_counter = 0;
const GURL url("test:foo");
// Ensure that instances are deleted when their NavigationEntries are gone.
- TestSiteInstance* instance =
- TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter,
- &browsing_delete_counter);
- EXPECT_EQ(0, site_delete_counter);
+ scoped_refptr<SiteInstanceImpl> instance = SiteInstanceImpl::Create(nullptr);
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
NavigationEntryImpl* e1 = new NavigationEntryImpl(
instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
@@ -190,43 +168,45 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
// Redundantly setting e1's SiteInstance shouldn't affect the ref count.
e1->set_site_instance(instance);
- EXPECT_EQ(0, site_delete_counter);
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
// Add a second reference
NavigationEntryImpl* e2 = new NavigationEntryImpl(
instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
false);
+ instance = nullptr;
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+
// Now delete both entries and be sure the SiteInstance goes away.
delete e1;
- EXPECT_EQ(0, site_delete_counter);
- EXPECT_EQ(0, browsing_delete_counter);
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
delete e2;
- EXPECT_EQ(1, site_delete_counter);
// instance is now deleted
- EXPECT_EQ(1, browsing_delete_counter);
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
// browsing_instance is now deleted
// Ensure that instances are deleted when their RenderViewHosts are gone.
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
- instance =
- TestSiteInstance::CreateTestSiteInstance(browser_context.get(),
- &site_delete_counter,
- &browsing_delete_counter);
{
scoped_ptr<WebContentsImpl> web_contents(static_cast<WebContentsImpl*>(
WebContents::Create(WebContents::CreateParams(
- browser_context.get(), instance))));
- EXPECT_EQ(1, site_delete_counter);
- EXPECT_EQ(1, browsing_delete_counter);
+ browser_context.get(),
+ SiteInstance::Create(browser_context.get())))));
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
}
// Make sure that we flush any messages related to the above WebContentsImpl
// destruction.
DrainMessageLoops();
- EXPECT_EQ(2, site_delete_counter);
- EXPECT_EQ(2, browsing_delete_counter);
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
// contents is now deleted, along with instance and browsing_instance
}
@@ -234,40 +214,31 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
// SiteInstances can be changed afterwards. Also tests that the ref counts are
// updated properly after the change.
TEST_F(SiteInstanceTest, CloneNavigationEntry) {
- int site_delete_counter1 = 0;
- int site_delete_counter2 = 0;
- int browsing_delete_counter = 0;
const GURL url("test:foo");
- SiteInstanceImpl* instance1 =
- TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter1,
- &browsing_delete_counter);
- SiteInstanceImpl* instance2 =
- TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter2,
- &browsing_delete_counter);
-
scoped_ptr<NavigationEntryImpl> e1 = make_scoped_ptr(new NavigationEntryImpl(
- instance1, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
- false));
+ SiteInstanceImpl::Create(nullptr), 0, url, Referrer(), base::string16(),
+ ui::PAGE_TRANSITION_LINK, false));
+
// Clone the entry.
scoped_ptr<NavigationEntryImpl> e2 = e1->Clone();
// Should be able to change the SiteInstance of the cloned entry.
- e2->set_site_instance(instance2);
+ e2->set_site_instance(SiteInstanceImpl::Create(nullptr));
+
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
- // The first SiteInstance should go away after resetting e1, since e2 should
- // no longer be referencing it.
+ // The first SiteInstance and BrowsingInstance should go away after resetting
+ // e1, since e2 should no longer be referencing it.
e1.reset();
- EXPECT_EQ(1, site_delete_counter1);
- EXPECT_EQ(0, site_delete_counter2);
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
// The second SiteInstance should go away after resetting e2.
e2.reset();
- EXPECT_EQ(1, site_delete_counter1);
- EXPECT_EQ(1, site_delete_counter2);
-
- // Both BrowsingInstances are also now deleted.
- EXPECT_EQ(2, browsing_delete_counter);
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
DrainMessageLoops();
}
@@ -277,16 +248,16 @@ TEST_F(SiteInstanceTest, GetProcess) {
// Ensure that GetProcess returns a process.
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host1;
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance(
+ SiteInstanceImpl::Create(browser_context.get()));
host1.reset(instance->GetProcess());
- EXPECT_TRUE(host1.get() != NULL);
+ EXPECT_TRUE(host1.get() != nullptr);
// Ensure that GetProcess creates a new process.
- scoped_refptr<SiteInstanceImpl> instance2(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance2(
+ SiteInstanceImpl::Create(browser_context.get()));
scoped_ptr<RenderProcessHost> host2(instance2->GetProcess());
- EXPECT_TRUE(host2.get() != NULL);
+ EXPECT_TRUE(host2.get() != nullptr);
EXPECT_NE(host1.get(), host2.get());
DrainMessageLoops();
@@ -294,8 +265,7 @@ TEST_F(SiteInstanceTest, GetProcess) {
// Test to ensure SetSite and site() work properly.
TEST_F(SiteInstanceTest, SetSite) {
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(NULL)));
+ scoped_refptr<SiteInstanceImpl> instance(SiteInstanceImpl::Create(nullptr));
EXPECT_FALSE(instance->HasSite());
EXPECT_TRUE(instance->GetSiteURL().is_empty());
@@ -311,45 +281,45 @@ TEST_F(SiteInstanceTest, SetSite) {
TEST_F(SiteInstanceTest, GetSiteForURL) {
// Pages are irrelevant.
GURL test_url = GURL("http://www.google.com/index.html");
- GURL site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ GURL site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://google.com"), site_url);
EXPECT_EQ("http", site_url.scheme());
EXPECT_EQ("google.com", site_url.host());
// Ports are irrlevant.
test_url = GURL("https://www.google.com:8080");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("https://google.com"), site_url);
// Hostnames without TLDs are ok.
test_url = GURL("http://foo/a.html");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://foo"), site_url);
EXPECT_EQ("foo", site_url.host());
// File URLs should include the scheme.
test_url = GURL("file:///C:/Downloads/");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("file:"), site_url);
EXPECT_EQ("file", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
// Some file URLs have hosts in the path.
test_url = GURL("file://server/path");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("file://server"), site_url);
EXPECT_EQ("server", site_url.host());
// Data URLs should include the scheme.
test_url = GURL("data:text/html,foo");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("data:"), site_url);
EXPECT_EQ("data", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
// Javascript URLs should include the scheme.
test_url = GURL("javascript:foo();");
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("javascript:"), site_url);
EXPECT_EQ("javascript", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
@@ -359,7 +329,7 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
std::string guest_url(kGuestScheme);
guest_url.append("://abc123/path");
test_url = GURL(guest_url);
- site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(test_url, site_url);
DrainMessageLoops();
@@ -377,29 +347,31 @@ TEST_F(SiteInstanceTest, IsSameWebSite) {
GURL url_blank = GURL(url::kAboutBlankURL);
// Same scheme and port -> same site.
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_foo, url_foo2));
// Different scheme -> different site.
- EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_https));
+ EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, url_foo, url_foo_https));
// Different port -> same site.
// (Changes to document.domain make renderer ignore the port.)
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_port));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_foo, url_foo_port));
// JavaScript links should be considered same site for anything.
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo));
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https));
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_port));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_javascript, url_foo));
+ EXPECT_TRUE(
+ SiteInstance::IsSameWebSite(nullptr, url_javascript, url_foo_https));
+ EXPECT_TRUE(
+ SiteInstance::IsSameWebSite(nullptr, url_javascript, url_foo_port));
// Navigating to a blank page is considered the same site.
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_blank));
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_https, url_blank));
- EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_port, url_blank));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_foo, url_blank));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_foo_https, url_blank));
+ EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, url_foo_port, url_blank));
// Navigating from a blank site is not considered to be the same site.
- EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo));
- EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_https));
- EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_port));
+ EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, url_blank, url_foo));
+ EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, url_blank, url_foo_https));
+ EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, url_blank, url_foo_port));
DrainMessageLoops();
}
@@ -409,22 +381,20 @@ TEST_F(SiteInstanceTest, IsSameWebSite) {
TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kProcessPerSite));
- int delete_counter = 0;
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
- TestBrowsingInstance* browsing_instance =
- new TestBrowsingInstance(browser_context.get(), &delete_counter);
+ BrowsingInstance* browsing_instance =
+ new BrowsingInstance(browser_context.get());
const GURL url_a1("http://www.google.com/1.html");
scoped_refptr<SiteInstanceImpl> site_instance_a1(
- static_cast<SiteInstanceImpl*>(
- browsing_instance->GetSiteInstanceForURL(url_a1)));
- EXPECT_TRUE(site_instance_a1.get() != NULL);
+ browsing_instance->GetSiteInstanceForURL(url_a1));
+ EXPECT_TRUE(site_instance_a1.get() != nullptr);
// A separate site should create a separate SiteInstance.
const GURL url_b1("http://www.yahoo.com/");
scoped_refptr<SiteInstanceImpl> site_instance_b1(
- static_cast<SiteInstanceImpl*>(
- browsing_instance->GetSiteInstanceForURL(url_b1)));
+
+ browsing_instance->GetSiteInstanceForURL(url_b1));
EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
@@ -442,12 +412,11 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
// A visit to the original site in a new BrowsingInstance (same or different
// browser context) should return a different SiteInstance.
- TestBrowsingInstance* browsing_instance2 =
- new TestBrowsingInstance(browser_context.get(), &delete_counter);
+ BrowsingInstance* browsing_instance2 =
+ new BrowsingInstance(browser_context.get());
// Ensure the new SiteInstance is ref counted so that it gets deleted.
scoped_refptr<SiteInstanceImpl> site_instance_a2_2(
- static_cast<SiteInstanceImpl*>(
- browsing_instance2->GetSiteInstanceForURL(url_a2)));
+ browsing_instance2->GetSiteInstanceForURL(url_a2));
EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get());
EXPECT_FALSE(
site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2.get()));
@@ -483,23 +452,20 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kProcessPerSite);
- int delete_counter = 0;
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
- TestBrowsingInstance* browsing_instance =
- new TestBrowsingInstance(browser_context.get(), &delete_counter);
+ scoped_refptr<BrowsingInstance> browsing_instance =
+ new BrowsingInstance(browser_context.get());
const GURL url_a1("http://www.google.com/1.html");
scoped_refptr<SiteInstanceImpl> site_instance_a1(
- static_cast<SiteInstanceImpl*>(
- browsing_instance->GetSiteInstanceForURL(url_a1)));
- EXPECT_TRUE(site_instance_a1.get() != NULL);
+ browsing_instance->GetSiteInstanceForURL(url_a1));
+ EXPECT_TRUE(site_instance_a1.get() != nullptr);
scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess());
// A separate site should create a separate SiteInstance.
const GURL url_b1("http://www.yahoo.com/");
scoped_refptr<SiteInstanceImpl> site_instance_b1(
- static_cast<SiteInstanceImpl*>(
- browsing_instance->GetSiteInstanceForURL(url_b1)));
+ browsing_instance->GetSiteInstanceForURL(url_b1));
EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
@@ -517,24 +483,22 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
// A visit to the original site in a new BrowsingInstance (same browser
// context) should return a different SiteInstance with the same process.
- TestBrowsingInstance* browsing_instance2 =
- new TestBrowsingInstance(browser_context.get(), &delete_counter);
+ BrowsingInstance* browsing_instance2 =
+ new BrowsingInstance(browser_context.get());
scoped_refptr<SiteInstanceImpl> site_instance_a1_2(
- static_cast<SiteInstanceImpl*>(
- browsing_instance2->GetSiteInstanceForURL(url_a1)));
- EXPECT_TRUE(site_instance_a1.get() != NULL);
+ browsing_instance2->GetSiteInstanceForURL(url_a1));
+ EXPECT_TRUE(site_instance_a1.get() != nullptr);
EXPECT_NE(site_instance_a1.get(), site_instance_a1_2.get());
EXPECT_EQ(process_a1.get(), site_instance_a1_2->GetProcess());
// A visit to the original site in a new BrowsingInstance (different browser
// context) should return a different SiteInstance with a different process.
scoped_ptr<TestBrowserContext> browser_context2(new TestBrowserContext());
- TestBrowsingInstance* browsing_instance3 =
- new TestBrowsingInstance(browser_context2.get(), &delete_counter);
+ BrowsingInstance* browsing_instance3 =
+ new BrowsingInstance(browser_context2.get());
scoped_refptr<SiteInstanceImpl> site_instance_a2_3(
- static_cast<SiteInstanceImpl*>(
- browsing_instance3->GetSiteInstanceForURL(url_a2)));
- EXPECT_TRUE(site_instance_a2_3.get() != NULL);
+ browsing_instance3->GetSiteInstanceForURL(url_a2));
+ EXPECT_TRUE(site_instance_a2_3.get() != nullptr);
scoped_ptr<RenderProcessHost> process_a2_3(site_instance_a2_3->GetProcess());
EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get());
EXPECT_NE(process_a1.get(), process_a2_3.get());
@@ -561,10 +525,10 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
DrainMessageLoops();
}
-static SiteInstanceImpl* CreateSiteInstance(BrowserContext* browser_context,
- const GURL& url) {
- return static_cast<SiteInstanceImpl*>(
- SiteInstance::CreateForURL(browser_context, url));
+static scoped_refptr<SiteInstanceImpl> CreateSiteInstance(
+ BrowserContext* browser_context,
+ const GURL& url) {
+ return SiteInstanceImpl::CreateForURL(browser_context, url);
}
// Test to ensure that pages that require certain privileges are grouped
@@ -635,8 +599,8 @@ TEST_F(SiteInstanceTest, ProcessSharingByType) {
TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host;
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance(
+ SiteInstanceImpl::Create(browser_context.get()));
EXPECT_FALSE(instance->HasSite());
EXPECT_TRUE(instance->GetSiteURL().is_empty());
@@ -651,7 +615,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
// The call to GetProcess actually creates a new real process, which works
// fine, but might be a cause for problems in different contexts.
host.reset(instance->GetProcess());
- EXPECT_TRUE(host.get() != NULL);
+ EXPECT_TRUE(host.get() != nullptr);
EXPECT_TRUE(instance->HasProcess());
EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
@@ -662,8 +626,8 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
// Test that WebUI SiteInstances reject normal web URLs.
const GURL webui_url("chrome://gpu");
- scoped_refptr<SiteInstanceImpl> webui_instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> webui_instance(
+ SiteInstanceImpl::Create(browser_context.get()));
webui_instance->SetSite(webui_url);
scoped_ptr<RenderProcessHost> webui_host(webui_instance->GetProcess());
@@ -680,8 +644,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
// even if we haven't called GetProcess yet. Make sure HasWrongProcessForURL
// doesn't crash (http://crbug.com/137070).
scoped_refptr<SiteInstanceImpl> webui_instance2(
- static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ SiteInstanceImpl::Create(browser_context.get()));
webui_instance2->SetSite(webui_url);
EXPECT_FALSE(webui_instance2->HasWrongProcessForURL(webui_url));
EXPECT_TRUE(
@@ -697,8 +660,8 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host;
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance(
+ SiteInstanceImpl::Create(browser_context.get()));
instance->SetSite(GURL("http://evernote.com/"));
EXPECT_TRUE(instance->HasSite());
@@ -710,7 +673,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
// The call to GetProcess actually creates a new real process, which works
// fine, but might be a cause for problems in different contexts.
host.reset(instance->GetProcess());
- EXPECT_TRUE(host.get() != NULL);
+ EXPECT_TRUE(host.get() != nullptr);
EXPECT_TRUE(instance->HasProcess());
EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
@@ -728,8 +691,8 @@ TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host;
scoped_ptr<RenderProcessHost> host2;
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance(
+ SiteInstanceImpl::Create(browser_context.get()));
EXPECT_FALSE(instance->HasSite());
EXPECT_TRUE(instance->GetSiteURL().is_empty());
@@ -742,7 +705,7 @@ TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
// The call to GetProcess actually creates a new real process.
host.reset(instance->GetProcess());
- EXPECT_TRUE(host.get() != NULL);
+ EXPECT_TRUE(host.get() != nullptr);
EXPECT_TRUE(instance->HasProcess());
// Without bindings, this should look like the wrong process.
@@ -752,11 +715,10 @@ TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
// same process. Make sure it doesn't use the same process if the bindings
// are missing.
scoped_refptr<SiteInstanceImpl> instance2(
- static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ SiteInstanceImpl::Create(browser_context.get()));
instance2->SetSite(webui_url);
host2.reset(instance2->GetProcess());
- EXPECT_TRUE(host2.get() != NULL);
+ EXPECT_TRUE(host2.get() != nullptr);
EXPECT_TRUE(instance2->HasProcess());
EXPECT_NE(host.get(), host2.get());
@@ -770,8 +732,8 @@ TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
switches::kProcessPerSite);
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host;
- scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
- SiteInstance::Create(browser_context.get())));
+ scoped_refptr<SiteInstanceImpl> instance(
+ SiteInstanceImpl::Create(browser_context.get()));
instance->SetSite(GURL());
EXPECT_TRUE(instance->HasSite());
@@ -784,4 +746,53 @@ TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
DrainMessageLoops();
}
+TEST_F(SiteInstanceTest, DefaultSubframeSiteInstance) {
+ if (AreAllSitesIsolatedForTesting())
+ return; // --top-document-isolation is not possible.
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTopDocumentIsolation);
+
+ scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
+ scoped_refptr<SiteInstanceImpl> main_instance =
+ SiteInstanceImpl::Create(browser_context.get());
+ scoped_refptr<SiteInstanceImpl> subframe_instance =
+ main_instance->GetDefaultSubframeSiteInstance();
+ int subframe_instance_id = subframe_instance->GetId();
+
+ EXPECT_NE(main_instance, subframe_instance);
+ EXPECT_EQ(subframe_instance, main_instance->GetDefaultSubframeSiteInstance());
+ EXPECT_FALSE(main_instance->is_default_subframe_site_instance());
+ EXPECT_TRUE(subframe_instance->is_default_subframe_site_instance());
+
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+
+ // Free the subframe instance.
+ subframe_instance = nullptr;
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+
+ // Calling GetDefaultSubframeSiteInstance again should return a new
+ // SiteInstance with a different ID from the original.
+ subframe_instance = main_instance->GetDefaultSubframeSiteInstance();
+ EXPECT_NE(subframe_instance->GetId(), subframe_instance_id);
+ EXPECT_FALSE(main_instance->is_default_subframe_site_instance());
+ EXPECT_TRUE(subframe_instance->is_default_subframe_site_instance());
+ EXPECT_EQ(subframe_instance->GetDefaultSubframeSiteInstance(),
+ subframe_instance);
+ EXPECT_EQ(0, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+
+ // Free the main instance.
+ main_instance = nullptr;
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(0, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+
+ // Free the subframe instance, which should free the browsing instance.
+ subframe_instance = nullptr;
+ EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
+ EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
+}
+
} // namespace content
diff --git a/chromium/content/browser/site_per_process_browsertest.cc b/chromium/content/browser/site_per_process_browsertest.cc
index 08f4c26bcb8..618ff8fec2c 100644
--- a/chromium/content/browser/site_per_process_browsertest.cc
+++ b/chromium/content/browser/site_per_process_browsertest.cc
@@ -26,17 +26,23 @@
#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/gpu/compositor_util.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
+#include "content/common/input/synthetic_tap_gesture_params.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/cert_store.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
@@ -49,8 +55,19 @@
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebSandboxFlags.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/switches.h"
+#if defined(USE_AURA)
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
+#endif
+
namespace content {
namespace {
@@ -118,6 +135,15 @@ void SimulateMouseClick(RenderWidgetHost* rwh, int x, int y) {
rwh->ForwardMouseEvent(mouse_event);
}
+// Retrieve document.origin for the frame |ftn|.
+std::string GetDocumentOrigin(FrameTreeNode* ftn) {
+ std::string origin;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ ftn->current_frame_host(),
+ "domAutomationController.send(document.origin)", &origin));
+ return origin;
+}
+
class RenderWidgetHostMouseEventMonitor {
public:
explicit RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
@@ -152,9 +178,6 @@ class RenderWidgetHostMouseEventMonitor {
void SurfaceHitTestTestHelper(
Shell* shell,
net::test_server::EmbeddedTestServer* embedded_test_server) {
- if (!UseSurfacesEnabled())
- return;
-
GURL main_url(embedded_test_server->GetURL(
"/frame_tree/page_with_positioned_frame.html"));
NavigateToURL(shell, main_url);
@@ -186,19 +209,9 @@ void SurfaceHitTestTestHelper(
RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
- // We need to wait for a compositor frame from the child frame, at which
- // point its surface will be created.
- while (rwhv_child->RendererFrameNumber() <= 0) {
- // TODO(lazyboy): Find a better way to avoid sleeping like this. See
- // http://crbug.com/405282 for details.
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(10));
- run_loop.Run();
- }
-
- uint32_t cur_render_frame_number = root_view->RendererFrameNumber();
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
+ notifier.WaitForSurfaceReady();
// Target input event to child frame.
blink::WebMouseEvent child_event;
@@ -211,32 +224,6 @@ void SurfaceHitTestTestHelper(
child_frame_monitor.ResetEventReceived();
router->RouteMouseEvent(root_view, &child_event);
- while (!child_frame_monitor.EventWasReceived()) {
- // This is working around a big synchronization problem. It is very
- // difficult to know if we have received a compositor frame from the
- // main frame renderer *after* it received the child frame's surface
- // ID. Hit testing won't work until this happens. So if the hit test
- // fails then we wait for another frame to arrive and try again.
- // TODO(kenrb): We need a better way to do all of this, possibly coming
- // from http://crbug.com/405282.
- while (root_view->RendererFrameNumber() <= cur_render_frame_number) {
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(10));
- run_loop.Run();
- }
- cur_render_frame_number = root_view->RendererFrameNumber();
- child_event.type = blink::WebInputEvent::MouseDown;
- child_event.button = blink::WebPointerProperties::ButtonLeft;
- child_event.x = 75;
- child_event.y = 75;
- child_event.clickCount = 1;
- main_frame_monitor.ResetEventReceived();
- child_frame_monitor.ResetEventReceived();
- router->RouteMouseEvent(root_view, &child_event);
- }
-
EXPECT_TRUE(child_frame_monitor.EventWasReceived());
EXPECT_EQ(23, child_frame_monitor.event().x);
EXPECT_EQ(23, child_frame_monitor.event().y);
@@ -545,7 +532,6 @@ class RenderWidgetHostVisibilityObserver : public NotificationObserver {
message_loop_runner_->Quit();
}
- RenderWidgetHostImpl* render_widget_host_;
bool expected_visibility_state_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
NotificationRegistrar registrar_;
@@ -556,6 +542,33 @@ class RenderWidgetHostVisibilityObserver : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostVisibilityObserver);
};
+// A mock CertStore that always assigns the render process host id as
+// the certificate id. Certificates are never removed.
+class MockCertStore : public CertStore {
+ public:
+ MockCertStore() {}
+ ~MockCertStore() override {}
+
+ int StoreCert(net::X509Certificate* cert,
+ int render_process_host_id) override {
+ certs_[render_process_host_id] = cert;
+ return render_process_host_id;
+ }
+
+ bool RetrieveCert(int cert_id,
+ scoped_refptr<net::X509Certificate>* cert) override {
+ if (certs_.find(cert_id) == certs_.end())
+ return false;
+ *cert = certs_[cert_id];
+ return true;
+ }
+
+ private:
+ std::map<int, scoped_refptr<net::X509Certificate>> certs_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCertStore);
+};
+
} // namespace
//
@@ -597,6 +610,20 @@ class SitePerProcessHighDPIBrowserTest : public SitePerProcessBrowserTest {
}
};
+// SitePerProcessIgnoreCertErrorsBrowserTest
+
+class SitePerProcessIgnoreCertErrorsBrowserTest
+ : public SitePerProcessBrowserTest {
+ public:
+ SitePerProcessIgnoreCertErrorsBrowserTest() {}
+
+ protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ SitePerProcessBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+ }
+};
+
// Ensure that navigating subframes in --site-per-process mode works and the
// correct documents are committed.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
@@ -728,9 +755,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
// Test that mouse events are being routed to the correct RenderWidgetHostView
// based on coordinates.
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
// Browser process hit testing is not implemented on Android.
// https://crbug.com/491334
+// The test times out often on TSAN bot.
+// https://crbug.com/591170.
#define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
#else
#define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
@@ -753,6 +782,150 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
SurfaceHitTestTestHelper(shell(), embedded_test_server());
}
+// Test that mouse events are being routed to the correct RenderWidgetHostView
+// when there are nested out-of-process iframes.
+#if defined(OS_ANDROID)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+#define MAYBE_NestedSurfaceHitTestTest DISABLED_NestedSurfaceHitTestTest
+#else
+#define MAYBE_NestedSurfaceHitTestTest NestedSurfaceHitTestTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_NestedSurfaceHitTestTest) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_nested_frames.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* parent_iframe_node = root->child_at(0);
+ GURL site_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_positioned_frame.html"));
+ EXPECT_EQ(site_url, parent_iframe_node->current_url());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ parent_iframe_node->current_frame_host()->GetSiteInstance());
+
+ FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
+ GURL nested_site_url(
+ embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(nested_site_url, nested_iframe_node->current_url());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ nested_iframe_node->current_frame_host()->GetSiteInstance());
+ EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(),
+ nested_iframe_node->current_frame_host()->GetSiteInstance());
+
+ // Create listeners for mouse events.
+ RenderWidgetHostMouseEventMonitor main_frame_monitor(
+ root->current_frame_host()->GetRenderWidgetHost());
+ RenderWidgetHostMouseEventMonitor nested_frame_monitor(
+ nested_iframe_node->current_frame_host()->GetRenderWidgetHost());
+
+ RenderWidgetHostInputEventRouter* router =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetInputEventRouter();
+
+ RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+ RenderWidgetHostViewBase* rwhv_nested =
+ static_cast<RenderWidgetHostViewBase*>(
+ nested_iframe_node->current_frame_host()
+ ->GetRenderWidgetHost()
+ ->GetView());
+
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv_nested));
+ notifier.WaitForSurfaceReady();
+
+ // Target input event to nested frame.
+ blink::WebMouseEvent nested_event;
+ nested_event.type = blink::WebInputEvent::MouseDown;
+ nested_event.button = blink::WebPointerProperties::ButtonLeft;
+ nested_event.x = 125;
+ nested_event.y = 125;
+ nested_event.clickCount = 1;
+ nested_frame_monitor.ResetEventReceived();
+ main_frame_monitor.ResetEventReceived();
+ router->RouteMouseEvent(root_view, &nested_event);
+
+ EXPECT_TRUE(nested_frame_monitor.EventWasReceived());
+ EXPECT_EQ(21, nested_frame_monitor.event().x);
+ EXPECT_EQ(21, nested_frame_monitor.event().y);
+ EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+}
+
+// This test tests that browser process hittesting ignores frames with
+// pointer-events: none.
+#if defined(OS_ANDROID)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+#define MAYBE_SurfaceHitTestPointerEventsNone \
+ DISABLED_SurfaceHitTestPointerEventsNone
+#elif defined(THREAD_SANITIZER)
+// Flaky on TSAN. https://crbug.com/582277
+#define MAYBE_SurfaceHitTestPointerEventsNone \
+ DISABLED_SurfaceHitTestPointerEventsNone
+#else
+#define MAYBE_SurfaceHitTestPointerEventsNone SurfaceHitTestPointerEventsNone
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_SurfaceHitTestPointerEventsNone) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* child_node = root->child_at(0);
+ GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_url, child_node->current_url());
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child_node->current_frame_host()->GetSiteInstance());
+
+ // Create listeners for mouse events.
+ RenderWidgetHostMouseEventMonitor main_frame_monitor(
+ root->current_frame_host()->GetRenderWidgetHost());
+ RenderWidgetHostMouseEventMonitor child_frame_monitor(
+ child_node->current_frame_host()->GetRenderWidgetHost());
+
+ RenderWidgetHostInputEventRouter* router =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetInputEventRouter();
+
+ RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+ RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
+ notifier.WaitForSurfaceReady();
+
+ // Target input event to child frame.
+ blink::WebMouseEvent child_event;
+ child_event.type = blink::WebInputEvent::MouseDown;
+ child_event.button = blink::WebPointerProperties::ButtonLeft;
+ child_event.x = 75;
+ child_event.y = 75;
+ child_event.clickCount = 1;
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+ router->RouteMouseEvent(root_view, &child_event);
+
+ EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+ EXPECT_EQ(75, main_frame_monitor.event().x);
+ EXPECT_EQ(75, main_frame_monitor.event().y);
+ EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+}
+
// Tests OOPIF rendering by checking that the RWH of the iframe generates
// OnSwapCompositorFrame message.
#if defined(OS_ANDROID)
@@ -1230,6 +1403,157 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
DepictFrameTree(root));
}
+// Ensure that the renderer process doesn't crash when the main frame navigates
+// a remote child to a page that results in a network error.
+// See https://crbug.com/558016.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteAfterError) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Load same-site page into iframe.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ FrameTreeNode* child = root->child_at(0);
+ GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ NavigateFrameToURL(child, http_url);
+ EXPECT_EQ(http_url, observer.last_navigation_url());
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ observer.Wait();
+ }
+
+ // Load cross-site page into iframe.
+ {
+ TestNavigationObserver observer(shell()->web_contents());
+ FrameTreeNode* child = root->child_at(0);
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), url);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url, observer.last_navigation_url());
+ observer.Wait();
+
+ // Ensure that we have created a new process for the subframe.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://foo.com/",
+ DepictFrameTree(root));
+ SiteInstance* site_instance =
+ child->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
+ }
+
+ // Stop the test server and try to navigate the remote frame.
+ {
+ GURL url = embedded_test_server()->GetURL("bar.com", "/title3.html");
+ EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
+ NavigateIframeToURL(shell()->web_contents(), "child-0", url);
+ }
+}
+
+// Ensure that a cross-site page ends up in the correct process when it
+// successfully loads after earlier encountering a network error for it.
+// See https://crbug.com/560511.
+// TODO(creis): Make the net error page show in the correct process as well,
+// per https://crbug.com/588314.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ProcessTransferAfterError) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ FrameTreeNode* child = root->child_at(0);
+ GURL url_a = child->current_url();
+
+ // Disable host resolution in the test server and try to navigate the subframe
+ // cross-site, which will lead to a committed net error (which looks like
+ // success to the TestNavigationObserver).
+ GURL url_b = embedded_test_server()->GetURL("b.com", "/title3.html");
+ host_resolver()->ClearRules();
+ TestNavigationObserver observer(shell()->web_contents());
+ NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url_b, observer.last_navigation_url());
+ EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount());
+
+ // PlzNavigate: Ensure that we have created a new process for the subframe.
+ if (IsBrowserSideNavigationEnabled()) {
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root));
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+ }
+
+ // The FrameTreeNode should update its URL (so that we don't affect other uses
+ // of the API), but the frame's last_successful_url shouldn't change and the
+ // origin should be empty.
+ // PlzNavigate: We have switched RenderFrameHosts for the subframe, so the
+ // last succesful url should be empty (since the frame only loaded an error
+ // page).
+ if (IsBrowserSideNavigationEnabled())
+ EXPECT_EQ(GURL(), child->current_frame_host()->last_successful_url());
+ else
+ EXPECT_EQ(url_a, child->current_frame_host()->last_successful_url());
+ EXPECT_EQ(url_b, child->current_url());
+ EXPECT_EQ("null", child->current_origin().Serialize());
+
+ // Try again after re-enabling host resolution.
+ host_resolver()->AddRule("*", "127.0.0.1");
+ NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
+ EXPECT_TRUE(observer.last_navigation_succeeded());
+ EXPECT_EQ(url_b, observer.last_navigation_url());
+
+ // The FrameTreeNode should have updated its URL and origin.
+ EXPECT_EQ(url_b, child->current_frame_host()->last_successful_url());
+ EXPECT_EQ(url_b, child->current_url());
+ EXPECT_EQ(url_b.GetOrigin().spec(),
+ child->current_origin().Serialize() + '/');
+
+ // Ensure that we have created a new process for the subframe.
+ // PlzNavigate: the subframe should still be in its separate process.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root));
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+
+ // Make sure that the navigation replaced the error page and that going back
+ // ends up on the original site.
+ EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount());
+ {
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+ }
+ EXPECT_EQ(
+ " Site A\n"
+ " +--Site A\n"
+ "Where A = http://a.com/",
+ DepictFrameTree(root));
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+ EXPECT_EQ(url_a, child->current_frame_host()->last_successful_url());
+ EXPECT_EQ(url_a, child->current_url());
+ EXPECT_EQ(url_a.GetOrigin().spec(),
+ child->current_origin().Serialize() + '/');
+}
+
// Verify that killing a cross-site frame's process B and then navigating a
// frame to B correctly recreates all proxies in B.
//
@@ -1273,10 +1597,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Navigate the second subframe to b.com to recreate the b.com process.
GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
NavigateFrameToURL(root->child_at(1), b_url);
- // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
- // fixed to use DidFinishLoad.
- EXPECT_TRUE(
- WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(b_url, observer.last_navigation_url());
EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
@@ -2004,6 +2324,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
#endif
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
MAYBE_FrameOwnerPropertiesPropagationScrolling) {
+#if defined(OS_MACOSX)
+ ui::test::ScopedPreferredScrollerStyle scroller_style_override(false);
+#endif
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_owner_properties_scrolling.html"));
NavigateToURL(shell(), main_url);
@@ -2063,11 +2386,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
set_scrolling_property(root->current_frame_host(), scrolling_values[i]);
for (size_t j = 0; j < arraysize(urls); ++j) {
NavigateFrameToURL(child, urls[j]);
-
- // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
- // fixed to use DidFinishLoad.
- EXPECT_TRUE(WaitForRenderFrameReady(child->current_frame_host()));
-
EXPECT_EQ(expect_scrollbar, has_scrollbar(child->current_frame_host()));
}
}
@@ -2142,9 +2460,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
" 'marginheight', '%d');", current_margin_height)));
NavigateFrameToURL(child, urls[i]);
- // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
- // fixed to use DidFinishLoad.
- EXPECT_TRUE(WaitForRenderFrameReady(child->current_frame_host()));
std::string actual_margin_width;
EXPECT_TRUE(ExecuteScriptAndExtractString(
@@ -2384,11 +2699,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
// Both frames should not be sandboxed to start with.
EXPECT_EQ(blink::WebSandboxFlags::None,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(0)->effective_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
- root->child_at(1)->current_replication_state().sandbox_flags);
+ root->child_at(1)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(1)->effective_sandbox_flags());
@@ -2399,7 +2714,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
"'allow-scripts');"));
// Check that updated sandbox flags are propagated to browser process.
- // The new flags should be set in current_replication_state(), while
+ // The new flags should be reflected in pending_sandbox_flags(), while
// effective_sandbox_flags() should still reflect the old flags, because
// sandbox flag updates take place only after navigations. "allow-scripts"
// resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
@@ -2407,8 +2722,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
blink::WebSandboxFlags expected_flags =
blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
~blink::WebSandboxFlags::AutomaticFeatures;
- EXPECT_EQ(expected_flags,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(0)->effective_sandbox_flags());
@@ -2434,8 +2748,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
// Confirm that the browser process has updated the frame's current sandbox
// flags.
- EXPECT_EQ(expected_flags,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
// Opening a popup in the now-sandboxed frame should fail.
@@ -2477,6 +2790,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
&success));
EXPECT_TRUE(success);
EXPECT_EQ(1u, Shell::windows().size());
+
+ // Child of a sandboxed frame should also be sandboxed on the browser side.
+ EXPECT_EQ(expected_flags,
+ root->child_at(0)->child_at(0)->effective_sandbox_flags());
}
// Check that dynamic updates to iframe sandbox flags are propagated correctly.
@@ -2511,26 +2828,20 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
blink::WebSandboxFlags expected_flags =
blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
~blink::WebSandboxFlags::AutomaticFeatures;
- EXPECT_EQ(expected_flags,
- root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(1)->effective_sandbox_flags());
// Navigate the second subframe to a page on bar.com. This will trigger a
- // remote-to-local frame swap in bar.com's process. The target page has
- // another frame, so use TestFrameNavigationObserver to wait for all frames
- // to be loaded.
- TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
+ // remote-to-local frame swap in bar.com's process.
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/frame_tree/page_with_one_frame.html"));
NavigateFrameToURL(root->child_at(1), bar_url);
- frame_observer.Wait();
EXPECT_EQ(bar_url, root->child_at(1)->current_url());
ASSERT_EQ(1U, root->child_at(1)->child_count());
// Confirm that the browser process has updated the current sandbox flags.
- EXPECT_EQ(expected_flags,
- root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags());
EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
// Opening a popup in the sandboxed second frame should fail.
@@ -2576,7 +2887,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// The frame should not be sandboxed to start with.
EXPECT_EQ(blink::WebSandboxFlags::None,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(0)->effective_sandbox_flags());
@@ -2587,7 +2898,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
"'allow-scripts');"));
// Check that updated sandbox flags are propagated to browser process.
- // The new flags should be set in current_replication_state(), while
+ // The new flags should be set in pending_sandbox_flags(), while
// effective_sandbox_flags() should still reflect the old flags, because
// sandbox flag updates take place only after navigations. "allow-scripts"
// resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
@@ -2595,8 +2906,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
blink::WebSandboxFlags expected_flags =
blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
~blink::WebSandboxFlags::AutomaticFeatures;
- EXPECT_EQ(expected_flags,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(blink::WebSandboxFlags::None,
root->child_at(0)->effective_sandbox_flags());
@@ -2611,8 +2921,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Confirm that the browser process has updated the frame's current sandbox
// flags.
- EXPECT_EQ(expected_flags,
- root->child_at(0)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
// Opening a popup in the now-sandboxed frame should fail.
@@ -2706,11 +3015,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
~blink::WebSandboxFlags::AutomaticFeatures &
~blink::WebSandboxFlags::Origin;
- EXPECT_EQ(expected_flags,
- root->child_at(1)->current_replication_state().sandbox_flags);
+ EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
// The child of the sandboxed frame should've inherited sandbox flags, so it
// should not be able to create popups.
+ EXPECT_EQ(expected_flags, bottom_child->effective_sandbox_flags());
bool success = false;
EXPECT_TRUE(
ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
@@ -2934,6 +3243,47 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
}
+// Ensure that the renderer does not crash when a local frame with a remote
+// parent frame is swapped from local to remote, then back to local again.
+// See https://crbug.com/585654.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigateSiblingsToSameProcess) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ FrameTreeNode* node2 = root->child_at(0);
+ FrameTreeNode* node3 = root->child_at(1);
+
+ // Navigate the second iframe to the same process as the first.
+ GURL frame_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
+ NavigateFrameToURL(node3, frame_url);
+
+ // Verify that they are in the same process.
+ EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+ EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+
+ // Navigate the first iframe into its parent's process.
+ GURL title_url = embedded_test_server()->GetURL("/title2.html");
+ NavigateFrameToURL(node2, title_url);
+ EXPECT_NE(node2->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+
+ // Return the first iframe to the same process as its sibling, and ensure
+ // that it does not crash.
+ NavigateFrameToURL(node2, frame_url);
+ EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(),
+ node3->current_frame_host()->GetSiteInstance());
+ EXPECT_TRUE(node2->current_frame_host()->IsRenderFrameLive());
+}
+
// Verify that load events for iframe elements work when the child frame is
// out-of-process. In such cases, the load event is forwarded from the child
// frame to the parent frame via the browser process.
@@ -3149,13 +3499,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
NavigateFrameToURL(child0, b_url);
- // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
- // TestFrameNavigationObserver is fixed to use DidFinishLoad.
- EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
NavigateFrameToURL(child1, c_url);
- EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
NavigateFrameToURL(child2, d_url);
- EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
EXPECT_EQ(
" Site A ------------ proxies for B C D\n"
@@ -3331,6 +3676,42 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
EXPECT_TRUE(success);
}
+// Test that cross-process popups can't be navigated to disallowed URLs by
+// their opener. This ensures that proper URL validation is performed when
+// RenderFrameProxyHosts are navigated. See https://crbug.com/595339.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigatePopupToIllegalURL) {
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // Open a cross-site popup.
+ GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ Shell* popup = OpenPopup(shell()->web_contents(), popup_url, "foo");
+ EXPECT_TRUE(popup);
+ EXPECT_NE(popup->web_contents()->GetSiteInstance(),
+ shell()->web_contents()->GetSiteInstance());
+
+ // From the opener, navigate the popup to a file:/// URL. This should be
+ // disallowed and result in an about:blank navigation.
+ GURL file_url("file:///");
+ NavigateNamedFrame(shell()->web_contents(), file_url, "foo");
+ EXPECT_TRUE(WaitForLoadStop(popup->web_contents()));
+ EXPECT_EQ(GURL(url::kAboutBlankURL),
+ popup->web_contents()->GetLastCommittedURL());
+
+ // Navigate popup back to a cross-site URL.
+ EXPECT_TRUE(NavigateToURL(popup, popup_url));
+ EXPECT_NE(popup->web_contents()->GetSiteInstance(),
+ shell()->web_contents()->GetSiteInstance());
+
+ // Now try the same test with a chrome:// URL.
+ GURL chrome_url(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ NavigateNamedFrame(shell()->web_contents(), chrome_url, "foo");
+ EXPECT_TRUE(WaitForLoadStop(popup->web_contents()));
+ EXPECT_EQ(GURL(url::kAboutBlankURL),
+ popup->web_contents()->GetLastCommittedURL());
+}
+
// Verify that named frames are discoverable from their opener's ancestors.
// See https://crbug.com/511474.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
@@ -3549,8 +3930,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Navigate popup's subframe to another site.
GURL frame_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
NavigateFrameToURL(popup_root->child_at(0), frame_url);
- EXPECT_TRUE(
- WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
// Check that the new subframe process still sees correct opener for its
// parent by sending a postMessage to subframe's parent.opener.
@@ -3691,8 +4070,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
GURL frame_url(
embedded_test_server()->GetURL("baz.com", "/post_message.html"));
NavigateFrameToURL(popup_root->child_at(0), frame_url);
- EXPECT_TRUE(
- WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
// Check that the second subframe's opener is still correct in the first
// subframe's new process. Verify it both in JS and with a postMessage.
@@ -3738,6 +4115,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
->root();
RenderFrameHostImpl* rfh = root->current_frame_host();
RenderViewHostImpl* rvh = rfh->render_view_host();
+ int rvh_routing_id = rvh->GetRoutingID();
+ SiteInstanceImpl* site_instance = rfh->GetSiteInstance();
RenderFrameDeletedObserver deleted_observer(rfh);
// Install a BrowserMessageFilter to drop SwapOut ACK messages in A's
@@ -3751,13 +4130,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestFrameNavigationObserver commit_observer(root);
shell()->LoadURL(b_url);
- commit_observer.Wait();
+ commit_observer.WaitForCommit();
+ EXPECT_FALSE(deleted_observer.deleted());
+ rfh->ResetSwapOutTimerForTesting();
// Since the SwapOut ACK for A->B is dropped, the first page's
// RenderFrameHost and RenderViewHost should be pending deletion after the
// last navigation.
- EXPECT_TRUE(root->render_manager()->IsPendingDeletion(rfh));
- EXPECT_TRUE(rvh->is_pending_deletion());
+ EXPECT_FALSE(rfh->is_active());
+ EXPECT_TRUE(root->render_manager()->IsViewPendingDeletion(rvh));
// Wait for process A to exit so we can reinitialize it cleanly for the next
// navigation. This can be removed once https://crbug.com/535246 is fixed.
@@ -3771,19 +4152,48 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
TestNavigationObserver navigation_observer(shell()->web_contents());
shell()->LoadURL(a_url);
RenderViewHostImpl* pending_rvh =
- root->render_manager()->pending_render_view_host();
- EXPECT_EQ(rvh->GetSiteInstance(), pending_rvh->GetSiteInstance());
- EXPECT_NE(rvh, pending_rvh);
-
- // Simulate that the dropped SwapOut ACK message arrives now on the original
- // RenderFrameHost, which should now get deleted.
- rfh->OnSwappedOut();
+ IsBrowserSideNavigationEnabled()
+ ? root->render_manager()->speculative_frame_host()->render_view_host()
+ : root->render_manager()->pending_render_view_host();
+ EXPECT_EQ(site_instance, pending_rvh->GetSiteInstance());
+ EXPECT_NE(rvh_routing_id, pending_rvh->GetRoutingID());
+
+ // TODO(alexmos, creis): Once https://crbug.com/535246 is fixed and the
+ // process_exit_observer is not needed above, we'll need to simulate that the
+ // dropped SwapOut ACK message arrives now on the original RenderFrameHost,
+ // causing it to be deleted.
EXPECT_TRUE(deleted_observer.deleted());
// Make sure the last navigation finishes without crashing.
navigation_observer.Wait();
}
+// Test for https://crbug.com/591478, where navigating to a cross-site page with
+// a subframe on the old site could cause the old RenderViewHost (now pending
+// deletion) to be reused.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ DontReusePendingDeleteRenderViewHostForSubframe) {
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ std::string script =
+ "window.onunload = function() { "
+ " var start = Date.now();"
+ " while (Date.now() - start < 1000);"
+ "}";
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
+
+ // Navigating cross-site with an iframe to the original site shouldn't crash.
+ GURL second_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(a)"));
+ EXPECT_TRUE(NavigateToURL(shell(), second_url));
+
+ // If the subframe is created while the main frame is pending deletion, then
+ // the RVH will be different.
+ // TODO(creis, alexmos): Find a way to assert this that isn't flaky. For now,
+ // the test is just likely (not certain) to catch regressions by crashing.
+}
+
// Check that when a cross-process frame acquires focus, the old focused frame
// loses focus and fires blur events. Starting on a page with a cross-site
// subframe, simulate mouse clicks to switch focus from root frame to subframe
@@ -4196,10 +4606,293 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenerSetLocation) {
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), cross_url);
}
+// Ensure that a cross-process subframe with a touch-handler can receive touch
+// events.
+#if defined(USE_AURA)
+// Browser process hit testing is not implemented on Android, and this test
+// requires Aura for RenderWidgetHostViewAura::OnTouchEvent().
+// https://crbug.com/491334
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ SubframeTouchEventRouting) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_nested_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = web_contents->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ GURL frame_url(
+ embedded_test_server()->GetURL("b.com", "/page_with_touch_handler.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+
+ // Synchronize with the child and parent renderers to guarantee that the
+ // surface information required for event hit testing is ready.
+ RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
+ root->child_at(0)->current_frame_host()->GetView());
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv));
+ notifier.WaitForSurfaceReady();
+
+ // Simulate touch event to sub-frame.
+ gfx::Point child_center(150, 150);
+ auto rwhv = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ ui::TouchEvent touch_event(ui::ET_TOUCH_PRESSED, child_center, 0, 0,
+ ui::EventTimeForNow(), 30.f, 30.f, 0.f, 0.f);
+ rwhv->OnTouchEvent(&touch_event);
+
+ // Verify touch handler in subframe was invoked
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ root->child_at(0)->current_frame_host(),
+ "window.domAutomationController.send(getLastTouchEvent());", &result));
+ EXPECT_EQ("touchstart", result);
+}
+
+namespace {
+
+// Declared here to be close to the SubframeGestureEventRouting test.
+void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner,
+ SyntheticGesture::Result result) {
+ EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+ runner->Quit();
+}
+
+} // namespace anonymous
+
+// Flaky under TSan. https://crbug.com/592320
+#if defined(THREAD_SANITIZER)
+#define MAYBE_SubframeGestureEventRouting DISABLED_SubframeGestureEventRouting
+#else
+#define MAYBE_SubframeGestureEventRouting SubframeGestureEventRouting
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_SubframeGestureEventRouting) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_nested_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = web_contents->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ GURL frame_url(
+ embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ auto child_frame_host = root->child_at(0)->current_frame_host();
+
+ // Synchronize with the child and parent renderers to guarantee that the
+ // surface information required for event hit testing is ready.
+ RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
+ child_frame_host->GetView());
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv));
+ notifier.WaitForSurfaceReady();
+
+ // There have been no GestureTaps sent yet.
+ {
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ child_frame_host,
+ "window.domAutomationController.send(getClickStatus());", &result));
+ EXPECT_EQ("0 clicks received", result);
+ }
+
+ // Simulate touch sequence to send GestureTap to sub-frame.
+ SyntheticTapGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ gfx::Point center(150, 150);
+ params.position = gfx::PointF(center.x(), center.y());
+ params.duration_ms = 100;
+ scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
+
+ scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
+
+ RenderWidgetHostImpl* render_widget_host =
+ root->current_frame_host()->GetRenderWidgetHost();
+ // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday.
+ render_widget_host->QueueSyntheticGesture(
+ std::move(gesture), base::Bind(OnSyntheticGestureCompleted, runner));
+
+ // We need to run the message loop while we wait for the synthetic gesture
+ // to be processed; the callback registered above will get us out of the
+ // message loop when that happens.
+ runner->Run();
+ runner = nullptr;
+
+ // Verify click handler in subframe was invoked
+ {
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ child_frame_host,
+ "window.domAutomationController.send(getClickStatus());", &result));
+ EXPECT_EQ("1 click received", result);
+ }
+}
+
+namespace {
+
+// Defined here to be close to
+// SitePerProcessBrowserTest.InputEventRouterGestureTargetQueueTest.
+void SendTouchTapWithExpectedTarget(
+ RenderWidgetHostViewBase* root_view,
+ const gfx::Point& touch_point,
+ RenderWidgetHostViewBase*& router_touch_target,
+ const RenderWidgetHostViewBase* expected_target) {
+ auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+ ui::TouchEvent touch_event_pressed(ui::ET_TOUCH_PRESSED, touch_point, 0,
+ 0, ui::EventTimeForNow(), 30.f, 30.f, 0.f,
+ 0.f);
+ root_view_aura->OnTouchEvent(&touch_event_pressed);
+ EXPECT_EQ(expected_target, router_touch_target);
+ ui::TouchEvent touch_event_released(ui::ET_TOUCH_RELEASED, touch_point,
+ 0, 0, ui::EventTimeForNow(), 30.f, 30.f,
+ 0.f, 0.f);
+ root_view_aura->OnTouchEvent(&touch_event_released);
+ EXPECT_EQ(nullptr, router_touch_target);
+}
+
+void SendGestureTapSequenceWithExpectedTarget(
+ RenderWidgetHostViewBase* root_view,
+ gfx::Point gesture_point,
+ RenderWidgetHostViewBase*& router_gesture_target,
+ const RenderWidgetHostViewBase* old_expected_target,
+ const RenderWidgetHostViewBase* expected_target) {
+ auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+
+ ui::GestureEvent gesture_begin_event(
+ gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_BEGIN));
+ root_view_aura->OnGestureEvent(&gesture_begin_event);
+ // We expect to still have the old gesture target in place for the
+ // GestureFlingCancel that will be inserted before GestureTapDown.
+ // Note: the GestureFlingCancel is inserted by RenderWidgetHostViewAura::
+ // OnGestureEvent() when it sees ui::ET_GESTURE_TAP_DOWN, so we don't
+ // explicitly add it here.
+ EXPECT_EQ(old_expected_target, router_gesture_target);
+
+ ui::GestureEvent gesture_tap_down_event(
+ gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+ root_view_aura->OnGestureEvent(&gesture_tap_down_event);
+ EXPECT_EQ(expected_target, router_gesture_target);
+
+ ui::GestureEvent gesture_show_press_event(
+ gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS));
+ root_view_aura->OnGestureEvent(&gesture_show_press_event);
+ EXPECT_EQ(expected_target, router_gesture_target);
+
+ ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP);
+ gesture_tap_details.set_tap_count(1);
+ ui::GestureEvent gesture_tap_event(
+ gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+ gesture_tap_details);
+ root_view_aura->OnGestureEvent(&gesture_tap_event);
+ EXPECT_EQ(expected_target, router_gesture_target);
+
+ ui::GestureEvent gesture_end_event(
+ gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END));
+ root_view_aura->OnGestureEvent(&gesture_end_event);
+ EXPECT_EQ(expected_target, router_gesture_target);
+}
+
+} // namespace anonymous
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ InputEventRouterGestureTargetQueueTest) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_nested_frames.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = web_contents->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ GURL frame_url(
+ embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ auto child_frame_host = root->child_at(0)->current_frame_host();
+
+ // Synchronize with the child and parent renderers to guarantee that the
+ // surface information required for event hit testing is ready.
+ auto rwhv_child =
+ static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
+ notifier.WaitForSurfaceReady();
+
+ // All touches & gestures are sent to the main frame's view, and should be
+ // routed appropriately from there.
+ auto rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView());
+
+ RenderWidgetHostInputEventRouter* router =
+ web_contents->GetInputEventRouter();
+ EXPECT_TRUE(router->gesture_target_queue_.empty());
+ EXPECT_EQ(nullptr, router->gesture_target_);
+
+ // Send touch sequence to main-frame.
+ gfx::Point main_frame_point(25, 25);
+ SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point,
+ router->touch_target_, rwhv_parent);
+ EXPECT_EQ(1LU, router->gesture_target_queue_.size());
+ EXPECT_EQ(nullptr, router->gesture_target_);
+
+
+ // Send touch sequence to child.
+ gfx::Point child_center(150, 150);
+ SendTouchTapWithExpectedTarget(rwhv_parent, child_center,
+ router->touch_target_, rwhv_child);
+ EXPECT_EQ(2LU, router->gesture_target_queue_.size());
+ EXPECT_EQ(nullptr, router->gesture_target_);
+
+ // Send another touch sequence to main frame.
+ SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point,
+ router->touch_target_, rwhv_parent);
+ EXPECT_EQ(3LU, router->gesture_target_queue_.size());
+ EXPECT_EQ(nullptr, router->gesture_target_);
+
+ // Send Gestures to clear GestureTargetQueue.
+
+ // The first touch sequence should generate a GestureTapDown, sent to the
+ // main frame.
+ SendGestureTapSequenceWithExpectedTarget(rwhv_parent, main_frame_point,
+ router->gesture_target_, nullptr,
+ rwhv_parent);
+ EXPECT_EQ(2LU, router->gesture_target_queue_.size());
+ // Note: rwhv_parent is the target used for GestureFlingCancel sent by
+ // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture
+ // sequence; the sequence itself goes to rwhv_child.
+ EXPECT_EQ(rwhv_parent, router->gesture_target_);
+
+ // The second touch sequence should generate a GestureTapDown, sent to the
+ // child frame.
+ SendGestureTapSequenceWithExpectedTarget(rwhv_parent, child_center,
+ router->gesture_target_, rwhv_parent,
+ rwhv_child);
+ EXPECT_EQ(1LU, router->gesture_target_queue_.size());
+ EXPECT_EQ(rwhv_child, router->gesture_target_);
+
+ // The third touch sequence should generate a GestureTapDown, sent to the
+ // main frame.
+ SendGestureTapSequenceWithExpectedTarget(rwhv_parent, main_frame_point,
+ router->gesture_target_, rwhv_child,
+ rwhv_parent);
+ EXPECT_EQ(0LU, router->gesture_target_queue_.size());
+ EXPECT_EQ(rwhv_parent, router->gesture_target_);
+}
+#endif // defined(USE_AURA)
+
// Ensure that a cross-process subframe can receive keyboard events when in
-// focus.
+// focus. Flaky: https://crbug.com/596508.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
- SubframeKeyboardEventRouting) {
+ DISABLED_SubframeKeyboardEventRouting) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4211,7 +4904,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
GURL frame_url(
embedded_test_server()->GetURL("b.com", "/page_with_input_field.html"));
NavigateFrameToURL(root->child_at(0), frame_url);
- EXPECT_TRUE(WaitForRenderFrameReady(root->child_at(0)->current_frame_host()));
// Focus the subframe and then its input field. The return value
// "input-focus" will be sent once the input field's focus event fires.
@@ -4248,7 +4940,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
//
// The test then presses <tab> six times to cycle through focused elements 1-6.
// The test then repeats this with <shift-tab> to cycle in reverse order.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SequentialFocusNavigation) {
+
+// Freqently times out. https://crbug.com/599730.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ DISABLED_SequentialFocusNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4355,33 +5050,25 @@ class ContextMenuObserverDelegate : public WebContentsDelegate {
DISALLOW_COPY_AND_ASSIGN(ContextMenuObserverDelegate);
};
-// Test that a mouse right-click to an out-of-process iframe causes a context
-// menu to be generated with the correct screen position.
-#if defined(OS_ANDROID)
-// Browser process hit testing is not implemented on Android.
-// https://crbug.com/491334
-#define MAYBE_CreateContextMenuTest DISABLED_CreateContextMenuTest
-#else
-#define MAYBE_CreateContextMenuTest CreateContextMenuTest
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CreateContextMenuTest) {
- if (!UseSurfacesEnabled())
- return;
-
- GURL main_url(embedded_test_server()->GetURL(
+// Helper function to run the CreateContextMenuTest in either normal
+// or high DPI mode.
+void CreateContextMenuTestHelper(
+ Shell* shell,
+ net::test_server::EmbeddedTestServer* embedded_test_server) {
+ GURL main_url(embedded_test_server->GetURL(
"/frame_tree/page_with_positioned_frame.html"));
- NavigateToURL(shell(), main_url);
+ EXPECT_TRUE(NavigateToURL(shell, main_url));
// It is safe to obtain the root frame tree node here, as it doesn't change.
- FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
->GetFrameTree()
->root();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_node = root->child_at(0);
- GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+ GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
EXPECT_EQ(site_url, child_node->current_url());
- EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ EXPECT_NE(shell->web_contents()->GetSiteInstance(),
child_node->current_frame_host()->GetSiteInstance());
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
@@ -4392,37 +5079,33 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CreateContextMenuTest) {
// Ensure that the child process renderer is ready to have input events
// routed to it. This happens when the browser process has received
// updated compositor surfaces from both renderer processes.
- gfx::Point point(75, 75);
- gfx::Point transformed_point;
- while (root_view->SurfaceIdNamespaceAtPoint(point, &transformed_point) !=
- rwhv_child->GetSurfaceIdNamespace()) {
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
- run_loop.Run();
- }
+ SurfaceHitTestReadyNotifier notifier(
+ static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
+ notifier.WaitForSurfaceReady();
// A WebContentsDelegate to listen for the ShowContextMenu message.
ContextMenuObserverDelegate context_menu_delegate;
- shell()->web_contents()->SetDelegate(&context_menu_delegate);
+ shell->web_contents()->SetDelegate(&context_menu_delegate);
RenderWidgetHostInputEventRouter* router =
- static_cast<WebContentsImpl*>(shell()->web_contents())
+ static_cast<WebContentsImpl*>(shell->web_contents())
->GetInputEventRouter();
+ gfx::Point point(75, 75);
+
// Target right-click event to child frame.
blink::WebMouseEvent click_event;
click_event.type = blink::WebInputEvent::MouseDown;
click_event.button = blink::WebPointerProperties::ButtonRight;
- click_event.x = 75;
- click_event.y = 75;
+ click_event.x = point.x();
+ click_event.y = point.y();
click_event.clickCount = 1;
router->RouteMouseEvent(root_view, &click_event);
// We also need a MouseUp event, needed by Windows.
click_event.type = blink::WebInputEvent::MouseUp;
- click_event.x = 75;
- click_event.y = 75;
+ click_event.x = point.x();
+ click_event.y = point.y();
router->RouteMouseEvent(root_view, &click_event);
context_menu_delegate.Wait();
@@ -4433,6 +5116,293 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CreateContextMenuTest) {
EXPECT_EQ(point.y(), params.y);
}
+// Test that a mouse right-click to an out-of-process iframe causes a context
+// menu to be generated with the correct screen position.
+#if defined(OS_ANDROID)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+#define MAYBE_CreateContextMenuTest DISABLED_CreateContextMenuTest
+#else
+#define MAYBE_CreateContextMenuTest CreateContextMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CreateContextMenuTest) {
+ CreateContextMenuTestHelper(shell(), embedded_test_server());
+}
+
+// Test that a mouse right-click to an out-of-process iframe causes a context
+// menu to be generated with the correct screen position on a screen with
+// non-default scale factor.
+#if defined(OS_ANDROID) || defined(OS_WIN)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+// Windows is disabled because of https://crbug.com/545547.
+#define MAYBE_HighDPICreateContextMenuTest DISABLED_HighDPICreateContextMenuTest
+#else
+#define MAYBE_HighDPICreateContextMenuTest HighDPICreateContextMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
+ MAYBE_HighDPICreateContextMenuTest) {
+ CreateContextMenuTestHelper(shell(), embedded_test_server());
+}
+
+class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
+ public:
+ ShowWidgetMessageFilter()
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ : content::BrowserMessageFilter(FrameMsgStart),
+#else
+ : content::BrowserMessageFilter(ViewMsgStart),
+#endif
+ message_loop_runner_(new content::MessageLoopRunner) {
+ }
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
+#else
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
+#endif
+ IPC_END_MESSAGE_MAP()
+ return false;
+ }
+
+ gfx::Rect last_initial_rect() const { return initial_rect_; }
+
+ void Wait() {
+ initial_rect_ = gfx::Rect();
+ message_loop_runner_->Run();
+ }
+
+ void Reset() {
+ initial_rect_ = gfx::Rect();
+ message_loop_runner_ = new content::MessageLoopRunner;
+ }
+
+ private:
+ ~ShowWidgetMessageFilter() override {}
+
+ void OnShowWidget(int route_id, const gfx::Rect& initial_rect) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this, route_id,
+ initial_rect));
+ }
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
+ MSG_ROUTING_NONE, params.bounds));
+ }
+#endif
+
+ void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) {
+ initial_rect_ = initial_rect;
+ message_loop_runner_->Quit();
+ }
+
+ scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+ gfx::Rect initial_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
+};
+
+// Test that clicking a select element in an out-of-process iframe creates
+// a popup menu in the correct position.
+#if defined(OS_ANDROID)
+// Surface-based hit testing and coordinate translation is not yet available
+// on Android.
+#define MAYBE_PopupMenuTest DISABLED_PopupMenuTest
+#else
+#define MAYBE_PopupMenuTest PopupMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_PopupMenuTest) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/cross_site_iframe_factory.html?a(a)"));
+ NavigateToURL(shell(), main_url);
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+#if !defined(OS_MACOSX)
+ // Unused variable on Mac.
+ RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+#endif
+ static_cast<WebContentsImpl*>(shell()->web_contents())->SendScreenRects();
+
+ content::TestNavigationObserver navigation_observer(shell()->web_contents());
+ FrameTreeNode* child_node = root->child_at(0);
+ GURL site_url(embedded_test_server()->GetURL(
+ "baz.com", "/site_isolation/page-with-select.html"));
+ NavigateFrameToURL(child_node, site_url);
+ navigation_observer.Wait();
+
+ RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child_node->current_frame_host()->GetSiteInstance());
+
+ scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
+ child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+ // Target left-click event to child frame.
+ blink::WebMouseEvent click_event;
+ click_event.type = blink::WebInputEvent::MouseDown;
+ click_event.button = blink::WebPointerProperties::ButtonLeft;
+ click_event.x = 15;
+ click_event.y = 15;
+ click_event.clickCount = 1;
+ rwhv_child->ProcessMouseEvent(click_event);
+
+ // Dismiss the popup.
+ click_event.x = 1;
+ click_event.y = 1;
+ rwhv_child->ProcessMouseEvent(click_event);
+
+ filter->Wait();
+ gfx::Rect popup_rect = filter->last_initial_rect();
+#if defined(OS_MACOSX)
+ // On Mac we receive the coordinates before they are transformed, so they
+ // are still relative to the out-of-process iframe origin.
+ EXPECT_EQ(popup_rect.x(), 9);
+ EXPECT_EQ(popup_rect.y(), 9);
+#else
+ EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
+ EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 94);
+#endif
+}
+
+// Test that clicking a select element in a nested out-of-process iframe creates
+// a popup menu in the correct position, even if the top-level page repositions
+// its out-of-process iframe. This verifies that screen positioning information
+// is propagating down the frame tree correctly.
+#if defined(OS_ANDROID)
+// Surface-based hit testing and coordinate translation is not yet avaiable on
+// Android.
+#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
+#else
+// Times out frequently. https://crbug.com/599730.
+#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_NestedPopupMenuTest) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/cross_site_iframe_factory.html?a(b(c))"));
+ NavigateToURL(shell(), main_url);
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+#if !defined(OS_MACOSX)
+ // Undefined variable on Mac.
+ RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+#endif
+ static_cast<WebContentsImpl*>(shell()->web_contents())->SendScreenRects();
+
+ // For clarity, we are labeling the frame tree nodes as:
+ // - root_node
+ // \-> b_node (out-of-process from root and c_node)
+ // \-> c_node (out-of-process from root and b_node)
+
+ content::TestNavigationObserver navigation_observer(shell()->web_contents());
+ FrameTreeNode* b_node = root->child_at(0);
+ FrameTreeNode* c_node = b_node->child_at(0);
+ GURL site_url(embedded_test_server()->GetURL(
+ "baz.com", "/site_isolation/page-with-select.html"));
+ NavigateFrameToURL(c_node, site_url);
+
+ RenderWidgetHostViewBase* rwhv_c_node =
+ static_cast<RenderWidgetHostViewBase*>(
+ c_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ c_node->current_frame_host()->GetSiteInstance());
+
+ scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
+ c_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+ // Target left-click event to child frame.
+ blink::WebMouseEvent click_event;
+ click_event.type = blink::WebInputEvent::MouseDown;
+ click_event.button = blink::WebPointerProperties::ButtonLeft;
+ click_event.x = 15;
+ click_event.y = 15;
+ click_event.clickCount = 1;
+ rwhv_c_node->ProcessMouseEvent(click_event);
+
+ // Prompt the WebContents to dismiss the popup by clicking elsewhere.
+ click_event.x = 1;
+ click_event.y = 1;
+ rwhv_c_node->ProcessMouseEvent(click_event);
+
+ filter->Wait();
+
+ gfx::Rect popup_rect = filter->last_initial_rect();
+
+#if defined(OS_MACOSX)
+ EXPECT_EQ(popup_rect.x(), 9);
+ EXPECT_EQ(popup_rect.y(), 9);
+#else
+ EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
+ EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 154);
+#endif
+
+ // Save the screen rect for b_node. Since it updates asynchronously from
+ // the script command that changes it, we need to wait for it to change
+ // before attempting to create the popup widget again.
+ gfx::Rect last_b_node_bounds_rect =
+ b_node->current_frame_host()->GetView()->GetViewBounds();
+
+ std::string script =
+ "var iframe = document.querySelector('iframe');"
+ "iframe.style.position = 'absolute';"
+ "iframe.style.left = 150;"
+ "iframe.style.top = 150;";
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+
+ filter->Reset();
+
+ // Busy loop to wait for b_node's screen rect to get updated. There
+ // doesn't seem to be any better way to find out when this happens.
+ while (last_b_node_bounds_rect.x() ==
+ b_node->current_frame_host()->GetView()->GetViewBounds().x() &&
+ last_b_node_bounds_rect.y() ==
+ b_node->current_frame_host()->GetView()->GetViewBounds().y()) {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+ run_loop.Run();
+ }
+
+ click_event.button = blink::WebPointerProperties::ButtonLeft;
+ click_event.x = 15;
+ click_event.y = 15;
+ click_event.clickCount = 1;
+ rwhv_c_node->ProcessMouseEvent(click_event);
+
+ click_event.x = 1;
+ click_event.y = 1;
+ rwhv_c_node->ProcessMouseEvent(click_event);
+
+ filter->Wait();
+
+ popup_rect = filter->last_initial_rect();
+
+#if defined(OS_MACOSX)
+ EXPECT_EQ(popup_rect.x(), 9);
+ EXPECT_EQ(popup_rect.y(), 9);
+#else
+ EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 203);
+ EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 248);
+#endif
+}
+
// Test for https://crbug.com/526304, where a parent frame executes a
// remote-to-local navigation on a child frame and immediately removes the same
// child frame. This test exercises the path where the detach happens before
@@ -4511,6 +5481,37 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_EQ(1, child_count);
}
+// Similar to NavigateProxyAndDetachBeforeCommit, but uses a synchronous
+// navigation to about:blank and the parent removes the child frame in a load
+// event handler for the subframe.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateAboutBlankAndDetach) {
+ GURL main_url(
+ embedded_test_server()->GetURL("a.com", "/remove_frame_on_load.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ WebContents* contents = shell()->web_contents();
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
+ EXPECT_EQ(1U, root->child_count());
+ FrameTreeNode* child = root->child_at(0);
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+
+ // Navigate the child frame to "about:blank" from the parent document.
+ TestNavigationObserver observer(shell()->web_contents());
+ EXPECT_TRUE(
+ ExecuteScript(root->current_frame_host(),
+ base::StringPrintf("f.src = '%s'", url::kAboutBlankURL)));
+ observer.Wait();
+
+ // Make sure the a.com renderer does not crash and the frame is removed.
+ int child_count = 0;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(
+ root->current_frame_host(), "domAutomationController.send(frames.length)",
+ &child_count));
+ EXPECT_EQ(0, child_count);
+}
+
// Test for https://crbug.com/568670. In A-embed-B, simultaneously have B
// create a new (local) child frame, and have A detach B's proxy. The child
// frame creation sends an IPC to create a new proxy in A's process, and if
@@ -4602,11 +5603,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// observer to ensure there is no crash when a new RenderFrame creation is
// attempted.
RenderProcessHost* process =
- node->render_manager()->pending_frame_host()->GetProcess();
+ IsBrowserSideNavigationEnabled()
+ ? node->render_manager()->speculative_frame_host()->GetProcess()
+ : node->render_manager()->pending_frame_host()->GetProcess();
RenderProcessHostWatcher watcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
int frame_routing_id =
- node->render_manager()->pending_frame_host()->GetRoutingID();
+ IsBrowserSideNavigationEnabled()
+ ? node->render_manager()->speculative_frame_host()->GetRoutingID()
+ : node->render_manager()->pending_frame_host()->GetRoutingID();
int proxy_routing_id =
node->render_manager()->GetProxyToParent()->GetRoutingID();
@@ -4625,6 +5630,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
params.previous_sibling_routing_id = MSG_ROUTING_NONE;
params.widget_params.routing_id = MSG_ROUTING_NONE;
params.widget_params.hidden = true;
+ params.replication_state.name = "name";
+ params.replication_state.unique_name = "name";
process->Send(new FrameMsg_NewFrame(params));
}
@@ -4689,6 +5696,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ParentDetachRemoteChild) {
params.previous_sibling_routing_id = MSG_ROUTING_NONE;
params.widget_params.routing_id = widget_routing_id;
params.widget_params.hidden = true;
+ params.replication_state.name = "name";
+ params.replication_state.unique_name = "name";
process->Send(new FrameMsg_NewFrame(params));
}
@@ -4745,4 +5754,572 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, VisibilityChanged) {
EXPECT_TRUE(show_observer.WaitUntilSatisfied());
}
+// Verify that sandbox flags inheritance works across multiple levels of
+// frames. See https://crbug.com/576845.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsInheritance) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Set sandbox flags for child frame.
+ EXPECT_TRUE(ExecuteScript(
+ root->current_frame_host(),
+ "document.querySelector('iframe').sandbox = 'allow-scripts';"));
+
+ // Calculate expected flags. Note that "allow-scripts" resets both
+ // WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits per
+ // blink::parseSandboxPolicy().
+ blink::WebSandboxFlags expected_flags =
+ blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ ~blink::WebSandboxFlags::AutomaticFeatures;
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::None,
+ root->child_at(0)->effective_sandbox_flags());
+
+ // Navigate child frame so that the sandbox flags take effect. Use a page
+ // with three levels of frames and make sure all frames properly inherit
+ // sandbox flags.
+ GURL frame_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(c(d))"));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+
+ // Wait for subframes to load as well.
+ ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ // Check each new frame's sandbox flags on the browser process side.
+ FrameTreeNode* b_child = root->child_at(0);
+ FrameTreeNode* c_child = b_child->child_at(0);
+ FrameTreeNode* d_child = c_child->child_at(0);
+ EXPECT_EQ(expected_flags, b_child->effective_sandbox_flags());
+ EXPECT_EQ(expected_flags, c_child->effective_sandbox_flags());
+ EXPECT_EQ(expected_flags, d_child->effective_sandbox_flags());
+
+ // Check whether each frame is sandboxed on the renderer side, by seeing if
+ // each frame's origin is unique ("null").
+ EXPECT_EQ("null", GetDocumentOrigin(b_child));
+ EXPECT_EQ("null", GetDocumentOrigin(c_child));
+ EXPECT_EQ("null", GetDocumentOrigin(d_child));
+}
+
+// Check that sandbox flags are not inherited before they take effect. Create
+// a child frame, update its sandbox flags but don't navigate the frame, and
+// ensure that a new cross-site grandchild frame doesn't inherit the new flags
+// (which shouldn't have taken effect).
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ SandboxFlagsNotInheritedBeforeNavigation) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ NavigateToURL(shell(), main_url);
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Set sandbox flags for child frame.
+ EXPECT_TRUE(ExecuteScript(
+ root->current_frame_host(),
+ "document.querySelector('iframe').sandbox = 'allow-scripts';"));
+
+ // These flags should be pending but not take effect, since there's been no
+ // navigation.
+ blink::WebSandboxFlags expected_flags =
+ blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ ~blink::WebSandboxFlags::AutomaticFeatures;
+ FrameTreeNode* child = root->child_at(0);
+ EXPECT_EQ(expected_flags, child->pending_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::None, child->effective_sandbox_flags());
+
+ // Add a new grandchild frame and navigate it cross-site.
+ RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
+ EXPECT_TRUE(ExecuteScript(
+ child->current_frame_host(),
+ "document.body.appendChild(document.createElement('iframe'));"));
+ frame_observer.Wait();
+
+ FrameTreeNode* grandchild = child->child_at(0);
+ GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ TestFrameNavigationObserver navigation_observer(grandchild);
+ NavigateFrameToURL(grandchild, frame_url);
+ navigation_observer.Wait();
+
+ // Since the update flags haven't yet taken effect in its parent, this
+ // grandchild frame should not be sandboxed.
+ EXPECT_EQ(blink::WebSandboxFlags::None, grandchild->pending_sandbox_flags());
+ EXPECT_EQ(blink::WebSandboxFlags::None,
+ grandchild->effective_sandbox_flags());
+
+ // Check that the grandchild frame isn't sandboxed on the renderer side. If
+ // sandboxed, its origin would be unique ("null").
+ EXPECT_EQ(frame_url.GetOrigin().spec(), GetDocumentOrigin(grandchild) + "/");
+}
+
+// Verify that popups opened from sandboxed frames inherit sandbox flags from
+// their opener, and that they keep these inherited flags after being navigated
+// cross-site. See https://crbug.com/483584.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NewPopupInheritsSandboxFlagsFromOpener) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Set sandbox flags for child frame.
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+ "document.querySelector('iframe').sandbox = "
+ " 'allow-scripts allow-popups';"));
+
+ // Calculate expected flags. Note that "allow-scripts" resets both
+ // WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits per
+ // blink::parseSandboxPolicy().
+ blink::WebSandboxFlags expected_flags =
+ blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ ~blink::WebSandboxFlags::AutomaticFeatures &
+ ~blink::WebSandboxFlags::Popups;
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
+
+ // Navigate child frame cross-site. The sandbox flags should take effect.
+ GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ TestFrameNavigationObserver frame_observer(root->child_at(0));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ frame_observer.Wait();
+ EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
+
+ // Verify that they've also taken effect on the renderer side. The sandboxed
+ // frame's origin should be unique.
+ EXPECT_EQ("null", GetDocumentOrigin(root->child_at(0)));
+
+ // Open a popup named "foo" from the sandboxed child frame.
+ Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
+ GURL(url::kAboutBlankURL), "foo");
+ EXPECT_TRUE(foo_shell);
+
+ FrameTreeNode* foo_root =
+ static_cast<WebContentsImpl*>(foo_shell->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Check that the sandbox flags for new popup are correct in the browser
+ // process.
+ EXPECT_EQ(expected_flags, foo_root->effective_sandbox_flags());
+
+ // The popup's origin should be unique, since it's sandboxed.
+ EXPECT_EQ("null", GetDocumentOrigin(foo_root));
+
+ // Navigate the popup cross-site. This should keep the unique origin and the
+ // inherited sandbox flags.
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
+ TestFrameNavigationObserver popup_observer(foo_root);
+ EXPECT_TRUE(ExecuteScript(foo_root->current_frame_host(),
+ "location.href = '" + c_url.spec() + "';"));
+ popup_observer.Wait();
+ EXPECT_EQ(c_url, foo_shell->web_contents()->GetLastCommittedURL());
+
+ // Confirm that the popup is still sandboxed, both on browser and renderer
+ // sides.
+ EXPECT_EQ(expected_flags, foo_root->effective_sandbox_flags());
+ EXPECT_EQ("null", GetDocumentOrigin(foo_root));
+}
+
+// Verify that popups opened from frames sandboxed with the
+// "allow-popups-to-escape-sandbox" directive do *not* inherit sandbox flags
+// from their opener.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ OpenUnsandboxedPopupFromSandboxedFrame) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Set sandbox flags for child frame, specifying that popups opened from it
+ // should not be sandboxed.
+ EXPECT_TRUE(ExecuteScript(
+ root->current_frame_host(),
+ "document.querySelector('iframe').sandbox = "
+ " 'allow-scripts allow-popups allow-popups-to-escape-sandbox';"));
+
+ // Set expected flags for the child frame. Note that "allow-scripts" resets
+ // both WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits
+ // per blink::parseSandboxPolicy().
+ blink::WebSandboxFlags expected_flags =
+ blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
+ ~blink::WebSandboxFlags::AutomaticFeatures &
+ ~blink::WebSandboxFlags::Popups &
+ ~blink::WebSandboxFlags::PropagatesToAuxiliaryBrowsingContexts;
+ EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
+
+ // Navigate child frame cross-site. The sandbox flags should take effect.
+ GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ TestFrameNavigationObserver frame_observer(root->child_at(0));
+ NavigateFrameToURL(root->child_at(0), frame_url);
+ frame_observer.Wait();
+ EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
+
+ // Open a cross-site popup named "foo" from the child frame.
+ GURL b_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
+ Shell* foo_shell =
+ OpenPopup(root->child_at(0)->current_frame_host(), b_url, "foo");
+ EXPECT_TRUE(foo_shell);
+
+ FrameTreeNode* foo_root =
+ static_cast<WebContentsImpl*>(foo_shell->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Check that the sandbox flags for new popup are correct in the browser
+ // process. They should not have been inherited.
+ EXPECT_EQ(blink::WebSandboxFlags::None, foo_root->effective_sandbox_flags());
+
+ // The popup's origin should match |b_url|, since it's not sandboxed.
+ std::string popup_origin;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ foo_root->current_frame_host(),
+ "domAutomationController.send(document.origin)",
+ &popup_origin));
+ EXPECT_EQ(b_url.GetOrigin().spec(), popup_origin + "/");
+}
+
+// Tests that the WebContents is notified when passive mixed content is
+// displayed in an OOPIF. The test ignores cert errors so that an HTTPS
+// iframe can be loaded from a site other than localhost (the
+// EmbeddedTestServer serves a certificate that is valid for localhost).
+// This test crashes on Windows under Dr. Memory, see https://crbug.com/600942.
+#if defined(OS_WIN)
+#define MAYBE_PassiveMixedContentInIframe DISABLED_PassiveMixedContentInIframe
+#else
+#define MAYBE_PassiveMixedContentInIframe PassiveMixedContentInIframe
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest,
+ MAYBE_PassiveMixedContentInIframe) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory("content/test/data");
+ ASSERT_TRUE(https_server.Start());
+ SetupCrossSiteRedirector(&https_server);
+
+ GURL iframe_url(
+ https_server.GetURL("/mixed-content/basic-passive-in-iframe.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), iframe_url));
+ EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent());
+
+ // When the subframe navigates, the WebContents should still be marked
+ // as having displayed insecure content.
+ GURL navigate_url(https_server.GetURL("/title1.html"));
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ NavigateFrameToURL(root->child_at(0), navigate_url);
+ EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent());
+
+ // When the main frame navigates, it should no longer be marked as
+ // displaying insecure content.
+ EXPECT_TRUE(
+ NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html")));
+ EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+}
+
+// Tests that, when a parent frame is set to strictly block mixed
+// content via Content Security Policy, child OOPIFs cannot display
+// mixed content.
+IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest,
+ PassiveMixedContentInIframeWithStrictBlocking) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory("content/test/data");
+ ASSERT_TRUE(https_server.Start());
+ SetupCrossSiteRedirector(&https_server);
+
+ GURL iframe_url_with_strict_blocking(https_server.GetURL(
+ "/mixed-content/basic-passive-in-iframe-with-strict-blocking.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), iframe_url_with_strict_blocking));
+ EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ EXPECT_TRUE(root->current_replication_state()
+ .should_enforce_strict_mixed_content_checking);
+ EXPECT_TRUE(root->child_at(0)
+ ->current_replication_state()
+ .should_enforce_strict_mixed_content_checking);
+
+ // When the subframe navigates, it should still be marked as enforcing
+ // strict mixed content.
+ GURL navigate_url(https_server.GetURL("/title1.html"));
+ NavigateFrameToURL(root->child_at(0), navigate_url);
+ EXPECT_TRUE(root->current_replication_state()
+ .should_enforce_strict_mixed_content_checking);
+ EXPECT_TRUE(root->child_at(0)
+ ->current_replication_state()
+ .should_enforce_strict_mixed_content_checking);
+
+ // When the main frame navigates, it should no longer be marked as
+ // enforcing strict mixed content.
+ EXPECT_TRUE(
+ NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html")));
+ EXPECT_FALSE(root->current_replication_state()
+ .should_enforce_strict_mixed_content_checking);
+}
+
+// Tests that active mixed content is blocked in an OOPIF. The test
+// ignores cert errors so that an HTTPS iframe can be loaded from a site
+// other than localhost (the EmbeddedTestServer serves a certificate
+// that is valid for localhost).
+IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest,
+ ActiveMixedContentInIframe) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory("content/test/data");
+ ASSERT_TRUE(https_server.Start());
+ SetupCrossSiteRedirector(&https_server);
+
+ GURL iframe_url(
+ https_server.GetURL("/mixed-content/basic-active-in-iframe.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), iframe_url));
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* mixed_child = root->child_at(0)->child_at(0);
+ ASSERT_TRUE(mixed_child);
+ // The child iframe attempted to create a mixed iframe; this should
+ // have been blocked, so the mixed iframe should not have committed a
+ // load.
+ EXPECT_FALSE(mixed_child->has_committed_real_load());
+}
+
+// Test setting a cross-origin iframe to display: none.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframeDisplayNone) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+ NavigateToURL(shell(), main_url);
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ RenderWidgetHost* root_render_widget_host =
+ root->current_frame_host()->GetRenderWidgetHost();
+
+ // Set the iframe to display: none.
+ EXPECT_TRUE(
+ ExecuteScript(shell()->web_contents(),
+ "document.querySelector('iframe').style.display = 'none'"));
+
+ // Waits until pending frames are done.
+ scoped_ptr<MainThreadFrameObserver> observer(
+ new MainThreadFrameObserver(root_render_widget_host));
+ observer->Wait();
+
+ // Force the renderer to generate a new frame.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.body.style.background = 'black'"));
+
+ // Waits for the next frame.
+ observer->Wait();
+}
+
+// Test that a cross-origin iframe can be blocked by X-Frame-Options and CSP
+// frame-ancestors.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ CrossSiteIframeBlockedByXFrameOptionsOrCSP) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ NavigateToURL(shell(), main_url);
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // Add a load event handler for the iframe element.
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.querySelector('iframe').onload = "
+ " function() { document.title = 'loaded'; };"));
+
+ GURL blocked_urls[] = {
+ embedded_test_server()->GetURL("b.com", "/frame-ancestors-none.html"),
+ embedded_test_server()->GetURL("b.com", "/x-frame-options-deny.html")
+ };
+
+ for (size_t i = 0; i < arraysize(blocked_urls); ++i) {
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+ "document.title = 'not loaded';"));
+ base::string16 expected_title(base::UTF8ToUTF16("loaded"));
+ TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+
+ // Navigate the subframe to a blocked URL.
+ TestNavigationObserver load_observer(shell()->web_contents());
+ EXPECT_TRUE(ExecuteScript(
+ shell()->web_contents(),
+ "frames[0].location.href = '" + blocked_urls[i].spec() + "';"));
+ load_observer.Wait();
+
+ // The blocked frame's origin should become unique.
+ EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
+
+ // The blocked frame should still fire a load event in its parent's process.
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+
+ // Check that the current RenderFrameHost has stopped loading.
+ EXPECT_FALSE(root->child_at(0)->current_frame_host()->is_loading());
+
+ // The blocked navigation should behave like an empty 200 response. Make
+ // sure that the frame's document.title is empty: this double-checks both
+ // that the blocked URL's contents wasn't loaded, and that the old page
+ // isn't active anymore (both of these pages have non-empty titles).
+ std::string frame_title;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ root->child_at(0)->current_frame_host(),
+ "domAutomationController.send(document.title)", &frame_title));
+ EXPECT_EQ("", frame_title);
+
+ // Navigate the subframe to another cross-origin page and ensure that this
+ // navigation succeeds. Use a renderer-initiated navigation to test the
+ // transfer logic, which used to have some issues with this.
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
+ EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", c_url));
+ EXPECT_EQ(c_url, root->child_at(0)->current_url());
+
+ // When a page gets blocked due to XFO or CSP, it is sandboxed with the
+ // SandboxOrigin flag (i.e., its origin is set to be unique) to ensure that
+ // the blocked page is seen as cross-origin. However, those flags shouldn't
+ // affect future navigations for a frame. Verify this for the above
+ // navigation.
+ EXPECT_EQ(c_url.GetOrigin().spec(),
+ root->child_at(0)->current_origin().Serialize() + "/");
+ EXPECT_EQ(blink::WebSandboxFlags::None,
+ root->child_at(0)->effective_sandbox_flags());
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScreenCoordinates) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+ NavigateToURL(shell(), main_url);
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ FrameTreeNode* child = root->child_at(0);
+
+ const char* properties[] = {"screenX", "screenY", "outerWidth",
+ "outerHeight"};
+
+ for (const char* property : properties) {
+ std::string script = "window.domAutomationController.send(window.";
+ script += property;
+ script += ");";
+ int root_value = 1;
+ int child_value = 2;
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(root->current_frame_host(),
+ script.c_str(), &root_value));
+
+ EXPECT_TRUE(ExecuteScriptAndExtractInt(child->current_frame_host(),
+ script.c_str(), &child_value));
+
+ EXPECT_EQ(root_value, child_value);
+ }
+}
+
+// Tests that the certificate store is updated during a cross-site
+// redirect navigation. (See https://crbug.com/561754.) Ignores
+// certificate errors so that it can use the cross-site redirector to
+// redirect from HTTPS to HTTPS.
+IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest,
+ CrossSiteRedirectCertificateStore) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory("content/test/data");
+ ASSERT_TRUE(https_server.Start());
+ SetupCrossSiteRedirector(&https_server);
+
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ ASSERT_TRUE(rdh);
+ MockCertStore mock_cert_store;
+ rdh->cert_store_for_testing_ = &mock_cert_store;
+
+ // First, navigate to an |https_server| URL to ensure that the site
+ // instance is assigned a site. This will force a renderer transfer to
+ // happen on the following navigation that redirects to a different
+ // site.
+ GURL url(https_server.GetURL("/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ int original_process_id =
+ shell()->web_contents()->GetRenderProcessHost()->GetID();
+
+ url = https_server.GetURL("/cross-site/a.test/title1.html");
+ // NavigateToURL() returns false because the committed URL doesn't
+ // match |url| (because it redirected).
+ EXPECT_FALSE(NavigateToURL(shell(), url));
+ EXPECT_TRUE(IsLastCommittedEntryOfPageType(shell()->web_contents(),
+ PAGE_TYPE_NORMAL));
+ int new_process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+
+ // Test that the mock certificate store saw the certificate associated with
+ // the new renderer process.
+ EXPECT_NE(original_process_id, new_process_id);
+ scoped_refptr<net::X509Certificate> original_cert;
+ scoped_refptr<net::X509Certificate> transfer_cert;
+ ASSERT_TRUE(
+ mock_cert_store.RetrieveCert(original_process_id, &original_cert));
+ ASSERT_TRUE(mock_cert_store.RetrieveCert(new_process_id, &transfer_cert));
+ EXPECT_TRUE(https_server.GetCertificate()->Equals(original_cert.get()));
+ EXPECT_TRUE(https_server.GetCertificate()->Equals(transfer_cert.get()));
+ // Test that the final cert id stored in the navigation entry is the
+ // cert id corresponding to the second renderer process.
+ EXPECT_EQ(new_process_id, shell()
+ ->web_contents()
+ ->GetController()
+ .GetVisibleEntry()
+ ->GetSSL()
+ .cert_id);
+}
+
+// Tests that the swapped out state on RenderViewHost is properly reset when
+// the main frame is navigated to the same SiteInstance as one of its child
+// frames.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ NavigateMainFrameToChildSite) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ WebContentsImpl* contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = contents->GetFrameTree()->root();
+ EXPECT_EQ(1U, root->child_count());
+
+ // Ensure the RenderViewHost for the SiteInstance of the child is considered
+ // in swapped out state.
+ RenderViewHostImpl* rvh = contents->GetFrameTree()->GetRenderViewHost(
+ root->child_at(0)->current_frame_host()->GetSiteInstance());
+ EXPECT_TRUE(rvh->is_swapped_out_);
+
+ // Have the child frame navigate its parent to its SiteInstance.
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ std::string script = base::StringPrintf(
+ "window.domAutomationController.send("
+ "parent.location = '%s');",
+ b_url.spec().c_str());
+
+ TestFrameNavigationObserver frame_observer(root);
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script));
+ frame_observer.Wait();
+ EXPECT_EQ(b_url, root->current_url());
+
+ // Verify that the same RenderViewHost is preserved and that it is no longer
+ // in swapped out state.
+ EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost(
+ root->current_frame_host()->GetSiteInstance()));
+ EXPECT_FALSE(rvh->is_swapped_out_);
+}
+
} // namespace content
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.cc b/chromium/content/browser/speech/speech_recognizer_impl.cc
index 273187d4b76..f11b5d306a2 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl.cc
@@ -793,7 +793,8 @@ void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() {
// Close has completed (in the audio thread) and automatically destroy it
// afterwards (upon return from OnAudioClosed).
audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed,
- this, audio_controller_));
+ this,
+ base::RetainedRef(audio_controller_)));
audio_controller_ = NULL; // The controller is still refcounted by Bind.
audio_log_->OnClosed(0);
}
@@ -835,6 +836,9 @@ SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(FSMEvent event_value)
engine_error(SPEECH_RECOGNITION_ERROR_NONE) {
}
+SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(const FSMEventArgs& other) =
+ default;
+
SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() {
}
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.h b/chromium/content/browser/speech/speech_recognizer_impl.h
index ff2484beed0..007142b9228 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.h
+++ b/chromium/content/browser/speech/speech_recognizer_impl.h
@@ -81,6 +81,7 @@ class CONTENT_EXPORT SpeechRecognizerImpl
struct FSMEventArgs {
explicit FSMEventArgs(FSMEvent event_value);
+ FSMEventArgs(const FSMEventArgs& other);
~FSMEventArgs();
FSMEvent event;
diff --git a/chromium/content/browser/ssl/ssl_client_auth_handler.cc b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
index 3c1e42cb1f7..9f5efaeee36 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
@@ -45,7 +45,7 @@ class ClientCertificateDelegateImpl : public ClientCertificateDelegate {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SSLClientAuthHandler::ContinueWithCertificate, handler_,
- make_scoped_refptr(cert)));
+ base::RetainedRef(cert)));
}
private:
@@ -88,7 +88,7 @@ class SSLClientAuthHandler::Core : public base::RefCountedThreadSafe<Core> {
client_cert_store_(std::move(client_cert_store)),
cert_request_info_(cert_request_info) {}
- bool has_client_cert_store() const { return client_cert_store_; }
+ bool has_client_cert_store() const { return !!client_cert_store_; }
void GetClientCerts() {
if (client_cert_store_) {
@@ -178,8 +178,7 @@ void SSLClientAuthHandler::DidGetClientCerts() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SSLClientAuthHandler::ContinueWithCertificate,
- weak_factory_.GetWeakPtr(),
- scoped_refptr<net::X509Certificate>()));
+ weak_factory_.GetWeakPtr(), nullptr));
return;
}
@@ -198,7 +197,7 @@ void SSLClientAuthHandler::DidGetClientCerts() {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&SelectCertificateOnUIThread, render_process_host_id,
- render_frame_host_id, cert_request_info_,
+ render_frame_host_id, base::RetainedRef(cert_request_info_),
weak_factory_.GetWeakPtr()));
}
diff --git a/chromium/content/browser/ssl/ssl_client_auth_handler.h b/chromium/content/browser/ssl/ssl_client_auth_handler.h
index 72c6cbd4dea..1deafbc8a1d 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.h
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/content/browser/storage_partition_impl.cc b/chromium/content/browser/storage_partition_impl.cc
index 0afff15d733..28b0eb13450 100644
--- a/chromium/content/browser/storage_partition_impl.cc
+++ b/chromium/content/browser/storage_partition_impl.cc
@@ -18,7 +18,6 @@
#include "content/browser/geofencing/geofencing_manager.h"
#include "content/browser/gpu/shader_disk_cache.h"
#include "content/browser/host_zoom_map_impl.h"
-#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "content/public/browser/browser_context.h"
@@ -349,7 +348,6 @@ StoragePartitionImpl::StoragePartitionImpl(
storage::SpecialStoragePolicy* special_storage_policy,
GeofencingManager* geofencing_manager,
HostZoomLevelContext* host_zoom_level_context,
- NavigatorConnectContextImpl* navigator_connect_context,
PlatformNotificationContextImpl* platform_notification_context,
BackgroundSyncContextImpl* background_sync_context)
: partition_path_(partition_path),
@@ -365,7 +363,6 @@ StoragePartitionImpl::StoragePartitionImpl(
special_storage_policy_(special_storage_policy),
geofencing_manager_(geofencing_manager),
host_zoom_level_context_(host_zoom_level_context),
- navigator_connect_context_(navigator_connect_context),
platform_notification_context_(platform_notification_context),
background_sync_context_(background_sync_context),
browser_context_(browser_context) {
@@ -408,12 +405,15 @@ StoragePartitionImpl::~StoragePartitionImpl() {
StoragePartitionImpl* StoragePartitionImpl::Create(
BrowserContext* context,
bool in_memory,
- const base::FilePath& partition_path) {
+ const base::FilePath& relative_partition_path) {
// Ensure that these methods are called on the UI thread, except for
// unittests where a UI thread might not have been created.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
!BrowserThread::IsMessageLoopValid(BrowserThread::UI));
+ base::FilePath partition_path =
+ context->GetPath().Append(relative_partition_path);
+
// All of the clients have to be created and registered with the
// QuotaManager prior to the QuotaManger being used. We do them
// all together here prior to handing out a reference to anything
@@ -440,9 +440,11 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
BrowserThread::GetMessageLoopProxyForThread(
BrowserThread::FILE).get());
- base::FilePath path = in_memory ? base::FilePath() : partition_path;
scoped_refptr<DOMStorageContextWrapper> dom_storage_context =
- new DOMStorageContextWrapper(path, context->GetSpecialStoragePolicy());
+ new DOMStorageContextWrapper(
+ BrowserContext::GetMojoUserIdFor(context),
+ in_memory ? base::FilePath() : context->GetPath(),
+ relative_partition_path, context->GetSpecialStoragePolicy());
// BrowserMainLoop may not be initialized in unit tests. Tests will
// need to inject their own task runner into the IndexedDBContext.
@@ -454,6 +456,8 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
->task_runner()
.get()
: NULL;
+
+ base::FilePath path = in_memory ? base::FilePath() : partition_path;
scoped_refptr<IndexedDBContextImpl> indexed_db_context =
new IndexedDBContextImpl(path,
context->GetSpecialStoragePolicy(),
@@ -462,8 +466,7 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
scoped_refptr<CacheStorageContextImpl> cache_storage_context =
new CacheStorageContextImpl(context);
- cache_storage_context->Init(path, quota_manager->proxy(),
- context->GetSpecialStoragePolicy());
+ cache_storage_context->Init(path, make_scoped_refptr(quota_manager->proxy()));
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
new ServiceWorkerContextWrapper(context);
@@ -487,9 +490,6 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
new HostZoomLevelContext(
context->CreateZoomLevelDelegate(partition_path)));
- scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context =
- new NavigatorConnectContextImpl(service_worker_context);
-
scoped_refptr<PlatformNotificationContextImpl> platform_notification_context =
new PlatformNotificationContextImpl(path, context,
service_worker_context);
@@ -506,8 +506,7 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
cache_storage_context.get(), service_worker_context.get(),
webrtc_identity_store.get(), special_storage_policy.get(),
geofencing_manager.get(), host_zoom_level_context.get(),
- navigator_connect_context.get(), platform_notification_context.get(),
- background_sync_context.get());
+ platform_notification_context.get(), background_sync_context.get());
service_worker_context->set_storage_partition(storage_partition);
@@ -577,11 +576,6 @@ ZoomLevelDelegate* StoragePartitionImpl::GetZoomLevelDelegate() {
return host_zoom_level_context_->GetZoomLevelDelegate();
}
-NavigatorConnectContextImpl*
-StoragePartitionImpl::GetNavigatorConnectContext() {
- return navigator_connect_context_.get();
-}
-
PlatformNotificationContextImpl*
StoragePartitionImpl::GetPlatformNotificationContext() {
return platform_notification_context_.get();
@@ -591,6 +585,14 @@ BackgroundSyncContextImpl* StoragePartitionImpl::GetBackgroundSyncContext() {
return background_sync_context_.get();
}
+void StoragePartitionImpl::OpenLocalStorage(
+ const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojo::InterfaceRequest<mojom::LevelDBWrapper> request) {
+ dom_storage_context_->OpenLocalStorage(
+ origin, std::move(observer), std::move(request));
+}
+
void StoragePartitionImpl::ClearDataImpl(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
@@ -652,42 +654,30 @@ void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
// within the user-specified timeframe, and deal with the resulting set in
// ClearQuotaManagedOriginsOnIOThread().
quota_manager->GetOriginsModifiedSince(
- storage::kStorageTypePersistent,
- begin,
+ storage::kStorageTypePersistent, begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
- base::Unretained(this),
- quota_manager,
- special_storage_policy,
- origin_matcher,
- decrement_callback));
+ base::Unretained(this), base::RetainedRef(quota_manager),
+ special_storage_policy, origin_matcher, decrement_callback));
}
// Do the same for temporary quota.
if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) {
IncrementTaskCountOnIO();
quota_manager->GetOriginsModifiedSince(
- storage::kStorageTypeTemporary,
- begin,
+ storage::kStorageTypeTemporary, begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
- base::Unretained(this),
- quota_manager,
- special_storage_policy,
- origin_matcher,
- decrement_callback));
+ base::Unretained(this), base::RetainedRef(quota_manager),
+ special_storage_policy, origin_matcher, decrement_callback));
}
// Do the same for syncable quota.
if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_SYNCABLE) {
IncrementTaskCountOnIO();
quota_manager->GetOriginsModifiedSince(
- storage::kStorageTypeSyncable,
- begin,
+ storage::kStorageTypeSyncable, begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
- base::Unretained(this),
- quota_manager,
- special_storage_policy,
- origin_matcher,
- decrement_callback));
+ base::Unretained(this), base::RetainedRef(quota_manager),
+ special_storage_policy, origin_matcher, decrement_callback));
}
DecrementTaskCountOnIO();
@@ -892,6 +882,11 @@ BrowserContext* StoragePartitionImpl::browser_context() const {
return browser_context_;
}
+void StoragePartitionImpl::Bind(
+ mojo::InterfaceRequest<mojom::StoragePartitionService> request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
void StoragePartitionImpl::OverrideQuotaManagerForTesting(
storage::QuotaManager* quota_manager) {
quota_manager_ = quota_manager;
diff --git a/chromium/content/browser/storage_partition_impl.h b/chromium/content/browser/storage_partition_impl.h
index ece0a8ebff6..d564f9ec235 100644
--- a/chromium/content/browser/storage_partition_impl.h
+++ b/chromium/content/browser/storage_partition_impl.h
@@ -18,17 +18,19 @@
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/host_zoom_level_context.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
-#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/content_export.h"
+#include "content/common/storage_partition_service.mojom.h"
#include "content/public/browser/storage_partition.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
#include "storage/browser/quota/special_storage_policy.h"
namespace content {
-class StoragePartitionImpl : public StoragePartition {
+class StoragePartitionImpl : public StoragePartition,
+ public mojom::StoragePartitionService {
public:
CONTENT_EXPORT ~StoragePartitionImpl() override;
@@ -57,10 +59,15 @@ class StoragePartitionImpl : public StoragePartition {
HostZoomMap* GetHostZoomMap() override;
HostZoomLevelContext* GetHostZoomLevelContext() override;
ZoomLevelDelegate* GetZoomLevelDelegate() override;
- NavigatorConnectContextImpl* GetNavigatorConnectContext() override;
PlatformNotificationContextImpl* GetPlatformNotificationContext() override;
BackgroundSyncContextImpl* GetBackgroundSyncContext() override;
+ // mojom::StoragePartitionService interface.
+ void OpenLocalStorage(
+ const url::Origin& origin,
+ mojom::LevelDBObserverPtr observer,
+ mojo::InterfaceRequest<mojom::LevelDBWrapper> request) override;
+
void ClearDataForOrigin(uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const GURL& storage_origin,
@@ -81,6 +88,9 @@ class StoragePartitionImpl : public StoragePartition {
// Can return nullptr while |this| is being destroyed.
BrowserContext* browser_context() const;
+ // Called by each renderer process once.
+ void Bind(mojo::InterfaceRequest<mojom::StoragePartitionService> request);
+
struct DataDeletionHelper;
struct QuotaManagedDataDeletionHelper;
@@ -120,15 +130,16 @@ class StoragePartitionImpl : public StoragePartition {
FRIEND_TEST_ALL_PREFIXES(StoragePartitionImplTest,
RemoveLocalStorageForLastWeek);
- // The |partition_path| is the absolute path to the root of this
- // StoragePartition's on-disk storage.
+ // |relative_partition_path| is the relative path under |profile_path| to the
+ // StoragePartition's on-disk-storage.
//
- // If |in_memory| is true, the |partition_path| is (ab)used as a way of
- // distinguishing different in-memory partitions, but nothing is persisted
+ // If |in_memory| is true, the |relative_partition_path| is (ab)used as a way
+ // of distinguishing different in-memory partitions, but nothing is persisted
// on to disk.
- static StoragePartitionImpl* Create(BrowserContext* context,
- bool in_memory,
- const base::FilePath& profile_path);
+ static StoragePartitionImpl* Create(
+ BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path);
CONTENT_EXPORT StoragePartitionImpl(
BrowserContext* browser_context,
@@ -145,7 +156,6 @@ class StoragePartitionImpl : public StoragePartition {
storage::SpecialStoragePolicy* special_storage_policy,
GeofencingManager* geofencing_manager,
HostZoomLevelContext* host_zoom_level_context,
- NavigatorConnectContextImpl* navigator_connect_context,
PlatformNotificationContextImpl* platform_notification_context,
BackgroundSyncContextImpl* background_sync_context);
@@ -190,10 +200,11 @@ class StoragePartitionImpl : public StoragePartition {
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_refptr<GeofencingManager> geofencing_manager_;
scoped_refptr<HostZoomLevelContext> host_zoom_level_context_;
- scoped_refptr<NavigatorConnectContextImpl> navigator_connect_context_;
scoped_refptr<PlatformNotificationContextImpl> platform_notification_context_;
scoped_refptr<BackgroundSyncContextImpl> background_sync_context_;
+ mojo::BindingSet<mojom::StoragePartitionService> bindings_;
+
// Raw pointer that should always be valid. The BrowserContext owns the
// StoragePartitionImplMap which then owns StoragePartitionImpl. When the
// BrowserContext is destroyed, |this| will be destroyed too.
diff --git a/chromium/content/browser/storage_partition_impl_map.cc b/chromium/content/browser/storage_partition_impl_map.cc
index 75c257ac081..83360f39a83 100644
--- a/chromium/content/browser/storage_partition_impl_map.cc
+++ b/chromium/content/browser/storage_partition_impl_map.cc
@@ -39,8 +39,6 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/navigator_connect_context.h"
-#include "content/public/browser/navigator_connect_service_factory.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
@@ -396,12 +394,11 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
if (it != partitions_.end())
return it->second;
- base::FilePath partition_path =
- browser_context_->GetPath().Append(
- GetStoragePartitionPath(partition_domain, partition_name));
- StoragePartitionImpl* partition =
- StoragePartitionImpl::Create(browser_context_, in_memory,
- partition_path);
+ base::FilePath relative_partition_path =
+ GetStoragePartitionPath(partition_domain, partition_name);
+
+ StoragePartitionImpl* partition = StoragePartitionImpl::Create(
+ browser_context_, in_memory, relative_partition_path);
partitions_[partition_config] = partition;
partition->GetQuotaManager()->SetTemporaryStorageEvictionPolicy(
@@ -462,14 +459,13 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
// These calls must happen after StoragePartitionImpl::Create().
if (partition_domain.empty()) {
partition->SetURLRequestContext(
- GetContentClient()->browser()->CreateRequestContext(
- browser_context_, &protocol_handlers,
- std::move(request_interceptors)));
+ browser_context_->CreateRequestContext(
+ &protocol_handlers, std::move(request_interceptors)));
} else {
partition->SetURLRequestContext(
- GetContentClient()->browser()->CreateRequestContextForStoragePartition(
- browser_context_, partition->GetPath(), in_memory,
- &protocol_handlers, std::move(request_interceptors)));
+ browser_context_->CreateRequestContextForStoragePartition(
+ partition->GetPath(), in_memory, &protocol_handlers,
+ std::move(request_interceptors)));
}
partition->SetMediaURLRequestContext(
partition_domain.empty() ?
@@ -477,9 +473,6 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
browser_context_->GetMediaRequestContextForStoragePartition(
partition->GetPath(), in_memory));
- GetContentClient()->browser()->GetAdditionalNavigatorConnectServices(
- partition->GetNavigatorConnectContext());
-
PostCreateInitialization(partition, in_memory);
return partition;
@@ -590,28 +583,29 @@ void StoragePartitionImplMap::PostCreateInitialization(
if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&ChromeAppCacheService::InitializeOnIOThread,
- partition->GetAppCacheService(),
- in_memory ? base::FilePath() :
- partition->GetPath().Append(kAppCacheDirname),
- browser_context_->GetResourceContext(),
- make_scoped_refptr(partition->GetURLRequestContext()),
- make_scoped_refptr(
- browser_context_->GetSpecialStoragePolicy())));
+ base::Bind(
+ &ChromeAppCacheService::InitializeOnIOThread,
+ partition->GetAppCacheService(),
+ in_memory ? base::FilePath()
+ : partition->GetPath().Append(kAppCacheDirname),
+ browser_context_->GetResourceContext(),
+ base::RetainedRef(partition->GetURLRequestContext()),
+ base::RetainedRef(browser_context_->GetSpecialStoragePolicy())));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&CacheStorageContextImpl::SetBlobParametersForCache,
partition->GetCacheStorageContext(),
- make_scoped_refptr(partition->GetURLRequestContext()),
- make_scoped_refptr(
+ base::RetainedRef(partition->GetURLRequestContext()),
+ base::RetainedRef(
ChromeBlobStorageContext::GetFor(browser_context_))));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&ServiceWorkerContextWrapper::set_resource_context,
+ base::Bind(&ServiceWorkerContextWrapper::InitializeResourceContext,
partition->GetServiceWorkerContext(),
- browser_context_->GetResourceContext()));
+ browser_context_->GetResourceContext(),
+ base::RetainedRef(partition->GetURLRequestContext())));
// We do not call InitializeURLRequestContext() for media contexts because,
// other than the HTTP cache, the media contexts share the same backing
diff --git a/chromium/content/browser/streams/stream_url_request_job.cc b/chromium/content/browser/streams/stream_url_request_job.cc
index e26fe35a41a..69251bda5da 100644
--- a/chromium/content/browser/streams/stream_url_request_job.cc
+++ b/chromium/content/browser/streams/stream_url_request_job.cc
@@ -23,7 +23,7 @@ StreamURLRequestJob::StreamURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
scoped_refptr<Stream> stream)
- : net::URLRequestJob(request, network_delegate),
+ : net::URLRangeRequestJob(request, network_delegate),
stream_(stream),
headers_set_(false),
pending_buffer_size_(0),
@@ -147,31 +147,18 @@ int StreamURLRequestJob::GetResponseCode() const {
return response_info_->headers->response_code();
}
-void StreamURLRequestJob::SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) {
- std::string range_header;
- if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
- std::vector<net::HttpByteRange> ranges;
- if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
- if (ranges.size() == 1) {
- // Streams don't support seeking, so a non-zero starting position
- // doesn't make sense.
- if (ranges[0].first_byte_position() == 0) {
- max_range_ = ranges[0].last_byte_position() + 1;
- } else {
- NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
- return;
- }
- } else {
- NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
- return;
- }
+void StreamURLRequestJob::DidStart() {
+ if (range_parse_result() == net::OK && ranges().size() > 0) {
+ // Only one range is supported, and it must start at the first byte.
+ if (ranges().size() > 1 || ranges()[0].first_byte_position() != 0) {
+ NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
+ return;
}
+
+ max_range_ = ranges()[0].last_byte_position() + 1;
}
-}
-void StreamURLRequestJob::DidStart() {
- // We only support GET request.
+ // This class only supports GET requests.
if (request()->method() != "GET") {
NotifyFailure(net::ERR_METHOD_NOT_SUPPORTED);
return;
diff --git a/chromium/content/browser/streams/stream_url_request_job.h b/chromium/content/browser/streams/stream_url_request_job.h
index ded5fa729ca..d11e6e7bdb9 100644
--- a/chromium/content/browser/streams/stream_url_request_job.h
+++ b/chromium/content/browser/streams/stream_url_request_job.h
@@ -9,7 +9,7 @@
#include "content/browser/streams/stream_read_observer.h"
#include "content/common/content_export.h"
#include "net/http/http_status_code.h"
-#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_range_request_job.h"
namespace content {
@@ -17,7 +17,7 @@ class Stream;
// A request job that handles reading stream URLs.
class CONTENT_EXPORT StreamURLRequestJob
- : public net::URLRequestJob,
+ : public net::URLRangeRequestJob,
public StreamReadObserver {
public:
StreamURLRequestJob(net::URLRequest* request,
@@ -34,7 +34,6 @@ class CONTENT_EXPORT StreamURLRequestJob
bool GetMimeType(std::string* mime_type) const override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int GetResponseCode() const override;
- void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
protected:
~StreamURLRequestJob() override;
diff --git a/chromium/content/browser/system_message_window_win.cc b/chromium/content/browser/system_message_window_win.cc
deleted file mode 100644
index 0316fc7cb02..00000000000
--- a/chromium/content/browser/system_message_window_win.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/system_message_window_win.h"
-
-#include <dbt.h>
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/system_monitor/system_monitor.h"
-#include "base/win/wrapped_window_proc.h"
-#include "media/audio/win/core_audio_util_win.h"
-
-namespace content {
-
-namespace {
-const wchar_t kWindowClassName[] = L"Chrome_SystemMessageWindow";
-
-// A static map from a device category guid to base::SystemMonitor::DeviceType.
-struct {
- const GUID device_category;
- const base::SystemMonitor::DeviceType device_type;
-} const kDeviceCategoryMap[] = {
- { KSCATEGORY_AUDIO, base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE },
- { KSCATEGORY_VIDEO, base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE },
-};
-} // namespace
-
-// Manages the device notification handles for SystemMessageWindowWin.
-class SystemMessageWindowWin::DeviceNotifications {
- public:
- explicit DeviceNotifications(HWND hwnd) : notifications_() {
- Register(hwnd);
- }
-
- ~DeviceNotifications() {
- Unregister();
- }
-
- void Register(HWND hwnd) {
- // Request to receive device notifications. All applications receive basic
- // notifications via WM_DEVICECHANGE but in order to receive detailed device
- // arrival and removal messages, we need to register.
- DEV_BROADCAST_DEVICEINTERFACE filter = {0};
- filter.dbcc_size = sizeof(filter);
- filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
- bool core_audio_support = media::CoreAudioUtil::IsSupported();
- for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
- // If CoreAudio is supported, AudioDeviceListenerWin will
- // take care of monitoring audio devices.
- if (core_audio_support &&
- KSCATEGORY_AUDIO == kDeviceCategoryMap[i].device_category) {
- continue;
- }
-
- filter.dbcc_classguid = kDeviceCategoryMap[i].device_category;
- DCHECK_EQ(notifications_[i], static_cast<HDEVNOTIFY>(NULL));
- notifications_[i] = RegisterDeviceNotification(
- hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
- DPLOG_IF(ERROR, !notifications_[i])
- << "RegisterDeviceNotification failed";
- }
- }
-
- void Unregister() {
- for (size_t i = 0; i < arraysize(notifications_); ++i) {
- if (notifications_[i]) {
- UnregisterDeviceNotification(notifications_[i]);
- notifications_[i] = NULL;
- }
- }
- }
-
- private:
- HDEVNOTIFY notifications_[arraysize(kDeviceCategoryMap)];
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DeviceNotifications);
-};
-
-
-SystemMessageWindowWin::SystemMessageWindowWin() {
- WNDCLASSEX window_class;
- base::win::InitializeWindowClass(
- kWindowClassName,
- &base::win::WrappedWindowProc<SystemMessageWindowWin::WndProcThunk>,
- 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
- &window_class);
- instance_ = window_class.hInstance;
- ATOM clazz = RegisterClassEx(&window_class);
- DCHECK(clazz);
-
- window_ = CreateWindow(kWindowClassName,
- 0, 0, 0, 0, 0, 0, 0, 0, instance_, 0);
- SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
- device_notifications_.reset(new DeviceNotifications(window_));
-}
-
-SystemMessageWindowWin::~SystemMessageWindowWin() {
- if (window_) {
- DestroyWindow(window_);
- UnregisterClass(kWindowClassName, instance_);
- }
-}
-
-LRESULT SystemMessageWindowWin::OnDeviceChange(UINT event_type, LPARAM data) {
- base::SystemMonitor* monitor = base::SystemMonitor::Get();
- base::SystemMonitor::DeviceType device_type =
- base::SystemMonitor::DEVTYPE_UNKNOWN;
- switch (event_type) {
- case DBT_DEVNODES_CHANGED:
- // For this notification, we're happy with the default DEVTYPE_UNKNOWN.
- break;
-
- case DBT_DEVICEREMOVECOMPLETE:
- case DBT_DEVICEARRIVAL: {
- // This notification has more details about the specific device that
- // was added or removed. See if this is a category we're interested
- // in monitoring and if so report the specific device type. If we don't
- // find the category in our map, ignore the notification and do not
- // notify the system monitor.
- DEV_BROADCAST_DEVICEINTERFACE* device_interface =
- reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data);
- if (device_interface->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
- return TRUE;
- for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) {
- if (kDeviceCategoryMap[i].device_category ==
- device_interface->dbcc_classguid) {
- device_type = kDeviceCategoryMap[i].device_type;
- break;
- }
- }
-
- // Devices that we do not have a DEVTYPE_ for, get detected via
- // DBT_DEVNODES_CHANGED, so we avoid sending additional notifications
- // for those here.
- if (device_type == base::SystemMonitor::DEVTYPE_UNKNOWN)
- return TRUE;
- break;
- }
-
- default:
- return TRUE;
- }
-
- monitor->ProcessDevicesChanged(device_type);
-
- return TRUE;
-}
-
-LRESULT CALLBACK SystemMessageWindowWin::WndProc(HWND hwnd, UINT message,
- WPARAM wparam, LPARAM lparam) {
- switch (message) {
- case WM_DEVICECHANGE:
- return OnDeviceChange(static_cast<UINT>(wparam), lparam);
- default:
- break;
- }
-
- return ::DefWindowProc(hwnd, message, wparam, lparam);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/system_message_window_win.h b/chromium/content/browser/system_message_window_win.h
deleted file mode 100644
index 061db54908f..00000000000
--- a/chromium/content/browser/system_message_window_win.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_SYSTEM_MESSAGE_WINDOW_WIN_H_
-#define CONTENT_BROWSER_SYSTEM_MESSAGE_WINDOW_WIN_H_
-
-#include <windows.h>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class CONTENT_EXPORT SystemMessageWindowWin {
- public:
- SystemMessageWindowWin();
-
- virtual ~SystemMessageWindowWin();
-
- virtual LRESULT OnDeviceChange(UINT event_type, LPARAM data);
-
- private:
- void Init();
-
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
- WPARAM wparam, LPARAM lparam);
-
- static LRESULT CALLBACK WndProcThunk(HWND hwnd,
- UINT message,
- WPARAM wparam,
- LPARAM lparam) {
- SystemMessageWindowWin* msg_wnd = reinterpret_cast<SystemMessageWindowWin*>(
- GetWindowLongPtr(hwnd, GWLP_USERDATA));
- if (msg_wnd)
- return msg_wnd->WndProc(hwnd, message, wparam, lparam);
- return ::DefWindowProc(hwnd, message, wparam, lparam);
- }
-
- HMODULE instance_;
- HWND window_;
- class DeviceNotifications;
- scoped_ptr<DeviceNotifications> device_notifications_;
-
- DISALLOW_COPY_AND_ASSIGN(SystemMessageWindowWin);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SYSTEM_MESSAGE_WINDOW_WIN_H_
diff --git a/chromium/content/browser/system_message_window_win_unittest.cc b/chromium/content/browser/system_message_window_win_unittest.cc
deleted file mode 100644
index fac8f2baafd..00000000000
--- a/chromium/content/browser/system_message_window_win_unittest.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/system_message_window_win.h"
-
-#include <dbt.h>
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/system_monitor/system_monitor.h"
-#include "base/test/mock_devices_changed_observer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class SystemMessageWindowWinTest : public testing::Test {
- public:
- ~SystemMessageWindowWinTest() override {}
-
- protected:
- void SetUp() override {
- system_monitor_.AddDevicesChangedObserver(&observer_);
- }
-
- base::MessageLoop message_loop_;
- base::SystemMonitor system_monitor_;
- base::MockDevicesChangedObserver observer_;
- SystemMessageWindowWin window_;
-};
-
-TEST_F(SystemMessageWindowWinTest, DevicesChanged) {
- EXPECT_CALL(observer_, OnDevicesChanged(testing::_)).Times(1);
- window_.OnDeviceChange(DBT_DEVNODES_CHANGED, NULL);
- message_loop_.RunUntilIdle();
-}
-
-TEST_F(SystemMessageWindowWinTest, RandomMessage) {
- window_.OnDeviceChange(DBT_DEVICEQUERYREMOVE, NULL);
- message_loop_.RunUntilIdle();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/theme_helper_mac.mm b/chromium/content/browser/theme_helper_mac.mm
index aa5ebd05a0d..7cc95a70aaf 100644
--- a/chromium/content/browser/theme_helper_mac.mm
+++ b/chromium/content/browser/theme_helper_mac.mm
@@ -8,8 +8,8 @@
#include "base/command_line.h"
#include "base/mac/mac_util.h"
-#include "base/mac/sdk_forward_declarations.h"
#include "base/strings/sys_string_conversions.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
@@ -18,25 +18,11 @@
#include "content/public/common/content_switches.h"
using content::RenderProcessHost;
+using content::RenderProcessHostImpl;
using content::ThemeHelperMac;
namespace {
-bool GetScrollAnimationEnabled() {
- bool enabled = false;
- id value = nil;
- if (base::mac::IsOSMountainLionOrLater()) {
- value = [[NSUserDefaults standardUserDefaults]
- objectForKey:@"NSScrollAnimationEnabled"];
- } else {
- value = [[NSUserDefaults standardUserDefaults]
- objectForKey:@"AppleScrollAnimationEnabled"];
- }
- if (value)
- enabled = [value boolValue];
- return enabled;
-}
-
blink::WebScrollbarButtonsPlacement GetButtonPlacement() {
NSString* scrollbar_variant = [[NSUserDefaults standardUserDefaults]
objectForKey:@"AppleScrollBarVariant"];
@@ -64,7 +50,6 @@ void FillScrollbarThemeParams(ViewMsg_UpdateScrollbarTheme_Params* params) {
[defaults boolForKey:@"AppleScrollerPagingBehavior"];
params->preferred_scroller_style =
ThemeHelperMac::GetPreferredScrollerStyle();
- params->scroll_animation_enabled = GetScrollAnimationEnabled();
params->button_placement = GetButtonPlacement();
}
@@ -139,12 +124,10 @@ ViewMsg_SystemColorsChanged* CreateSystemColorsChangedMessage() {
switches::kSingleProcess)) {
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- if ([NSScroller respondsToSelector:@selector(preferredScrollerStyle)]) {
- [center addObserver:self
- selector:@selector(behaviorPrefsChanged:)
- name:NSPreferredScrollerStyleDidChangeNotification
- object:nil];
- }
+ [center addObserver:self
+ selector:@selector(behaviorPrefsChanged:)
+ name:NSPreferredScrollerStyleDidChangeNotification
+ object:nil];
[center addObserver:self
selector:@selector(systemColorsChanged:)
@@ -177,7 +160,10 @@ ViewMsg_SystemColorsChanged* CreateSystemColorsChangedMessage() {
for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
!it.IsAtEnd();
it.Advance()) {
- it.GetCurrentValue()->Send(new ViewMsg_UpdateScrollbarTheme(params));
+ RenderProcessHostImpl* rphi =
+ static_cast<RenderProcessHostImpl*>(it.GetCurrentValue());
+ rphi->RecomputeAndUpdateWebKitPreferences();
+ rphi->Send(new ViewMsg_UpdateScrollbarTheme(params));
}
}
@@ -193,8 +179,6 @@ ThemeHelperMac* ThemeHelperMac::GetInstance() {
// static
blink::ScrollerStyle ThemeHelperMac::GetPreferredScrollerStyle() {
- if (![NSScroller respondsToSelector:@selector(preferredScrollerStyle)])
- return blink::ScrollerStyleLegacy;
return static_cast<blink::ScrollerStyle>([NSScroller preferredScrollerStyle]);
}
@@ -219,9 +203,11 @@ void ThemeHelperMac::Observe(int type,
FillScrollbarThemeParams(&params);
params.redraw = false;
- RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
- rph->Send(new ViewMsg_UpdateScrollbarTheme(params));
- rph->Send(CreateSystemColorsChangedMessage());
+ RenderProcessHostImpl* rphi =
+ Source<content::RenderProcessHostImpl>(source).ptr();
+ rphi->RecomputeAndUpdateWebKitPreferences();
+ rphi->Send(new ViewMsg_UpdateScrollbarTheme(params));
+ rphi->Send(CreateSystemColorsChangedMessage());
}
} // namespace content
diff --git a/chromium/content/browser/top_document_isolation_browsertest.cc b/chromium/content/browser/top_document_isolation_browsertest.cc
new file mode 100644
index 00000000000..dd4541f2318
--- /dev/null
+++ b/chromium/content/browser/top_document_isolation_browsertest.cc
@@ -0,0 +1,571 @@
+// 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 <string>
+
+#include "base/command_line.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/web_contents/web_contents_impl.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 "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/test_frame_navigation_observer.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class TopDocumentIsolationTest : public ContentBrowserTest {
+ public:
+ TopDocumentIsolationTest() {}
+
+ protected:
+ std::string DepictFrameTree(FrameTreeNode* node) {
+ return visualizer_.DepictFrameTree(node);
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kTopDocumentIsolation);
+ }
+
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ SetupCrossSiteRedirector(embedded_test_server());
+ }
+
+ FrameTreeNode* root() {
+ return static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ }
+
+ void GoBack() {
+ TestNavigationObserver back_load_observer(shell()->web_contents());
+ shell()->web_contents()->GetController().GoBack();
+ back_load_observer.Wait();
+ }
+
+ Shell* OpenPopup(FrameTreeNode* opener, const std::string& url) {
+ GURL gurl =
+ opener->current_frame_host()->GetLastCommittedURL().Resolve(url);
+ return content::OpenPopup(opener->current_frame_host(), gurl, "_blank");
+ }
+
+ void RendererInitiatedNavigateToURL(FrameTreeNode* node, const GURL& url) {
+ TestFrameNavigationObserver nav_observer(node);
+ ASSERT_TRUE(ExecuteScript(node->current_frame_host(),
+ "window.location.href='" + url.spec() + "'"));
+ nav_observer.Wait();
+ }
+
+ private:
+ FrameTreeVisualizer visualizer_;
+};
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, SameSiteDeeplyNested) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
+
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " |--Site A\n"
+ " +--Site A\n"
+ " +--Site A\n"
+ "Where A = http://a.com/",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, CrossSiteDeeplyNested) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(c(d(b))))"));
+
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, ReturnToTopSite) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(a(c)))"));
+
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ " +--Site A -- proxies for B\n"
+ " +--Site B -- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, NavigateSubframeToTopSite) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(c(d)))"));
+
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ GURL ada_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(d(a))"));
+ RendererInitiatedNavigateToURL(root()->child_at(0)->child_at(0), ada_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ " +--Site A -- proxies for B\n"
+ " +--Site B -- proxies for A\n"
+ " +--Site A -- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, NavigateToSubframeSite) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL ab_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+ GURL ba_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(a, c)"));
+
+ NavigateToURL(shell(), ab_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ NavigateToURL(shell(), ba_url);
+
+ EXPECT_EQ(
+ " Site C ------------ proxies for B\n"
+ " |--Site B ------- proxies for C\n"
+ " +--Site B ------- proxies for C\n"
+ "Where B = default subframe process\n"
+ " C = http://b.com/",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest,
+ NavigateToSubframeSiteWithPopup) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ // A(B) -> B(A), but while a separate B(A) popup exists.
+ GURL ab_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+
+ NavigateToURL(shell(), ab_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ Shell* popup =
+ OpenPopup(root()->child_at(0), "/cross_site_iframe_factory.html?b(a)");
+ FrameTreeNode* popup_root =
+ static_cast<WebContentsImpl*>(popup->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // This popup's main frame must stay in the default subframe siteinstance,
+ // since its opener (the b.com subframe) may synchronously script it. Note
+ // that the popup's subframe is same-site with window.top.opener.top, the
+ // a.com main frame of the tab. But --top-document-isolation does not
+ // currently place the popup subframe in the a.com process in this case.
+ EXPECT_EQ(
+ " Site B\n"
+ " +--Site B\n"
+ "Where B = default subframe process",
+ DepictFrameTree(popup_root));
+
+ GURL ba_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(a, c)"));
+ NavigateToURL(shell(), ba_url);
+
+ // This navigation destroys the popup's opener, so we allow the main frame to
+ // commit in a top level process for b.com, in spite of the b.com popup in the
+ // default subframe process.
+ EXPECT_EQ(
+ " Site C ------------ proxies for B\n"
+ " |--Site B ------- proxies for C\n"
+ " +--Site B ------- proxies for C\n"
+ "Where B = default subframe process\n"
+ " C = http://b.com/",
+ DepictFrameTree(root()));
+ EXPECT_EQ(
+ " Site B\n"
+ " +--Site B\n"
+ "Where B = default subframe process",
+ DepictFrameTree(popup_root));
+
+ // Navigate the popup to a new site.
+ GURL c_url(embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c(c, c, c, c)"));
+ NavigateToURL(popup, c_url);
+ EXPECT_EQ(
+ " Site D ------------ proxies for B\n"
+ " |--Site D ------- proxies for B\n"
+ " |--Site D ------- proxies for B\n"
+ " |--Site D ------- proxies for B\n"
+ " +--Site D ------- proxies for B\n"
+ "Where B = default subframe process\n"
+ " D = http://c.com/",
+ DepictFrameTree(popup_root));
+ NavigateToURL(shell(), c_url);
+ EXPECT_EQ(
+ " Site D\n"
+ " |--Site D\n"
+ " |--Site D\n"
+ " |--Site D\n"
+ " +--Site D\n"
+ "Where D = http://c.com/",
+ DepictFrameTree(popup_root));
+ EXPECT_EQ(
+ " Site D\n"
+ " |--Site D\n"
+ " |--Site D\n"
+ " |--Site D\n"
+ " +--Site D\n"
+ "Where D = http://c.com/",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest,
+ NavigateToSubframeSiteWithPopup2) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ // A(B, C) -> C(A, B), but while a separate C(A) popup exists.
+ //
+ // This test is constructed so that c.com is the second site to commit in the
+ // default subframe SiteInstance, so the default subframe SiteInstance does
+ // not have a "c.com" as the value of GetSiteURL().
+ GURL abb_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b, b)"));
+
+ NavigateToURL(shell(), abb_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ // A(B, B) -> A(B, C)
+ GURL c_url(embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c"));
+ NavigateFrameToURL(root()->child_at(1), c_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " |--Site B ------- proxies for A\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ // This test exercises what happens when the SiteURL of the default subframe
+ // siteinstance doesn't match the subframe site.
+ EXPECT_NE("c.com", root()
+ ->child_at(1)
+ ->current_frame_host()
+ ->GetSiteInstance()
+ ->GetSiteURL()
+ .host());
+
+ // Subframe C creates C(A) popup.
+ Shell* popup =
+ OpenPopup(root()->child_at(1), "/cross_site_iframe_factory.html?c(a)");
+
+ FrameTreeNode* popup_root =
+ static_cast<WebContentsImpl*>(popup->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // The popup must stay with its opener, in the default subframe process.
+ EXPECT_EQ(
+ " Site B\n"
+ " +--Site B\n"
+ "Where B = default subframe process",
+ DepictFrameTree(popup_root));
+
+ GURL cab_url(embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c(a, b)"));
+ NavigateToURL(shell(), cab_url);
+
+ // This c.com navigation currently breaks out of the default subframe process,
+ // even though that process houses a c.com pop-up.
+ EXPECT_EQ(
+ " Site C ------------ proxies for B\n"
+ " |--Site B ------- proxies for C\n"
+ " +--Site B ------- proxies for C\n"
+ "Where B = default subframe process\n"
+ " C = http://c.com/",
+ DepictFrameTree(root()));
+
+ // c.com popup should remain where it was, in the subframe process.
+ EXPECT_EQ(
+ " Site B\n"
+ " +--Site B\n"
+ "Where B = default subframe process",
+ DepictFrameTree(popup_root));
+ EXPECT_EQ(nullptr, popup_root->opener());
+
+ // If we navigate the popup to a new site, it ought to transfer processes.
+ GURL d_url(embedded_test_server()->GetURL(
+ "d.com", "/cross_site_iframe_factory.html?d"));
+ NavigateToURL(popup, d_url);
+ EXPECT_EQ(
+ " Site D ------------ proxies for B\n"
+ "Where B = default subframe process\n"
+ " D = http://d.com/",
+ DepictFrameTree(popup_root));
+ NavigateToURL(shell(), d_url);
+ EXPECT_EQ(
+ " Site D\n"
+ "Where D = http://d.com/",
+ DepictFrameTree(popup_root));
+ EXPECT_EQ(
+ " Site D\n"
+ "Where D = http://d.com/",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, FramesForSitesInHistory) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ // First, do a series of navigations.
+ GURL a_url = embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a");
+ GURL b_url = embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b");
+ GURL c_url = embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c");
+
+ // Browser-initiated navigation to a.com.
+ NavigateToURL(shell(), a_url);
+ EXPECT_EQ(
+ " Site A\n"
+ "Where A = http://a.com/",
+ DepictFrameTree(root()));
+
+ // Browser-initiated navigation to b.com.
+ NavigateToURL(shell(), b_url);
+ EXPECT_EQ(
+ " Site B\n"
+ "Where B = http://b.com/",
+ DepictFrameTree(root()));
+
+ // Renderer-initiated navigation back to a.com. This shouldn't swap processes.
+ RendererInitiatedNavigateToURL(root(), a_url);
+ EXPECT_EQ(
+ " Site B\n"
+ "Where B = http://b.com/",
+ DepictFrameTree(root()));
+
+ // Browser-initiated navigation to c.com.
+ NavigateToURL(shell(), c_url);
+ EXPECT_EQ(
+ " Site C\n"
+ "Where C = http://c.com/",
+ DepictFrameTree(root()));
+
+ // Now, navigate to a fourth site with iframes to the sites in the history.
+ NavigateToURL(shell(),
+ embedded_test_server()->GetURL(
+ "d.com", "/cross_site_iframe_factory.html?d(a,b,c)"));
+
+ EXPECT_EQ(
+ " Site D ------------ proxies for E\n"
+ " |--Site E ------- proxies for D\n"
+ " |--Site E ------- proxies for D\n"
+ " +--Site E ------- proxies for D\n"
+ "Where D = http://d.com/\n"
+ " E = default subframe process",
+ DepictFrameTree(root()));
+
+ // Now try going back.
+ GoBack();
+ EXPECT_EQ(
+ " Site C\n"
+ "Where C = http://c.com/",
+ DepictFrameTree(root()));
+ GoBack();
+ EXPECT_EQ(
+ " Site B\n"
+ "Where B = http://b.com/",
+ DepictFrameTree(root()));
+ GoBack();
+ EXPECT_EQ(
+ " Site B\n"
+ "Where B = http://b.com/",
+ DepictFrameTree(root()));
+ GoBack();
+ EXPECT_EQ(
+ " Site A\n"
+ "Where A = http://a.com/",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, CrossSiteAtLevelTwo) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a(b, a))"));
+
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site A ------- proxies for B\n"
+ " |--Site B -- proxies for A\n"
+ " +--Site A -- proxies for B\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ GURL c_url(embedded_test_server()->GetURL(
+ "c.com", "/cross_site_iframe_factory.html?c"));
+ NavigateFrameToURL(root()->child_at(0)->child_at(1), c_url);
+
+ // This navigation should complete in the default subframe siteinstance.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site A ------- proxies for B\n"
+ " |--Site B -- proxies for A\n"
+ " +--Site B -- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+}
+
+IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, PopupAndRedirection) {
+ if (content::AreAllSitesIsolatedForTesting())
+ return; // Top Document Isolation is disabled in this mode.
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "page.com", "/cross_site_iframe_factory.html?page(adnetwork)"));
+
+ // User opens page on page.com which contains a subframe from adnetwork.com.
+ NavigateToURL(shell(), main_url);
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://page.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ GURL ad_url(embedded_test_server()->GetURL(
+ "ad.com", "/cross_site_iframe_factory.html?ad"));
+
+ // adnetwork.com retrieves an ad from advertiser (ad.com) and redirects the
+ // subframe to ad.com.
+ RendererInitiatedNavigateToURL(root()->child_at(0), ad_url);
+
+ // The subframe still uses the default subframe SiteInstance after navigation.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://page.com/\n"
+ " B = default subframe process",
+ DepictFrameTree(root()));
+
+ // User clicks the ad in the subframe, which opens a popup on the ad
+ // network's domain.
+ GURL popup_url(embedded_test_server()->GetURL(
+ "adnetwork.com", "/cross_site_iframe_factory.html?adnetwork"));
+ Shell* popup = OpenPopup(root()->child_at(0), popup_url.spec());
+
+ FrameTreeNode* popup_root =
+ static_cast<WebContentsImpl*>(popup->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ // It's ok for the popup to break out of the subframe process because it's
+ // currently cross-site from its opener frame.
+ EXPECT_EQ(
+ " Site C ------------ proxies for B\n"
+ "Where B = default subframe process\n"
+ " C = http://adnetwork.com/",
+ DepictFrameTree(popup_root));
+
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " +--Site B ------- proxies for A C\n"
+ "Where A = http://page.com/\n"
+ " B = default subframe process\n"
+ " C = http://adnetwork.com/",
+ DepictFrameTree(root()));
+
+ // The popup redirects itself to the advertiser's website (ad.com).
+ RendererInitiatedNavigateToURL(popup_root, ad_url);
+
+ // This must join its same-site opener, in the default subframe SiteInstance.
+ EXPECT_EQ(
+ " Site A ------------ proxies for B C\n"
+ " +--Site B ------- proxies for A C\n"
+ "Where A = http://page.com/\n"
+ " B = default subframe process\n"
+ " C = http://adnetwork.com/",
+ DepictFrameTree(root()));
+ EXPECT_EQ(
+ " Site C ------------ proxies for B\n"
+ "Where B = default subframe process\n"
+ " C = http://adnetwork.com/",
+ DepictFrameTree(popup_root));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/BUILD.gn b/chromium/content/browser/tracing/BUILD.gn
index 2122c79aa59..b71bf1b4428 100644
--- a/chromium/content/browser/tracing/BUILD.gn
+++ b/chromium/content/browser/tracing/BUILD.gn
@@ -12,7 +12,7 @@ tracing_gen_dir = "$root_gen_dir/content/browser/tracing"
tracing_grd = "$tracing_gen_dir/tracing_resources.grd"
action("generate_tracing_grd") {
- visibility = [ ":*" ]
+ visibility = [ ":*" ] # Depend on ":resources" to get this.
script = "generate_trace_viewer_grd.py"
input_pages = [
diff --git a/chromium/content/browser/tracing/DEPS b/chromium/content/browser/tracing/DEPS
index b99424f6482..982848711e3 100644
--- a/chromium/content/browser/tracing/DEPS
+++ b/chromium/content/browser/tracing/DEPS
@@ -2,4 +2,5 @@ include_rules = [
# Generated by the local tracing_resources.gyp:tracing_resources
"+grit/tracing_resources.h",
"+third_party/zlib/zlib.h",
+ "+tools/battor_agent",
]
diff --git a/chromium/content/browser/tracing/background_tracing_config_impl.cc b/chromium/content/browser/tracing/background_tracing_config_impl.cc
index 32eebe5a715..741e90e912f 100644
--- a/chromium/content/browser/tracing/background_tracing_config_impl.cc
+++ b/chromium/content/browser/tracing/background_tracing_config_impl.cc
@@ -30,6 +30,7 @@ const char kConfigCategoryBenchmarkDeep[] = "BENCHMARK_DEEP";
const char kConfigCategoryBenchmarkGPU[] = "BENCHMARK_GPU";
const char kConfigCategoryBenchmarkIPC[] = "BENCHMARK_IPC";
const char kConfigCategoryBenchmarkStartup[] = "BENCHMARK_STARTUP";
+const char kConfigCategoryBenchmarkBlinkGC[] = "BENCHMARK_BLINK_GC";
const char kConfigCategoryBlinkStyle[] = "BLINK_STYLE";
} // namespace
@@ -54,6 +55,8 @@ std::string BackgroundTracingConfigImpl::CategoryPresetToString(
return kConfigCategoryBenchmarkIPC;
case BackgroundTracingConfigImpl::BENCHMARK_STARTUP:
return kConfigCategoryBenchmarkStartup;
+ case BackgroundTracingConfigImpl::BENCHMARK_BLINK_GC:
+ return kConfigCategoryBenchmarkBlinkGC;
case BackgroundTracingConfigImpl::BLINK_STYLE:
return kConfigCategoryBlinkStyle;
}
@@ -89,6 +92,11 @@ bool BackgroundTracingConfigImpl::StringToCategoryPreset(
return true;
}
+ if (category_preset_string == kConfigCategoryBenchmarkBlinkGC) {
+ *category_preset = BackgroundTracingConfigImpl::BENCHMARK_BLINK_GC;
+ return true;
+ }
+
if (category_preset_string == kConfigCategoryBlinkStyle) {
*category_preset = BackgroundTracingConfigImpl::BLINK_STYLE;
return true;
diff --git a/chromium/content/browser/tracing/background_tracing_config_impl.h b/chromium/content/browser/tracing/background_tracing_config_impl.h
index 841a04711a5..0cee4b198ab 100644
--- a/chromium/content/browser/tracing/background_tracing_config_impl.h
+++ b/chromium/content/browser/tracing/background_tracing_config_impl.h
@@ -30,6 +30,7 @@ class CONTENT_EXPORT BackgroundTracingConfigImpl
BENCHMARK_GPU,
BENCHMARK_IPC,
BENCHMARK_STARTUP,
+ BENCHMARK_BLINK_GC,
BLINK_STYLE
};
diff --git a/chromium/content/browser/tracing/background_tracing_config_unittest.cc b/chromium/content/browser/tracing/background_tracing_config_unittest.cc
index 2b95069a401..901e865e60b 100644
--- a/chromium/content/browser/tracing/background_tracing_config_unittest.cc
+++ b/chromium/content/browser/tracing/background_tracing_config_unittest.cc
@@ -269,6 +269,44 @@ TEST_F(BackgroundTracingConfigTest, PreemptiveConfigFromValidString) {
EXPECT_EQ(config->scenario_name(), "my_awesome_experiment");
}
+TEST_F(BackgroundTracingConfigTest, ValidPreemptiveCategoryToString) {
+ scoped_ptr<BackgroundTracingConfigImpl> config = ReadFromJSONString(
+ "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": "
+ "\"BENCHMARK\",\"configs\": [{\"rule\": "
+ "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"trigger_name\":\"foo\"}]}");
+
+ BackgroundTracingConfigImpl::CategoryPreset categories[] = {
+ BackgroundTracingConfigImpl::BENCHMARK,
+ BackgroundTracingConfigImpl::BENCHMARK_DEEP,
+ BackgroundTracingConfigImpl::BENCHMARK_GPU,
+ BackgroundTracingConfigImpl::BENCHMARK_IPC,
+ BackgroundTracingConfigImpl::BENCHMARK_STARTUP,
+ BackgroundTracingConfigImpl::BENCHMARK_BLINK_GC,
+ BackgroundTracingConfigImpl::BLINK_STYLE,
+ };
+
+ const char* category_strings[] = {"BENCHMARK", "BENCHMARK_DEEP",
+ "BENCHMARK_GPU", "BENCHMARK_IPC",
+ "BENCHMARK_STARTUP", "BENCHMARK_BLINK_GC",
+ "BLINK_STYLE"};
+ for (size_t i = 0;
+ i <
+ sizeof(categories) / sizeof(BackgroundTracingConfigImpl::CategoryPreset);
+ i++) {
+ config->set_category_preset(categories[i]);
+ std::string expected =
+ std::string("{\"category\":\"") + category_strings[i] +
+ std::string(
+ "\",\"configs\":[{\"rule\":"
+ "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":"
+ "\"foo\"}],\"mode\":\"PREEMPTIVE_TRACING_MODE\"}");
+ EXPECT_EQ(ConfigToString(config.get()), expected.c_str());
+ scoped_ptr<BackgroundTracingConfigImpl> config2 =
+ ReadFromJSONString(expected);
+ EXPECT_EQ(config->category_preset(), config2->category_preset());
+ }
+}
+
TEST_F(BackgroundTracingConfigTest, ReactiveConfigFromValidString) {
scoped_ptr<BackgroundTracingConfigImpl> config;
diff --git a/chromium/content/browser/tracing/background_tracing_manager_impl.cc b/chromium/content/browser/tracing/background_tracing_manager_impl.cc
index 250d0fa4c13..ca394886207 100644
--- a/chromium/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/chromium/content/browser/tracing/background_tracing_manager_impl.cc
@@ -188,7 +188,7 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
}
bool BackgroundTracingManagerImpl::HasActiveScenario() {
- return config_;
+ return !!config_;
}
bool BackgroundTracingManagerImpl::IsTracingForTesting() {
@@ -515,6 +515,8 @@ BackgroundTracingManagerImpl::GetCategoryFilterStringForCategoryPreset(
return "benchmark,toplevel,startup,disabled-by-default-file,"
"disabled-by-default-toplevel.flow,"
"disabled-by-default-ipc.flow";
+ case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_BLINK_GC:
+ return "blink_gc,disabled-by-default-blink_gc";
case BackgroundTracingConfigImpl::CategoryPreset::BLINK_STYLE:
return "blink_style";
}
diff --git a/chromium/content/browser/tracing/battor_power_trace_provider.cc b/chromium/content/browser/tracing/battor_power_trace_provider.cc
deleted file mode 100644
index 41e99110381..00000000000
--- a/chromium/content/browser/tracing/battor_power_trace_provider.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/tracing/battor_power_trace_provider.h"
-
-namespace content {
-
-BattorPowerTraceProvider::BattorPowerTraceProvider() {}
-
-BattorPowerTraceProvider::~BattorPowerTraceProvider() {}
-
-bool BattorPowerTraceProvider::IsConnected() {
- return false;
-}
-
-bool BattorPowerTraceProvider::StartTracing() {
- return false;
-}
-
-bool BattorPowerTraceProvider::StopTracing() {
- return false;
-}
-
-void BattorPowerTraceProvider::RecordClockSyncMarker(int sync_id) {}
-
-void BattorPowerTraceProvider::GetLog(std::string* log_str) {
- // Get logs from battor.
- *log_str = "";
-}
-}
diff --git a/chromium/content/browser/tracing/battor_power_trace_provider.h b/chromium/content/browser/tracing/battor_power_trace_provider.h
deleted file mode 100644
index 8a9a5b5e890..00000000000
--- a/chromium/content/browser/tracing/battor_power_trace_provider.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_TRACING_BATTOR_POWER_TRACE_PROVIDER_H_
-#define CONTENT_BROWSER_TRACING_BATTOR_POWER_TRACE_PROVIDER_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace content {
-
-// This class handles the connection with the battor h/w using
-// chrome serial port interfaces.
-// TODO(charliea): port over battor C code.
-class BattorPowerTraceProvider {
- public:
- BattorPowerTraceProvider();
- bool IsConnected();
- bool StartTracing();
- bool StopTracing();
- void RecordClockSyncMarker(int sync_id);
- void GetLog(std::string* log_str);
- ~BattorPowerTraceProvider();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BattorPowerTraceProvider);
-};
-}
-#endif // CONTENT_BROWSER_TRACING_BATTOR_POWER_TRACE_PROVIDER_H_
diff --git a/chromium/content/browser/tracing/etw_system_event_consumer_win.cc b/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
index 07dfd4db7b8..09d81f7dbbd 100644
--- a/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
+++ b/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
@@ -11,6 +11,7 @@
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event_impl.h"
#include "content/public/browser/browser_thread.h"
@@ -49,11 +50,16 @@ std::string EtwSystemEventConsumer::GetTraceEventLabel() {
return kETWTraceLabel;
}
-bool EtwSystemEventConsumer::StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) {
+void EtwSystemEventConsumer::StartAgentTracing(
+ const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) {
// Activate kernel tracing.
- if (!StartKernelSessionTracing())
- return false;
+ if (!StartKernelSessionTracing()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, GetTracingAgentName(), false /* success */));
+ return;
+ }
// Start the consumer thread and start consuming events.
thread_.Start();
@@ -62,7 +68,9 @@ bool EtwSystemEventConsumer::StartAgentTracing(
base::Bind(&EtwSystemEventConsumer::TraceAndConsumeOnThread,
base::Unretained(this)));
- return true;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, GetTracingAgentName(), true /* success */));
}
void EtwSystemEventConsumer::StopAgentTracing(
diff --git a/chromium/content/browser/tracing/etw_system_event_consumer_win.h b/chromium/content/browser/tracing/etw_system_event_consumer_win.h
index 4327365386a..f14a37e623e 100644
--- a/chromium/content/browser/tracing/etw_system_event_consumer_win.h
+++ b/chromium/content/browser/tracing/etw_system_event_consumer_win.h
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_ptr.h"
#include "base/threading/thread.h"
#include "base/trace_event/tracing_agent.h"
#include "base/values.h"
@@ -28,8 +29,8 @@ class EtwSystemEventConsumer
// base::trace_event::TracingAgent implementation.
std::string GetTracingAgentName() override;
std::string GetTraceEventLabel() override;
- bool StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) override;
+ void StartAgentTracing(const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) override;
void StopAgentTracing(const StopAgentTracingCallback& callback) override;
// Retrieve the ETW consumer instance.
diff --git a/chromium/content/browser/tracing/power_tracing_agent.cc b/chromium/content/browser/tracing/power_tracing_agent.cc
index 6bf47e66bd2..5c0d654afa7 100644
--- a/chromium/content/browser/tracing/power_tracing_agent.cc
+++ b/chromium/content/browser/tracing/power_tracing_agent.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
+#include "base/thread_task_runner_handle.h"
#include "base/trace_event/trace_event_impl.h"
-#include "content/browser/tracing/battor_power_trace_provider.h"
#include "content/browser/tracing/power_tracing_agent.h"
-#include "content/public/browser/browser_thread.h"
+#include "tools/battor_agent/battor_finder.h"
namespace content {
@@ -23,10 +24,7 @@ PowerTracingAgent* PowerTracingAgent::GetInstance() {
return base::Singleton<PowerTracingAgent>::get();
}
-PowerTracingAgent::PowerTracingAgent() : thread_("PowerTracingAgentThread") {
- battor_trace_provider_.reset(new BattorPowerTraceProvider());
-}
-
+PowerTracingAgent::PowerTracingAgent() {}
PowerTracingAgent::~PowerTracingAgent() {}
std::string PowerTracingAgent::GetTracingAgentName() {
@@ -37,103 +35,151 @@ std::string PowerTracingAgent::GetTraceEventLabel() {
return kPowerTraceLabel;
}
-bool PowerTracingAgent::StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) {
+void PowerTracingAgent::StartAgentTracing(
+ const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // TODO(charliea): When system tracing is enabled in about://tracing, it will
- // trigger power tracing. We need a way of checking if BattOr is connected.
- // Currently, IsConnected() always returns false, so that we do not include
- // BattOr trace until it is hooked up.
- if (!battor_trace_provider_->IsConnected())
- return false;
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&PowerTracingAgent::FindBattOrOnFileThread,
+ base::Unretained(this), callback));
+}
+
+void PowerTracingAgent::FindBattOrOnFileThread(
+ const StartAgentTracingCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- thread_.Start();
+ std::string path = battor::BattOrFinder::FindBattOr();
+ if (path.empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, GetTracingAgentName(), false /* success */));
+ return;
+ }
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&PowerTracingAgent::TraceOnThread, base::Unretained(this)));
- return true;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PowerTracingAgent::StartAgentTracingOnIOThread,
+ base::Unretained(this), path, callback));
}
-void PowerTracingAgent::StopAgentTracing(
- const StopAgentTracingCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(thread_.IsRunning());
+void PowerTracingAgent::StartAgentTracingOnIOThread(
+ const std::string& path,
+ const StartAgentTracingCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&PowerTracingAgent::FlushOnThread, base::Unretained(this),
- callback));
+ battor_agent_.reset(new battor::BattOrAgent(
+ path, this,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
+
+ start_tracing_callback_ = callback;
+ battor_agent_->StartTracing();
}
-void PowerTracingAgent::OnStopTracingDone(
- const StopAgentTracingCallback& callback,
- const scoped_refptr<base::RefCountedString>& result) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+void PowerTracingAgent::OnStartTracingComplete(battor::BattOrError error) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Pass the serialized events.
- callback.Run(GetTracingAgentName(), GetTraceEventLabel(), result);
+ bool success = (error == battor::BATTOR_ERROR_NONE);
+ if (!success)
+ battor_agent_.reset();
- // Stop the power tracing agent thread on file thread.
BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&base::Thread::Stop, base::Unretained(&thread_)));
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(start_tracing_callback_, GetTracingAgentName(), success));
+ start_tracing_callback_.Reset();
}
-void PowerTracingAgent::TraceOnThread() {
- DCHECK(thread_.task_runner()->BelongsToCurrentThread());
- battor_trace_provider_->StartTracing();
+void PowerTracingAgent::StopAgentTracing(
+ const StopAgentTracingCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PowerTracingAgent::StopAgentTracingOnIOThread,
+ base::Unretained(this), callback));
}
-void PowerTracingAgent::FlushOnThread(
+void PowerTracingAgent::StopAgentTracingOnIOThread(
const StopAgentTracingCallback& callback) {
- DCHECK(thread_.task_runner()->BelongsToCurrentThread());
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!battor_agent_) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, GetTracingAgentName(), GetTraceEventLabel(),
+ nullptr /* events_str_ptr */));
+ return;
+ }
+
+ stop_tracing_callback_ = callback;
+ battor_agent_->StopTracing();
+}
+
+void PowerTracingAgent::OnStopTracingComplete(const std::string& trace,
+ battor::BattOrError error) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ scoped_refptr<base::RefCountedString> result(new base::RefCountedString());
+ if (error == battor::BATTOR_ERROR_NONE)
+ result->data() = trace;
- battor_trace_provider_->StopTracing();
- std::string battor_logs;
- battor_trace_provider_->GetLog(&battor_logs);
- scoped_refptr<base::RefCountedString> result =
- base::RefCountedString::TakeString(&battor_logs);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&PowerTracingAgent::OnStopTracingDone,
- base::Unretained(this),
- callback,
- result));
-}
-
-bool PowerTracingAgent::SupportsExplicitClockSync() {
- return true;
+ base::Bind(stop_tracing_callback_, GetTracingAgentName(),
+ GetTraceEventLabel(), result));
+ stop_tracing_callback_.Reset();
+ battor_agent_.reset();
}
void PowerTracingAgent::RecordClockSyncMarker(
- int sync_id,
+ const std::string& sync_id,
const RecordClockSyncMarkerCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(SupportsExplicitClockSync());
- thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&PowerTracingAgent::RecordClockSyncMarkerOnThread,
- base::Unretained(this),
- sync_id,
- callback));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PowerTracingAgent::RecordClockSyncMarkerOnIOThread,
+ base::Unretained(this), sync_id, callback));
}
-void PowerTracingAgent::RecordClockSyncMarkerOnThread(
- int sync_id,
+void PowerTracingAgent::RecordClockSyncMarkerOnIOThread(
+ const std::string& sync_id,
const RecordClockSyncMarkerCallback& callback) {
- DCHECK(thread_.task_runner()->BelongsToCurrentThread());
- DCHECK(SupportsExplicitClockSync());
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(battor_agent_);
- base::TimeTicks issue_ts = base::TimeTicks::Now();
- battor_trace_provider_->RecordClockSyncMarker(sync_id);
+ record_clock_sync_marker_sync_id_ = sync_id;
+ record_clock_sync_marker_callback_ = callback;
+ record_clock_sync_marker_start_time_ = base::TimeTicks::Now();
+ battor_agent_->RecordClockSyncMarker(sync_id);
+}
+
+void PowerTracingAgent::OnRecordClockSyncMarkerComplete(
+ battor::BattOrError error) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ base::TimeTicks issue_start_ts = record_clock_sync_marker_start_time_;
base::TimeTicks issue_end_ts = base::TimeTicks::Now();
+ if (error != battor::BATTOR_ERROR_NONE)
+ issue_start_ts = issue_end_ts = base::TimeTicks();
+
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(callback, sync_id, issue_ts, issue_end_ts));
+ base::Bind(record_clock_sync_marker_callback_,
+ record_clock_sync_marker_sync_id_,
+ issue_start_ts,
+ issue_end_ts));
+
+ record_clock_sync_marker_callback_.Reset();
+ record_clock_sync_marker_sync_id_ = std::string();
+ record_clock_sync_marker_start_time_ = base::TimeTicks();
+}
+
+bool PowerTracingAgent::SupportsExplicitClockSync() {
+ return battor_agent_->SupportsExplicitClockSync();
}
} // namespace content
diff --git a/chromium/content/browser/tracing/power_tracing_agent.h b/chromium/content/browser/tracing/power_tracing_agent.h
index 58c6a87d02c..0fa97fe5dd5 100644
--- a/chromium/content/browser/tracing/power_tracing_agent.h
+++ b/chromium/content/browser/tracing/power_tracing_agent.h
@@ -7,8 +7,12 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_ptr.h"
#include "base/threading/thread.h"
#include "base/trace_event/tracing_agent.h"
+#include "content/public/browser/browser_thread.h"
+#include "tools/battor_agent/battor_agent.h"
+#include "tools/battor_agent/battor_error.h"
namespace base {
template <typename Type>
@@ -17,46 +21,61 @@ struct DefaultSingletonTraits;
namespace content {
-class BattorPowerTraceProvider;
-
-class PowerTracingAgent : public base::trace_event::TracingAgent {
+class PowerTracingAgent : public base::trace_event::TracingAgent,
+ public battor::BattOrAgent::Listener {
public:
// Retrieve the singleton instance.
static PowerTracingAgent* GetInstance();
+ void StartAgentTracing(const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) override;
+ void StopAgentTracing(const StopAgentTracingCallback& callback) override;
+ void RecordClockSyncMarker(
+ const std::string& sync_id,
+ const RecordClockSyncMarkerCallback& callback) override;
+
+ bool SupportsExplicitClockSync() override;
+
// base::trace_event::TracingAgent implementation.
std::string GetTracingAgentName() override;
std::string GetTraceEventLabel() override;
- bool StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) override;
- void StopAgentTracing(const StopAgentTracingCallback& callback) override;
-
- bool SupportsExplicitClockSync() override;
- void RecordClockSyncMarker(
- int sync_id,
- const RecordClockSyncMarkerCallback& callback) override;
+ // BattOrAgent::Listener implementation.
+ void OnStartTracingComplete(battor::BattOrError error) override;
+ void OnStopTracingComplete(const std::string& trace,
+ battor::BattOrError error) override;
+ void OnRecordClockSyncMarkerComplete(battor::BattOrError error) override;
private:
// This allows constructor and destructor to be private and usable only
// by the Singleton class.
friend struct base::DefaultSingletonTraits<PowerTracingAgent>;
- // Constructor.
PowerTracingAgent();
~PowerTracingAgent() override;
- void OnStopTracingDone(const StopAgentTracingCallback& callback,
- const scoped_refptr<base::RefCountedString>& result);
-
- void TraceOnThread();
- void FlushOnThread(const StopAgentTracingCallback& callback);
- void RecordClockSyncMarkerOnThread(
- int sync_id,
+ void FindBattOrOnFileThread(const StartAgentTracingCallback& callback);
+ void StartAgentTracingOnIOThread(const std::string& path,
+ const StartAgentTracingCallback& callback);
+ void StopAgentTracingOnIOThread(const StopAgentTracingCallback& callback);
+ void RecordClockSyncMarkerOnIOThread(
+ const std::string& sync_id,
const RecordClockSyncMarkerCallback& callback);
- base::Thread thread_;
- scoped_ptr<BattorPowerTraceProvider> battor_trace_provider_;
+ // Returns the path of a BattOr (e.g. /dev/ttyUSB0), or an empty string if
+ // none are found.
+ std::string GetBattOrPath();
+
+ // All interactions with the BattOrAgent (after construction) must happen on
+ // the IO thread.
+ scoped_ptr<battor::BattOrAgent, BrowserThread::DeleteOnIOThread>
+ battor_agent_;
+
+ StartAgentTracingCallback start_tracing_callback_;
+ StopAgentTracingCallback stop_tracing_callback_;
+ std::string record_clock_sync_marker_sync_id_;
+ base::TimeTicks record_clock_sync_marker_start_time_;
+ RecordClockSyncMarkerCallback record_clock_sync_marker_callback_;
DISALLOW_COPY_AND_ASSIGN(PowerTracingAgent);
};
diff --git a/chromium/content/browser/tracing/trace_message_filter.cc b/chromium/content/browser/tracing/trace_message_filter.cc
index 45cb7023379..d9168e718bb 100644
--- a/chromium/content/browser/tracing/trace_message_filter.cc
+++ b/chromium/content/browser/tracing/trace_message_filter.cc
@@ -18,7 +18,6 @@ TraceMessageFilter::TraceMessageFilter(int child_process_id)
ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
child_process_id)),
is_awaiting_end_ack_(false),
- is_awaiting_capture_monitoring_snapshot_ack_(false),
is_awaiting_buffer_percent_full_ack_(false) {
}
@@ -29,9 +28,6 @@ void TraceMessageFilter::OnChannelClosing() {
if (is_awaiting_end_ack_)
OnEndTracingAck(std::vector<std::string>());
- if (is_awaiting_capture_monitoring_snapshot_ack_)
- OnCaptureMonitoringSnapshotAcked();
-
if (is_awaiting_buffer_percent_full_ack_)
OnTraceLogStatusReply(base::trace_event::TraceLogStatus());
@@ -46,12 +42,8 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(TracingHostMsg_ChildSupportsTracing,
OnChildSupportsTracing)
IPC_MESSAGE_HANDLER(TracingHostMsg_EndTracingAck, OnEndTracingAck)
- IPC_MESSAGE_HANDLER(TracingHostMsg_CaptureMonitoringSnapshotAck,
- OnCaptureMonitoringSnapshotAcked)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceDataCollected,
OnTraceDataCollected)
- IPC_MESSAGE_HANDLER(TracingHostMsg_MonitoringTraceDataCollected,
- OnMonitoringTraceDataCollected)
IPC_MESSAGE_HANDLER(TracingHostMsg_WatchEventMatched,
OnWatchEventMatched)
IPC_MESSAGE_HANDLER(TracingHostMsg_TraceLogStatusReply,
@@ -90,25 +82,6 @@ void TraceMessageFilter::SendCancelTracing() {
Send(new TracingMsg_CancelTracing);
}
-void TraceMessageFilter::SendStartMonitoring(
- const base::trace_event::TraceConfig& trace_config) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- Send(new TracingMsg_StartMonitoring(trace_config.ToString(),
- base::TimeTicks::Now()));
-}
-
-void TraceMessageFilter::SendStopMonitoring() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- Send(new TracingMsg_StopMonitoring);
-}
-
-void TraceMessageFilter::SendCaptureMonitoringSnapshot() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(!is_awaiting_capture_monitoring_snapshot_ack_);
- is_awaiting_capture_monitoring_snapshot_ack_ = true;
- Send(new TracingMsg_CaptureMonitoringSnapshot);
-}
-
void TraceMessageFilter::SendGetTraceLogStatus() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_awaiting_buffer_percent_full_ack_);
@@ -155,32 +128,12 @@ void TraceMessageFilter::OnEndTracingAck(
}
}
-void TraceMessageFilter::OnCaptureMonitoringSnapshotAcked() {
- // is_awaiting_capture_monitoring_snapshot_ack_ should always be true here,
- // but check in case the child process is compromised.
- if (is_awaiting_capture_monitoring_snapshot_ack_) {
- is_awaiting_capture_monitoring_snapshot_ack_ = false;
- TracingControllerImpl::GetInstance()->OnCaptureMonitoringSnapshotAcked(
- this);
- } else {
- NOTREACHED();
- }
-}
-
void TraceMessageFilter::OnTraceDataCollected(const std::string& data) {
scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString());
data_ptr->data() = data;
TracingControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr);
}
-void TraceMessageFilter::OnMonitoringTraceDataCollected(
- const std::string& data) {
- scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString());
- data_ptr->data() = data;
- TracingControllerImpl::GetInstance()->OnMonitoringTraceDataCollected(
- data_ptr);
-}
-
void TraceMessageFilter::OnWatchEventMatched() {
TracingControllerImpl::GetInstance()->OnWatchEventMatched();
}
diff --git a/chromium/content/browser/tracing/trace_message_filter.h b/chromium/content/browser/tracing/trace_message_filter.h
index 22d91d914ad..94c435ed1b6 100644
--- a/chromium/content/browser/tracing/trace_message_filter.h
+++ b/chromium/content/browser/tracing/trace_message_filter.h
@@ -32,10 +32,6 @@ class TraceMessageFilter : public BrowserMessageFilter {
const base::trace_event::TraceConfig& trace_config);
void SendEndTracing();
void SendCancelTracing();
- void SendStartMonitoring(
- const base::trace_event::TraceConfig& trace_config);
- void SendStopMonitoring();
- void SendCaptureMonitoringSnapshot();
void SendGetTraceLogStatus();
void SendSetWatchEvent(const std::string& category_name,
const std::string& event_name);
@@ -50,11 +46,9 @@ class TraceMessageFilter : public BrowserMessageFilter {
// Message handlers.
void OnChildSupportsTracing();
void OnEndTracingAck(const std::vector<std::string>& known_categories);
- void OnCaptureMonitoringSnapshotAcked();
void OnWatchEventMatched();
void OnTraceLogStatusReply(const base::trace_event::TraceLogStatus& status);
void OnTraceDataCollected(const std::string& data);
- void OnMonitoringTraceDataCollected(const std::string& data);
void OnGlobalMemoryDumpRequest(
const base::trace_event::MemoryDumpRequestArgs& args);
void OnProcessMemoryDumpResponse(uint64_t dump_guid, bool success);
@@ -71,8 +65,6 @@ class TraceMessageFilter : public BrowserMessageFilter {
// Awaiting ack for previously sent SendEndTracing
bool is_awaiting_end_ack_;
- // Awaiting ack for previously sent SendCaptureMonitoringSnapshot
- bool is_awaiting_capture_monitoring_snapshot_ack_;
// Awaiting ack for previously sent SendGetTraceLogStatus
bool is_awaiting_buffer_percent_full_ack_;
diff --git a/chromium/content/browser/tracing/tracing_controller_browsertest.cc b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
index d4b8671d915..8cafbd7df88 100644
--- a/chromium/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
@@ -80,7 +80,7 @@ class TracingControllerTestEndpoint
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(done_callback_, base::Passed(std::move(metadata)),
- chunk_ptr));
+ base::RetainedRef(chunk_ptr)));
}
protected:
@@ -99,9 +99,6 @@ class TracingControllerTest : public ContentBrowserTest {
get_categories_done_callback_count_ = 0;
enable_recording_done_callback_count_ = 0;
disable_recording_done_callback_count_ = 0;
- enable_monitoring_done_callback_count_ = 0;
- disable_monitoring_done_callback_count_ = 0;
- capture_monitoring_snapshot_done_callback_count_ = 0;
ContentBrowserTest::SetUp();
}
@@ -145,28 +142,7 @@ class TracingControllerTest : public ContentBrowserTest {
last_actual_recording_file_path_ = file_path;
}
- void StartMonitoringDoneCallbackTest(base::Closure quit_callback) {
- enable_monitoring_done_callback_count_++;
- quit_callback.Run();
- }
-
- void StopMonitoringDoneCallbackTest(base::Closure quit_callback) {
- disable_monitoring_done_callback_count_++;
- quit_callback.Run();
- }
-
- void CaptureMonitoringSnapshotDoneCallbackTest(
- base::Closure quit_callback, const base::FilePath& file_path) {
- capture_monitoring_snapshot_done_callback_count_++;
- EXPECT_TRUE(PathExists(file_path));
- int64_t file_size;
- base::GetFileSize(file_path, &file_size);
- EXPECT_TRUE(file_size > 0);
- quit_callback.Run();
- last_actual_monitoring_file_path_ = file_path;
- }
-
- int get_categories_done_callback_count() const {
+ int get_categories_done_callback_count() const {
return get_categories_done_callback_count_;
}
@@ -178,26 +154,10 @@ class TracingControllerTest : public ContentBrowserTest {
return disable_recording_done_callback_count_;
}
- int enable_monitoring_done_callback_count() const {
- return enable_monitoring_done_callback_count_;
- }
-
- int disable_monitoring_done_callback_count() const {
- return disable_monitoring_done_callback_count_;
- }
-
- int capture_monitoring_snapshot_done_callback_count() const {
- return capture_monitoring_snapshot_done_callback_count_;
- }
-
base::FilePath last_actual_recording_file_path() const {
return last_actual_recording_file_path_;
}
- base::FilePath last_actual_monitoring_file_path() const {
- return last_actual_monitoring_file_path_;
- }
-
const base::DictionaryValue* last_metadata() const {
return last_metadata_.get();
}
@@ -382,96 +342,11 @@ class TracingControllerTest : public ContentBrowserTest {
}
}
- void TestEnableCaptureAndStopMonitoring(
- const base::FilePath& result_file_path) {
- Navigate(shell());
-
- TracingController* controller = TracingController::GetInstance();
-
- {
- bool is_monitoring;
- TraceConfig trace_config("", "");
- controller->GetMonitoringStatus(
- &is_monitoring, &trace_config);
- EXPECT_FALSE(is_monitoring);
- EXPECT_EQ("-*Debug,-*Test", trace_config.ToCategoryFilterString());
- EXPECT_FALSE(trace_config.GetTraceRecordMode() == RECORD_CONTINUOUSLY);
- EXPECT_FALSE(trace_config.IsSamplingEnabled());
- EXPECT_FALSE(trace_config.IsSystraceEnabled());
- }
-
- {
- base::RunLoop run_loop;
- TracingController::StartMonitoringDoneCallback callback =
- base::Bind(&TracingControllerTest::StartMonitoringDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure());
-
- TraceConfig trace_config("*", "");
- trace_config.EnableSampling();
- bool result = controller->StartMonitoring(trace_config, callback);
- ASSERT_TRUE(result);
- run_loop.Run();
- EXPECT_EQ(enable_monitoring_done_callback_count(), 1);
- }
-
- {
- bool is_monitoring;
- TraceConfig trace_config("", "");
- controller->GetMonitoringStatus(&is_monitoring, &trace_config);
- EXPECT_TRUE(is_monitoring);
- EXPECT_EQ("*", trace_config.ToCategoryFilterString());
- EXPECT_FALSE(trace_config.GetTraceRecordMode() == RECORD_CONTINUOUSLY);
- EXPECT_TRUE(trace_config.IsSamplingEnabled());
- EXPECT_FALSE(trace_config.IsSystraceEnabled());
- }
-
- {
- base::RunLoop run_loop;
- base::Closure callback = base::Bind(
- &TracingControllerTest::CaptureMonitoringSnapshotDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure(),
- result_file_path);
- ASSERT_TRUE(controller->CaptureMonitoringSnapshot(
- TracingController::CreateFileSink(result_file_path, callback)));
- run_loop.Run();
- EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1);
- }
-
- {
- base::RunLoop run_loop;
- TracingController::StopMonitoringDoneCallback callback =
- base::Bind(&TracingControllerTest::StopMonitoringDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure());
- bool result = controller->StopMonitoring(callback);
- ASSERT_TRUE(result);
- run_loop.Run();
- EXPECT_EQ(disable_monitoring_done_callback_count(), 1);
- }
-
- {
- bool is_monitoring;
- TraceConfig trace_config("", "");
- controller->GetMonitoringStatus(&is_monitoring, &trace_config);
- EXPECT_FALSE(is_monitoring);
- EXPECT_EQ("", trace_config.ToCategoryFilterString());
- EXPECT_FALSE(trace_config.GetTraceRecordMode() == RECORD_CONTINUOUSLY);
- EXPECT_FALSE(trace_config.IsSamplingEnabled());
- EXPECT_FALSE(trace_config.IsSystraceEnabled());
- }
- }
-
private:
int get_categories_done_callback_count_;
int enable_recording_done_callback_count_;
int disable_recording_done_callback_count_;
- int enable_monitoring_done_callback_count_;
- int disable_monitoring_done_callback_count_;
- int capture_monitoring_snapshot_done_callback_count_;
base::FilePath last_actual_recording_file_path_;
- base::FilePath last_actual_monitoring_file_path_;
scoped_ptr<const base::DictionaryValue> last_metadata_;
std::string last_data_;
};
@@ -585,45 +460,4 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
base::RunLoop().RunUntilIdle();
}
-IN_PROC_BROWSER_TEST_F(TracingControllerTest,
- EnableCaptureAndStopMonitoring) {
- base::FilePath file_path;
- base::CreateTemporaryFile(&file_path);
- TestEnableCaptureAndStopMonitoring(file_path);
-}
-
-IN_PROC_BROWSER_TEST_F(TracingControllerTest,
- EnableCaptureAndStopMonitoringWithFilePath) {
- base::FilePath file_path;
- base::CreateTemporaryFile(&file_path);
- TestEnableCaptureAndStopMonitoring(file_path);
- EXPECT_EQ(file_path.value(), last_actual_monitoring_file_path().value());
-}
-
-// See http://crbug.com/392446
-#if defined(OS_ANDROID)
-#define MAYBE_EnableCaptureAndStopMonitoringWithEmptyFileAndNullCallback \
- DISABLED_EnableCaptureAndStopMonitoringWithEmptyFileAndNullCallback
-#else
-#define MAYBE_EnableCaptureAndStopMonitoringWithEmptyFileAndNullCallback \
- EnableCaptureAndStopMonitoringWithEmptyFileAndNullCallback
-#endif
-IN_PROC_BROWSER_TEST_F(
- TracingControllerTest,
- MAYBE_EnableCaptureAndStopMonitoringWithEmptyFileAndNullCallback) {
- Navigate(shell());
-
- TracingController* controller = TracingController::GetInstance();
- TraceConfig trace_config("*", "");
- trace_config.EnableSampling();
- EXPECT_TRUE(controller->StartMonitoring(
- trace_config,
- TracingController::StartMonitoringDoneCallback()));
- controller->CaptureMonitoringSnapshot(NULL);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(controller->StopMonitoring(
- TracingController::StopMonitoringDoneCallback()));
- base::RunLoop().RunUntilIdle();
-}
-
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.cc b/chromium/content/browser/tracing/tracing_controller_impl.cc
index 684bea8ec49..06ef7c8f04b 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl.cc
@@ -6,14 +6,18 @@
#include "base/bind.h"
#include "base/cpu.h"
#include "base/files/file_util.h"
+#include "base/guid.h"
#include "base/json/string_escape.h"
#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "components/tracing/process_metrics_memory_dump_provider.h"
#include "content/browser/tracing/file_tracing_provider_impl.h"
-#include "content/browser/tracing/power_tracing_agent.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/tracing/tracing_ui.h"
#include "content/common/child_process_messages.h"
@@ -27,6 +31,15 @@
#include "gpu/config/gpu_info.h"
#include "net/base/network_change_notifier.h"
+#if (defined(OS_POSIX) && defined(USE_UDEV)) || defined(OS_WIN) || \
+ defined(OS_MACOSX)
+#define ENABLE_POWER_TRACING
+#endif
+
+#if defined(ENABLE_POWER_TRACING)
+#include "content/browser/tracing/power_tracing_agent.h"
+#endif
+
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon_client.h"
@@ -50,7 +63,9 @@ const char kChromeTracingAgentName[] = "chrome";
const char kETWTracingAgentName[] = "etw";
const char kChromeTraceLabel[] = "traceEvents";
-const int kIssueClockSyncTimeout = 30;
+const int kStartTracingTimeoutSeconds = 30;
+const int kIssueClockSyncTimeoutSeconds = 30;
+const int kStopTracingRetryTimeMilliseconds = 100;
std::string GetNetworkTypeString() {
switch (net::NetworkChangeNotifier::GetConnectionType()) {
@@ -75,6 +90,24 @@ std::string GetNetworkTypeString() {
return "Unknown";
}
+std::string GetClockString() {
+ switch (base::TimeTicks::GetClock()) {
+ case base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC:
+ return "LINUX_CLOCK_MONOTONIC";
+ case base::TimeTicks::Clock::IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME:
+ return "IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME";
+ case base::TimeTicks::Clock::MAC_MACH_ABSOLUTE_TIME:
+ return "MAC_MACH_ABSOLUTE_TIME";
+ case base::TimeTicks::Clock::WIN_QPC:
+ return "WIN_QPC";
+ case base::TimeTicks::Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME:
+ return "WIN_ROLLOVER_PROTECTED_TIME_GET_TIME";
+ }
+
+ NOTREACHED();
+ return std::string();
+}
+
scoped_ptr<base::DictionaryValue> GenerateTracingMetadataDict() {
scoped_ptr<base::DictionaryValue> metadata_dict(new base::DictionaryValue());
@@ -130,7 +163,7 @@ scoped_ptr<base::DictionaryValue> GenerateTracingMetadataDict() {
if (delegate)
delegate->GenerateMetadataDict(metadata_dict.get());
- // Highres ticks.
+ metadata_dict->SetString("clock-domain", GetClockString());
metadata_dict->SetBoolean("highres-ticks",
base::TimeTicks::IsHighResolution());
@@ -144,17 +177,15 @@ TracingController* TracingController::GetInstance() {
}
TracingControllerImpl::TracingControllerImpl()
- : pending_stop_tracing_ack_count_(0),
- pending_capture_monitoring_snapshot_ack_count_(0),
+ : pending_start_tracing_ack_count_(0),
+ pending_stop_tracing_ack_count_(0),
pending_trace_log_status_ack_count_(0),
maximum_trace_buffer_usage_(0),
approximate_event_count_(0),
pending_memory_dump_ack_count_(0),
failed_memory_dump_count_(0),
- clock_sync_id_(0),
pending_clock_sync_ack_count_(0),
- is_tracing_(false),
- is_monitoring_(false) {
+ is_tracing_(false) {
base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
this /* delegate */, true /* is_coordinator */);
@@ -218,6 +249,9 @@ bool TracingControllerImpl::StartTracing(
return false;
is_tracing_ = true;
start_tracing_done_callback_ = callback;
+ start_tracing_trace_config_.reset(
+ new base::trace_event::TraceConfig(trace_config));
+ pending_start_tracing_ack_count_ = 0;
#if defined(OS_ANDROID)
if (pending_get_categories_done_callback_.is_null())
@@ -225,56 +259,92 @@ bool TracingControllerImpl::StartTracing(
#endif
if (trace_config.IsSystraceEnabled()) {
- if (PowerTracingAgent::GetInstance()->StartAgentTracing(trace_config))
- additional_tracing_agents_.push_back(PowerTracingAgent::GetInstance());
+#if defined(ENABLE_POWER_TRACING)
+ PowerTracingAgent::GetInstance()->StartAgentTracing(
+ trace_config,
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked,
+ base::Unretained(this)));
+ ++pending_start_tracing_ack_count_;
+#endif
+
#if defined(OS_CHROMEOS)
chromeos::DebugDaemonClient* debug_daemon =
chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
- if (debug_daemon && debug_daemon->StartAgentTracing(trace_config)) {
- debug_daemon->SetStopAgentTracingTaskRunner(
- BrowserThread::GetBlockingPool());
- additional_tracing_agents_.push_back(
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient());
+ if (debug_daemon) {
+ debug_daemon->StartAgentTracing(
+ trace_config,
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked,
+ base::Unretained(this)));
+ ++pending_start_tracing_ack_count_;
}
#elif defined(OS_WIN)
- if (EtwSystemEventConsumer::GetInstance()->StartAgentTracing(
- trace_config)) {
- additional_tracing_agents_.push_back(
- EtwSystemEventConsumer::GetInstance());
- }
+ EtwSystemEventConsumer::GetInstance()->StartAgentTracing(
+ trace_config,
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked,
+ base::Unretained(this)));
+ ++pending_start_tracing_ack_count_;
#endif
}
// TraceLog may have been enabled in startup tracing before threads are ready.
if (TraceLog::GetInstance()->IsEnabled())
return true;
- return StartAgentTracing(trace_config);
+
+ StartAgentTracing(trace_config,
+ base::Bind(&TracingControllerImpl::OnStartAgentTracingAcked,
+ base::Unretained(this)));
+ ++pending_start_tracing_ack_count_;
+
+ // Set a deadline to ensure all agents ack within a reasonable time frame.
+ start_tracing_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kStartTracingTimeoutSeconds),
+ base::Bind(&TracingControllerImpl::OnAllTracingAgentsStarted,
+ base::Unretained(this)));
+
+ return true;
}
-void TracingControllerImpl::OnStartAgentTracingDone(
- const TraceConfig& trace_config,
- const StartTracingDoneCallback& callback) {
+void TracingControllerImpl::OnAllTracingAgentsStarted() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- TRACE_EVENT_API_ADD_METADATA_EVENT("IsTimeTicksHighResolution", "value",
- base::TimeTicks::IsHighResolution());
- TRACE_EVENT_API_ADD_METADATA_EVENT("TraceConfig", "value",
- trace_config.AsConvertableToTraceFormat());
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ TraceLog::GetCategoryGroupEnabled("__metadata"),
+ "IsTimeTicksHighResolution", "value",
+ base::TimeTicks::IsHighResolution());
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ TraceLog::GetCategoryGroupEnabled("__metadata"), "TraceConfig", "value",
+ start_tracing_trace_config_->AsConvertableToTraceFormat());
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
it != trace_message_filters_.end(); ++it) {
- it->get()->SendBeginTracing(trace_config);
+ it->get()->SendBeginTracing(*start_tracing_trace_config_);
}
- if (!callback.is_null())
- callback.Run();
+ if (!start_tracing_done_callback_.is_null())
+ start_tracing_done_callback_.Run();
+
+ start_tracing_done_callback_.Reset();
+ start_tracing_trace_config_.reset();
}
bool TracingControllerImpl::StopTracing(
const scoped_refptr<TraceDataSink>& trace_data_sink) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!can_stop_tracing())
+ return false;
+
+ // If we're still waiting to start tracing, try again after a delay.
+ if (start_tracing_timer_.IsRunning()) {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&TracingControllerImpl::StopTracing),
+ base::Unretained(this), trace_data_sink),
+ base::TimeDelta::FromMilliseconds(kStopTracingRetryTimeMilliseconds));
+ return true;
+ }
+
if (trace_data_sink) {
if (TraceLog::GetInstance()->GetCurrentTraceConfig()
.IsArgumentFilterEnabled()) {
@@ -288,9 +358,6 @@ bool TracingControllerImpl::StopTracing(
trace_data_sink->AddMetadata(*GenerateTracingMetadataDict().get());
}
- if (!can_stop_tracing())
- return false;
-
trace_data_sink_ = trace_data_sink;
// Issue clock sync marker before actually stopping tracing.
@@ -340,134 +407,6 @@ void TracingControllerImpl::OnStopTracingDone() {
StopAgentTracing(StopAgentTracingCallback());
}
-bool TracingControllerImpl::StartMonitoring(
- const TraceConfig& trace_config,
- const StartMonitoringDoneCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- if (!can_start_monitoring())
- return false;
- OnMonitoringStateChanged(true);
-
-#if defined(OS_ANDROID)
- TraceLog::GetInstance()->AddClockSyncMetadataEvent();
-#endif
-
- base::Closure on_start_monitoring_done_callback =
- base::Bind(&TracingControllerImpl::OnStartMonitoringDone,
- base::Unretained(this),
- trace_config, callback);
- if (!BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
- base::Unretained(this), trace_config,
- base::trace_event::TraceLog::MONITORING_MODE,
- on_start_monitoring_done_callback))) {
- // BrowserThread::PostTask fails if the threads haven't been created yet,
- // so it should be safe to just use TraceLog::SetEnabled directly.
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- trace_config, base::trace_event::TraceLog::MONITORING_MODE);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- on_start_monitoring_done_callback);
- }
- return true;
-}
-
-void TracingControllerImpl::OnStartMonitoringDone(
- const TraceConfig& trace_config,
- const StartMonitoringDoneCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- // Notify all child processes.
- for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
- it != trace_message_filters_.end(); ++it) {
- it->get()->SendStartMonitoring(trace_config);
- }
-
- if (!callback.is_null())
- callback.Run();
-}
-
-bool TracingControllerImpl::StopMonitoring(
- const StopMonitoringDoneCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- if (!can_stop_monitoring())
- return false;
-
- base::Closure on_stop_monitoring_done_callback =
- base::Bind(&TracingControllerImpl::OnStopMonitoringDone,
- base::Unretained(this), callback);
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
- base::Unretained(this),
- on_stop_monitoring_done_callback));
- return true;
-}
-
-void TracingControllerImpl::OnStopMonitoringDone(
- const StopMonitoringDoneCallback& callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- OnMonitoringStateChanged(false);
-
- // Notify all child processes.
- for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
- it != trace_message_filters_.end(); ++it) {
- it->get()->SendStopMonitoring();
- }
- if (!callback.is_null())
- callback.Run();
-}
-
-void TracingControllerImpl::GetMonitoringStatus(
- bool* out_enabled,
- TraceConfig* out_trace_config) {
- *out_enabled = is_monitoring_;
- *out_trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
-}
-
-bool TracingControllerImpl::CaptureMonitoringSnapshot(
- const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- if (!can_stop_monitoring())
- return false;
-
- if (!monitoring_data_sink.get())
- return false;
-
- monitoring_data_sink_ = monitoring_data_sink;
-
- // Count myself in pending_capture_monitoring_snapshot_ack_count_,
- // acked below.
- pending_capture_monitoring_snapshot_ack_count_ =
- trace_message_filters_.size() + 1;
- pending_capture_monitoring_filters_ = trace_message_filters_;
-
- // Handle special case of zero child processes by immediately flushing the
- // trace log. Once the flush has completed the caller will be notified that
- // the capture snapshot has ended.
- if (pending_capture_monitoring_snapshot_ack_count_ == 1) {
- // Flush asynchronously now, because we don't have any children to wait for.
- TraceLog::GetInstance()->FlushButLeaveBufferIntact(
- base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
- base::Unretained(this)));
- }
-
- // Notify all child processes.
- for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
- it != trace_message_filters_.end(); ++it) {
- it->get()->SendCaptureMonitoringSnapshot();
- }
-
-#if defined(OS_ANDROID)
- TraceLog::GetInstance()->AddClockSyncMetadataEvent();
-#endif
-
- return true;
-}
-
bool TracingControllerImpl::GetTraceBufferUsage(
const GetTraceBufferUsageCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -491,8 +430,7 @@ bool TracingControllerImpl::GetTraceBufferUsage(
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
- base::Unretained(this), scoped_refptr<TraceMessageFilter>(),
- status));
+ base::Unretained(this), nullptr, status));
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
@@ -549,13 +487,21 @@ bool TracingControllerImpl::IsTracing() const {
void TracingControllerImpl::AddTraceMessageFilter(
TraceMessageFilter* trace_message_filter) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::AddTraceMessageFilter,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter)));
+ base::RetainedRef(trace_message_filter)));
return;
}
+#if defined(OS_LINUX)
+ // On Linux the browser process dumps process metrics for child process due to
+ // sandbox.
+ tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
+ trace_message_filter->peer_pid());
+#endif
+
trace_message_filters_.insert(trace_message_filter);
if (can_cancel_watch_event()) {
trace_message_filter->SendSetWatchEvent(watch_category_name_,
@@ -565,10 +511,6 @@ void TracingControllerImpl::AddTraceMessageFilter(
trace_message_filter->SendBeginTracing(
TraceLog::GetInstance()->GetCurrentTraceConfig());
}
- if (can_stop_monitoring()) {
- trace_message_filter->SendStartMonitoring(
- TraceLog::GetInstance()->GetCurrentTraceConfig());
- }
FOR_EACH_OBSERVER(TraceMessageFilterObserver, trace_message_filter_observers_,
OnTraceMessageFilterAdded(trace_message_filter));
@@ -577,13 +519,19 @@ void TracingControllerImpl::AddTraceMessageFilter(
void TracingControllerImpl::RemoveTraceMessageFilter(
TraceMessageFilter* trace_message_filter) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter)));
+ base::RetainedRef(trace_message_filter)));
return;
}
+#if defined(OS_LINUX)
+ tracing::ProcessMetricsMemoryDumpProvider::UnregisterForProcess(
+ trace_message_filter->peer_pid());
+#endif
+
// If a filter is removed while a response from that filter is pending then
// simulate the response. Otherwise the response count will be wrong and the
// completion callback will never be executed.
@@ -591,23 +539,14 @@ void TracingControllerImpl::RemoveTraceMessageFilter(
TraceMessageFilterSet::const_iterator it =
pending_stop_tracing_filters_.find(trace_message_filter);
if (it != pending_stop_tracing_filters_.end()) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnStopTracingAcked,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter),
+ base::RetainedRef(trace_message_filter),
std::vector<std::string>()));
}
}
- if (pending_capture_monitoring_snapshot_ack_count_ > 0) {
- TraceMessageFilterSet::const_iterator it =
- pending_capture_monitoring_filters_.find(trace_message_filter);
- if (it != pending_capture_monitoring_filters_.end()) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
- base::Unretained(this),
- make_scoped_refptr(trace_message_filter)));
- }
- }
if (pending_trace_log_status_ack_count_ > 0) {
TraceMessageFilterSet::const_iterator it =
pending_trace_log_status_filters_.find(trace_message_filter);
@@ -616,7 +555,7 @@ void TracingControllerImpl::RemoveTraceMessageFilter(
BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter),
+ base::RetainedRef(trace_message_filter),
base::trace_event::TraceLogStatus()));
}
}
@@ -628,22 +567,69 @@ void TracingControllerImpl::RemoveTraceMessageFilter(
BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter),
+ base::RetainedRef(trace_message_filter),
pending_memory_dump_guid_, false /* success */));
}
}
trace_message_filters_.erase(trace_message_filter);
}
+void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) {
+#if defined(OS_CHROMEOS)
+ auto debug_daemon =
+ chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
+ if (agent_name == debug_daemon->GetTracingAgentName()) {
+ additional_tracing_agents_.push_back(debug_daemon);
+ debug_daemon->SetStopAgentTracingTaskRunner(
+ BrowserThread::GetBlockingPool());
+ return;
+ }
+#elif defined(OS_WIN)
+ auto etw_agent = EtwSystemEventConsumer::GetInstance();
+ if (agent_name == etw_agent->GetTracingAgentName()) {
+ additional_tracing_agents_.push_back(etw_agent);
+ return;
+ }
+#endif
+
+#if defined(ENABLE_POWER_TRACING)
+ auto power_agent = PowerTracingAgent::GetInstance();
+ if (agent_name == power_agent->GetTracingAgentName()) {
+ additional_tracing_agents_.push_back(power_agent);
+ return;
+ }
+#endif
+
+ DCHECK(agent_name == kChromeTracingAgentName);
+}
+
+void TracingControllerImpl::OnStartAgentTracingAcked(
+ const std::string& agent_name,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Don't taken any further action if the ack came after the deadline.
+ if (!start_tracing_timer_.IsRunning())
+ return;
+
+ if (success)
+ AddTracingAgent(agent_name);
+
+ if (--pending_start_tracing_ack_count_ == 0) {
+ start_tracing_timer_.Stop();
+ OnAllTracingAgentsStarted();
+ }
+}
+
void TracingControllerImpl::OnStopTracingAcked(
TraceMessageFilter* trace_message_filter,
const std::vector<std::string>& known_category_groups) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnStopTracingAcked,
- base::Unretained(this),
- make_scoped_refptr(trace_message_filter),
- known_category_groups));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ &TracingControllerImpl::OnStopTracingAcked, base::Unretained(this),
+ base::RetainedRef(trace_message_filter), known_category_groups));
return;
}
@@ -700,7 +686,8 @@ void TracingControllerImpl::OnEndAgentTracingAcked(
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (trace_data_sink_.get()) {
+ if (trace_data_sink_.get() && events_str_ptr &&
+ !events_str_ptr->data().empty()) {
std::string json_string;
if (agent_name == kETWTracingAgentName) {
// The Windows kernel events are kept into a JSON format stored as string
@@ -715,44 +702,6 @@ void TracingControllerImpl::OnEndAgentTracingAcked(
OnStopTracingAcked(NULL, category_groups);
}
-void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
- TraceMessageFilter* trace_message_filter) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
- base::Unretained(this),
- make_scoped_refptr(trace_message_filter)));
- return;
- }
-
- if (pending_capture_monitoring_snapshot_ack_count_ == 0)
- return;
-
- if (trace_message_filter &&
- !pending_capture_monitoring_filters_.erase(trace_message_filter)) {
- // The response from the specified message filter has already been received.
- return;
- }
-
- if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
- // All acks from subprocesses have been received. Now flush the local trace.
- // During or after this call, our OnLocalMonitoringTraceDataCollected
- // will be called with the last of the local trace data.
- TraceLog::GetInstance()->FlushButLeaveBufferIntact(
- base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
- base::Unretained(this)));
- return;
- }
-
- if (pending_capture_monitoring_snapshot_ack_count_ != 0)
- return;
-
- if (monitoring_data_sink_.get()) {
- monitoring_data_sink_->Close();
- monitoring_data_sink_ = NULL;
- }
-}
-
void TracingControllerImpl::OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
// OnTraceDataCollected may be called from any browser thread, either by the
@@ -768,19 +717,6 @@ void TracingControllerImpl::OnTraceDataCollected(
trace_data_sink_->AddTraceChunk(events_str_ptr->data());
}
-void TracingControllerImpl::OnMonitoringTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
- base::Unretained(this), events_str_ptr));
- return;
- }
-
- if (monitoring_data_sink_.get())
- monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
-}
-
void TracingControllerImpl::OnLocalTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events) {
@@ -796,19 +732,6 @@ void TracingControllerImpl::OnLocalTraceDataCollected(
OnStopTracingAcked(NULL, category_groups);
}
-void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr,
- bool has_more_events) {
- if (events_str_ptr->data().size())
- OnMonitoringTraceDataCollected(events_str_ptr);
-
- if (has_more_events)
- return;
-
- // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
- OnCaptureMonitoringSnapshotAcked(NULL);
-}
-
void TracingControllerImpl::OnTraceLogStatusReply(
TraceMessageFilter* trace_message_filter,
const base::trace_event::TraceLogStatus& status) {
@@ -817,7 +740,7 @@ void TracingControllerImpl::OnTraceLogStatusReply(
BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnTraceLogStatusReply,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter), status));
+ base::RetainedRef(trace_message_filter), status));
return;
}
@@ -875,29 +798,25 @@ std::string TracingControllerImpl::GetTraceEventLabel() {
return kChromeTraceLabel;
}
-bool TracingControllerImpl::StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) {
+void TracingControllerImpl::StartAgentTracing(
+ const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- base::Closure on_start_tracing_done_callback =
- base::Bind(&TracingControllerImpl::OnStartAgentTracingDone,
- base::Unretained(this),
- trace_config, start_tracing_done_callback_);
+ base::Closure on_agent_started =
+ base::Bind(callback, kChromeTracingAgentName, true);
if (!BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&TracingControllerImpl::SetEnabledOnFileThread,
base::Unretained(this), trace_config,
base::trace_event::TraceLog::RECORDING_MODE,
- on_start_tracing_done_callback))) {
+ on_agent_started))) {
// BrowserThread::PostTask fails if the threads haven't been created yet,
// so it should be safe to just use TraceLog::SetEnabled directly.
base::trace_event::TraceLog::GetInstance()->SetEnabled(
trace_config, base::trace_event::TraceLog::RECORDING_MODE);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- on_start_tracing_done_callback);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, on_agent_started);
}
-
- return true;
}
void TracingControllerImpl::StopAgentTracing(
@@ -935,19 +854,13 @@ bool TracingControllerImpl::SupportsExplicitClockSync() {
}
void TracingControllerImpl::RecordClockSyncMarker(
- int sync_id,
+ const std::string& sync_id,
const RecordClockSyncMarkerCallback& callback) {
DCHECK(SupportsExplicitClockSync());
TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id);
}
-int TracingControllerImpl::GetUniqueClockSyncID() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // There is no need to lock because this function only runs on UI thread.
- return ++clock_sync_id_;
-}
-
void TracingControllerImpl::IssueClockSyncMarker() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(pending_clock_sync_ack_count_ == 0);
@@ -955,7 +868,7 @@ void TracingControllerImpl::IssueClockSyncMarker() {
for (const auto& it : additional_tracing_agents_) {
if (it->SupportsExplicitClockSync()) {
it->RecordClockSyncMarker(
- GetUniqueClockSyncID(),
+ base::GenerateGUID(),
base::Bind(&TracingControllerImpl::OnClockSyncMarkerRecordedByAgent,
base::Unretained(this)));
pending_clock_sync_ack_count_++;
@@ -968,20 +881,22 @@ void TracingControllerImpl::IssueClockSyncMarker() {
StopTracingAfterClockSync();
} else {
clock_sync_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromSeconds(kIssueClockSyncTimeout),
- this,
- &TracingControllerImpl::StopTracingAfterClockSync);
+ FROM_HERE, base::TimeDelta::FromSeconds(kIssueClockSyncTimeoutSeconds),
+ this, &TracingControllerImpl::StopTracingAfterClockSync);
}
}
void TracingControllerImpl::OnClockSyncMarkerRecordedByAgent(
- int sync_id,
+ const std::string& sync_id,
const base::TimeTicks& issue_ts,
const base::TimeTicks& issue_end_ts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts);
+ // TODO(charliea): Change this function so that it can accept a boolean
+ // success indicator instead of having to rely on sentinel issue_ts and
+ // issue_end_ts values to signal failure.
+ if (!(issue_ts == base::TimeTicks() || issue_end_ts == base::TimeTicks()))
+ TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts);
// Timer is not running means that clock sync already timed out.
if (!clock_sync_timer_.IsRunning())
@@ -1066,7 +981,7 @@ void TracingControllerImpl::OnProcessMemoryDumpResponse(
BrowserThread::UI, FROM_HERE,
base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
base::Unretained(this),
- make_scoped_refptr(trace_message_filter), dump_guid,
+ base::RetainedRef(trace_message_filter), dump_guid,
success));
return;
}
@@ -1116,17 +1031,4 @@ void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
pending_memory_dump_guid_ = 0;
}
-void TracingControllerImpl::OnMonitoringStateChanged(bool is_monitoring) {
- if (is_monitoring_ == is_monitoring)
- return;
-
- is_monitoring_ = is_monitoring;
-#if !defined(OS_ANDROID)
- for (std::set<TracingUI*>::iterator it = tracing_uis_.begin();
- it != tracing_uis_.end(); it++) {
- (*it)->OnMonitoringStateChanged(is_monitoring);
- }
-#endif
-}
-
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.h b/chromium/content/browser/tracing/tracing_controller_impl.h
index 90dcc408076..7a6c17b2b79 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.h
+++ b/chromium/content/browser/tracing/tracing_controller_impl.h
@@ -41,16 +41,6 @@ class TracingControllerImpl
bool StartTracing(const base::trace_event::TraceConfig& trace_config,
const StartTracingDoneCallback& callback) override;
bool StopTracing(const scoped_refptr<TraceDataSink>& sink) override;
- bool StartMonitoring(
- const base::trace_event::TraceConfig& trace_config,
- const StartMonitoringDoneCallback& callback) override;
- bool StopMonitoring(
- const StopMonitoringDoneCallback& callback) override;
- void GetMonitoringStatus(
- bool* out_enabled,
- base::trace_event::TraceConfig* out_trace_config) override;
- bool CaptureMonitoringSnapshot(
- const scoped_refptr<TraceDataSink>& sink) override;
bool GetTraceBufferUsage(
const GetTraceBufferUsageCallback& callback) override;
bool SetWatchEvent(const std::string& category_name,
@@ -65,12 +55,12 @@ class TracingControllerImpl
// base::trace_event::TracingAgent implementation.
std::string GetTracingAgentName() override;
std::string GetTraceEventLabel() override;
- bool StartAgentTracing(
- const base::trace_event::TraceConfig& trace_config) override;
+ void StartAgentTracing(const base::trace_event::TraceConfig& trace_config,
+ const StartAgentTracingCallback& callback) override;
void StopAgentTracing(const StopAgentTracingCallback& callback) override;
bool SupportsExplicitClockSync() override;
void RecordClockSyncMarker(
- int sync_id,
+ const std::string& sync_id,
const RecordClockSyncMarkerCallback& callback) override;
// base::trace_event::MemoryDumpManagerDelegate implementation.
@@ -124,17 +114,17 @@ class TracingControllerImpl
void OnTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr);
- void OnMonitoringTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr);
// Callback of TraceLog::Flush() for the local trace.
void OnLocalTraceDataCollected(
const scoped_refptr<base::RefCountedString>& events_str_ptr,
bool has_more_events);
- // Callback of TraceLog::FlushMonitoring() for the local trace.
- void OnLocalMonitoringTraceDataCollected(
- const scoped_refptr<base::RefCountedString>& events_str_ptr,
- bool has_more_events);
+
+ // Adds the tracing agent with the specified agent name to the list of
+ // additional tracing agents.
+ void AddTracingAgent(const std::string& agent_name);
+
+ void OnStartAgentTracingAcked(const std::string& agent_name, bool success);
void OnStopTracingAcked(
TraceMessageFilter* trace_message_filter,
@@ -145,9 +135,6 @@ class TracingControllerImpl
const std::string& events_label,
const scoped_refptr<base::RefCountedString>& events_str_ptr);
- void OnCaptureMonitoringSnapshotAcked(
- TraceMessageFilter* trace_message_filter);
-
void OnTraceLogStatusReply(TraceMessageFilter* trace_message_filter,
const base::trace_event::TraceLogStatus& status);
void OnProcessMemoryDumpResponse(TraceMessageFilter* trace_message_filter,
@@ -166,37 +153,30 @@ class TracingControllerImpl
int mode,
const base::Closure& callback);
void SetDisabledOnFileThread(const base::Closure& callback);
- void OnStartAgentTracingDone(
- const base::trace_event::TraceConfig& trace_config,
- const StartTracingDoneCallback& callback);
+ void OnAllTracingAgentsStarted();
void StopTracingAfterClockSync();
void OnStopTracingDone();
- void OnStartMonitoringDone(
- const base::trace_event::TraceConfig& trace_config,
- const StartMonitoringDoneCallback& callback);
- void OnStopMonitoringDone(const StopMonitoringDoneCallback& callback);
- void OnMonitoringStateChanged(bool is_monitoring);
-
- int GetUniqueClockSyncID();
// Issue clock sync markers to the tracing agents.
void IssueClockSyncMarker();
void OnClockSyncMarkerRecordedByAgent(
- int sync_id,
+ const std::string& sync_id,
const base::TimeTicks& issue_ts,
const base::TimeTicks& issue_end_ts);
typedef std::set<scoped_refptr<TraceMessageFilter>> TraceMessageFilterSet;
TraceMessageFilterSet trace_message_filters_;
+ // Pending acks for StartTracing.
+ int pending_start_tracing_ack_count_;
+ base::OneShotTimer start_tracing_timer_;
+ StartTracingDoneCallback start_tracing_done_callback_;
+ scoped_ptr<base::trace_event::TraceConfig> start_tracing_trace_config_;
+
// Pending acks for StopTracing.
int pending_stop_tracing_ack_count_;
TraceMessageFilterSet pending_stop_tracing_filters_;
- // Pending acks for CaptureMonitoringSnapshot.
- int pending_capture_monitoring_snapshot_ack_count_;
- TraceMessageFilterSet pending_capture_monitoring_filters_;
-
// Pending acks for GetTraceLogStatus.
int pending_trace_log_status_ack_count_;
TraceMessageFilterSet pending_trace_log_status_filters_;
@@ -210,7 +190,6 @@ class TracingControllerImpl
uint64_t pending_memory_dump_guid_;
base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
- StartTracingDoneCallback start_tracing_done_callback_;
std::vector<base::trace_event::TracingAgent*> additional_tracing_agents_;
int clock_sync_id_;
int pending_clock_sync_ack_count_;
diff --git a/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc b/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc
index 025619f2024..1ee6327893a 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl_data_sinks.cc
@@ -34,9 +34,10 @@ class StringTraceDataEndpoint : public TracingController::TraceDataEndpoint {
scoped_refptr<base::RefCountedString> str =
base::RefCountedString::TakeString(&tmp);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(completion_callback_,
- base::Passed(std::move(metadata)), str));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(completion_callback_, base::Passed(std::move(metadata)),
+ base::RetainedRef(str)));
}
private:
diff --git a/chromium/content/browser/tracing/tracing_ui.cc b/chromium/content/browser/tracing/tracing_ui.cc
index 13eaa402036..074a771a1a8 100644
--- a/chromium/content/browser/tracing/tracing_ui.cc
+++ b/chromium/content/browser/tracing/tracing_ui.cc
@@ -145,55 +145,6 @@ void OnTraceBufferStatusResult(const WebUIDataSource::GotDataCallback& callback,
callback.Run(status_base64);
}
-void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
-
-bool StartMonitoring(const std::string& data64,
- const WebUIDataSource::GotDataCallback& callback) {
- base::trace_event::TraceConfig trace_config("", "");
- if (!GetTracingOptions(data64, &trace_config))
- return false;
-
- return TracingController::GetInstance()->StartMonitoring(
- trace_config,
- base::Bind(OnMonitoringEnabledAck, callback));
-}
-
-void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback) {
- base::RefCountedString* res = new base::RefCountedString();
- callback.Run(res);
-}
-
-void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
- base::RefCountedString* res = new base::RefCountedString();
- callback.Run(res);
-}
-
-void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
- bool is_monitoring;
- base::trace_event::TraceConfig config("", "");
- TracingController::GetInstance()->GetMonitoringStatus(
- &is_monitoring, &config);
-
- base::DictionaryValue monitoring_options;
- monitoring_options.SetBoolean("isMonitoring", is_monitoring);
- monitoring_options.SetString("categoryFilter",
- config.ToCategoryFilterString());
- monitoring_options.SetBoolean("useSystemTracing", config.IsSystraceEnabled());
- monitoring_options.SetBoolean(
- "useContinuousTracing",
- config.GetTraceRecordMode() == base::trace_event::RECORD_CONTINUOUSLY);
- monitoring_options.SetBoolean("useSampling", config.IsSamplingEnabled());
-
- std::string monitoring_options_json;
- base::JSONWriter::Write(monitoring_options, &monitoring_options_json);
-
- base::RefCountedString* monitoring_options_base64 =
- new base::RefCountedString();
- base::Base64Encode(monitoring_options_json,
- &monitoring_options_base64->data());
- callback.Run(monitoring_options_base64);
-}
-
void TracingCallbackWrapperBase64(
const WebUIDataSource::GotDataCallback& callback,
scoped_ptr<const base::DictionaryValue> metadata,
@@ -241,29 +192,6 @@ bool OnBeginJSONRequest(const std::string& path,
return TracingController::GetInstance()->StopTracing(data_sink);
}
- const char* StartMonitoringPath = "json/begin_monitoring?";
- if (path.find(StartMonitoringPath) == 0) {
- std::string data = path.substr(strlen(StartMonitoringPath));
- return StartMonitoring(data, callback);
- }
- if (path == "json/end_monitoring") {
- return TracingController::GetInstance()->StopMonitoring(
- base::Bind(OnMonitoringDisabled, callback));
- }
- if (path == "json/capture_monitoring_compressed") {
- scoped_refptr<TracingControllerImpl::TraceDataSink> data_sink =
- TracingController::CreateCompressedStringSink(
- TracingController::CreateCallbackEndpoint(
- base::Bind(TracingCallbackWrapperBase64, callback)));
- AddCustomMetadata(data_sink.get());
- TracingController::GetInstance()->CaptureMonitoringSnapshot(data_sink);
- return true;
- }
- if (path == "json/get_monitoring_status") {
- GetMonitoringStatus(callback);
- return true;
- }
-
LOG(ERROR) << "Unhandled request to " << path;
return false;
}
@@ -317,11 +245,6 @@ TracingUI::~TracingUI() {
TracingControllerImpl::GetInstance()->UnregisterTracingUI(this);
}
-void TracingUI::OnMonitoringStateChanged(bool is_monitoring) {
- web_ui()->CallJavascriptFunction(
- "onMonitoringStateChanged", base::FundamentalValue(is_monitoring));
-}
-
void TracingUI::DoUploadBase64Encoded(const base::ListValue* args) {
std::string file_contents_base64;
if (!args || args->empty() || !args->GetString(0, &file_contents_base64)) {
diff --git a/chromium/content/browser/tracing/tracing_ui.h b/chromium/content/browser/tracing/tracing_ui.h
index 22e8616cab5..4e65de11a7a 100644
--- a/chromium/content/browser/tracing/tracing_ui.h
+++ b/chromium/content/browser/tracing/tracing_ui.h
@@ -24,7 +24,6 @@ class CONTENT_EXPORT TracingUI : public WebUIController {
public:
explicit TracingUI(WebUI* web_ui);
~TracingUI() override;
- void OnMonitoringStateChanged(bool is_monitoring);
void OnTraceUploadProgress(int64_t current, int64_t total);
void OnTraceUploadComplete(bool success, const std::string& feedback);
diff --git a/chromium/content/browser/udev_linux.cc b/chromium/content/browser/udev_linux.cc
deleted file mode 100644
index 1890523d714..00000000000
--- a/chromium/content/browser/udev_linux.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/udev_linux.h"
-
-#include <stddef.h>
-
-#include "base/message_loop/message_loop.h"
-
-namespace content {
-
-UdevLinux::UdevLinux(const std::vector<UdevMonitorFilter>& filters,
- const UdevNotificationCallback& callback)
- : udev_(device::udev_new()),
- monitor_(device::udev_monitor_new_from_netlink(udev_.get(), "udev")),
- monitor_fd_(-1),
- callback_(callback) {
- CHECK(udev_);
- CHECK(monitor_);
-
- for (size_t i = 0; i < filters.size(); ++i) {
- int ret = device::udev_monitor_filter_add_match_subsystem_devtype(
- monitor_.get(), filters[i].subsystem, filters[i].devtype);
- CHECK_EQ(0, ret);
- }
-
- int ret = device::udev_monitor_enable_receiving(monitor_.get());
- CHECK_EQ(0, ret);
- monitor_fd_ = device::udev_monitor_get_fd(monitor_.get());
- CHECK_GE(monitor_fd_, 0);
-
- bool success = base::MessageLoopForIO::current()->WatchFileDescriptor(
- monitor_fd_,
- true,
- base::MessageLoopForIO::WATCH_READ,
- &monitor_watcher_,
- this);
- CHECK(success);
-}
-
-UdevLinux::~UdevLinux() {
- monitor_watcher_.StopWatchingFileDescriptor();
-}
-
-udev* UdevLinux::udev_handle() {
- return udev_.get();
-}
-
-void UdevLinux::OnFileCanReadWithoutBlocking(int fd) {
- // Events occur when devices attached to the system are added, removed, or
- // change state. udev_monitor_receive_device() will return a device object
- // representing the device which changed and what type of change occured.
- DCHECK_EQ(monitor_fd_, fd);
- device::ScopedUdevDevicePtr dev(
- device::udev_monitor_receive_device(monitor_.get()));
- if (!dev)
- return;
-
- callback_.Run(dev.get());
-}
-
-void UdevLinux::OnFileCanWriteWithoutBlocking(int fd) {
-}
-
-} // namespace content
diff --git a/chromium/content/browser/udev_linux.h b/chromium/content/browser/udev_linux.h
deleted file mode 100644
index 3e4ac44a778..00000000000
--- a/chromium/content/browser/udev_linux.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// UdevLinux listens for device change notifications from udev and runs
-// callbacks when notifications occur.
-//
-// UdevLinux must be created on a MessageLoop of TYPE_IO.
-// UdevLinux is not thread-safe.
-//
-// Example usage:
-//
-// class UdevLinux;
-//
-// class Foo {
-// public:
-// Foo() {
-// std::vector<UdevLinux::UdevMonitorFilter> filters;
-// filters.push_back(content::UdevLinux::UdevMonitorFilter("block", NULL));
-// udev_.reset(new UdevLinux(filters,
-// base::Bind(&Foo::Notify, this)));
-// }
-//
-// // Called when a "block" device attaches/detaches.
-// // To hold on to |device|, call udev_device_ref(device).
-// void Notify(udev_device* device) {
-// // Do something with |device|.
-// }
-//
-// private:
-// scoped_ptr<UdevLinux> udev_;
-//
-// DISALLOW_COPY_AND_ASSIGN(Foo);
-// };
-
-#ifndef CONTENT_BROWSER_UDEV_LINUX_H_
-#define CONTENT_BROWSER_UDEV_LINUX_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/message_loop/message_pump_libevent.h"
-#include "device/udev_linux/scoped_udev.h"
-
-extern "C" {
-struct udev;
-struct udev_device;
-struct udev_monitor;
-}
-
-namespace content {
-
-class UdevLinux : public base::MessagePumpLibevent::Watcher {
- public:
- typedef base::Callback<void(udev_device*)> UdevNotificationCallback;
-
- // subsystem and devtype parameter for
- // udev_monitor_filter_add_match_subsystem_devtype().
- struct UdevMonitorFilter {
- UdevMonitorFilter(const char* subsystem_in, const char* devtype_in)
- : subsystem(subsystem_in),
- devtype(devtype_in) {
- }
- const char* subsystem;
- const char* devtype;
- };
-
- // Filter incoming devices based on |filters|.
- // Calls |callback| upon device change events.
- UdevLinux(const std::vector<UdevMonitorFilter>& filters,
- const UdevNotificationCallback& callback);
- ~UdevLinux() override;
-
- // Returns the udev handle to be passed into other udev_*() functions.
- udev* udev_handle();
-
- private:
- // base::MessagePump:Libevent::Watcher implementation.
- void OnFileCanReadWithoutBlocking(int fd) override;
- void OnFileCanWriteWithoutBlocking(int fd) override;
-
- // libudev-related items, the main context, and the monitoring context to be
- // notified about changes to device states.
- device::ScopedUdevPtr udev_;
- device::ScopedUdevMonitorPtr monitor_;
- int monitor_fd_;
- base::MessagePumpLibevent::FileDescriptorWatcher monitor_watcher_;
- UdevNotificationCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(UdevLinux);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_UDEV_LINUX_H_
diff --git a/chromium/content/browser/utility_process_host_impl.cc b/chromium/content/browser/utility_process_host_impl.cc
index 42c31bd9b2a..0ad33097570 100644
--- a/chromium/content/browser/utility_process_host_impl.cc
+++ b/chromium/content/browser/utility_process_host_impl.cc
@@ -37,6 +37,10 @@
#include "ipc/ipc_switches.h"
#include "ui/base/ui_base_switches.h"
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+#include "content/public/browser/zygote_handle_linux.h"
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
#if defined(OS_WIN)
#include "sandbox/win/src/sandbox_policy.h"
#include "sandbox/win/src/sandbox_types.h"
@@ -44,6 +48,12 @@
namespace content {
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+namespace {
+ZygoteHandle g_utility_zygote;
+} // namespace
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
// NOTE: changes to this class need to be reviewed by the security team.
class UtilitySandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
@@ -58,7 +68,9 @@ class UtilitySandboxedProcessLauncherDelegate
launch_elevated_(launch_elevated)
#elif defined(OS_POSIX)
env_(env),
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
no_sandbox_(no_sandbox),
+#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
ipc_fd_(host->TakeClientFileDescriptor())
#endif // OS_WIN
{}
@@ -88,9 +100,13 @@ class UtilitySandboxedProcessLauncherDelegate
#elif defined(OS_POSIX)
- bool ShouldUseZygote() override {
- return !no_sandbox_ && exposed_dir_.empty();
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+ ZygoteHandle* GetZygote() override {
+ if (no_sandbox_ || !exposed_dir_.empty())
+ return nullptr;
+ return GetGenericZygote();
}
+#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
base::EnvironmentMap GetEnvironment() override { return env_; }
base::ScopedFD TakeIpcFd() override { return std::move(ipc_fd_); }
#endif // OS_WIN
@@ -106,7 +122,9 @@ class UtilitySandboxedProcessLauncherDelegate
bool launch_elevated_;
#elif defined(OS_POSIX)
base::EnvironmentMap env_;
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
bool no_sandbox_;
+#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
base::ScopedFD ipc_fd_;
#endif // OS_WIN
};
@@ -139,6 +157,7 @@ UtilityProcessHostImpl::UtilityProcessHostImpl(
#endif
started_(false),
name_(base::ASCIIToUTF16("utility process")),
+ mojo_application_host_(new MojoApplicationHost),
weak_ptr_factory_(this) {
}
@@ -199,27 +218,27 @@ void UtilityProcessHostImpl::SetEnv(const base::EnvironmentMap& env) {
#endif // OS_POSIX
-bool UtilityProcessHostImpl::StartMojoMode() {
- CHECK(!mojo_application_host_);
- mojo_application_host_.reset(new MojoApplicationHost);
-
- bool mojo_result = mojo_application_host_->Init();
- if (!mojo_result)
- return false;
-
+bool UtilityProcessHostImpl::Start() {
return StartProcess();
}
ServiceRegistry* UtilityProcessHostImpl::GetServiceRegistry() {
- if (mojo_application_host_)
- return mojo_application_host_->service_registry();
- return nullptr;
+ DCHECK(mojo_application_host_);
+ return mojo_application_host_->service_registry();
}
void UtilityProcessHostImpl::SetName(const base::string16& name) {
name_ = name;
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+// static
+void UtilityProcessHostImpl::EarlyZygoteLaunch() {
+ DCHECK(!g_utility_zygote);
+ g_utility_zygote = CreateZygote();
+}
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
bool UtilityProcessHostImpl::StartProcess() {
if (started_)
return true;
@@ -228,6 +247,10 @@ bool UtilityProcessHostImpl::StartProcess() {
if (is_batch_mode_)
return true;
+ bool mojo_result = mojo_application_host_->Init();
+ if (!mojo_result)
+ return false;
+
// Name must be set or metrics_service will crash in any test which
// launches a UtilityProcessHost.
process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_UTILITY, this));
@@ -296,7 +319,6 @@ bool UtilityProcessHostImpl::StartProcess() {
// Browser command-line switches to propagate to the utility process.
static const char* const kSwitchNames[] = {
- switches::kDebugPluginLoading,
switches::kNoSandbox,
switches::kProfilerTiming,
#if defined(OS_MACOSX)
@@ -371,15 +393,14 @@ void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) {
}
void UtilityProcessHostImpl::OnProcessLaunched() {
- if (mojo_application_host_) {
- base::ProcessHandle handle;
- if (RenderProcessHost::run_renderer_in_process())
- handle = base::GetCurrentProcessHandle();
- else
- handle = process_->GetData().handle;
-
- mojo_application_host_->Activate(this, handle);
- }
+ DCHECK(mojo_application_host_);
+ base::ProcessHandle handle;
+ if (RenderProcessHost::run_renderer_in_process())
+ handle = base::GetCurrentProcessHandle();
+ else
+ handle = process_->GetData().handle;
+
+ mojo_application_host_->Activate(this, handle);
}
} // namespace content
diff --git a/chromium/content/browser/utility_process_host_impl.h b/chromium/content/browser/utility_process_host_impl.h
index 94aafa7c517..25974950208 100644
--- a/chromium/content/browser/utility_process_host_impl.h
+++ b/chromium/content/browser/utility_process_host_impl.h
@@ -57,12 +57,17 @@ class CONTENT_EXPORT UtilityProcessHostImpl
#if defined(OS_POSIX)
void SetEnv(const base::EnvironmentMap& env) override;
#endif
- bool StartMojoMode() override;
+ bool Start() override;
ServiceRegistry* GetServiceRegistry() override;
void SetName(const base::string16& name) override;
void set_child_flags(int flags) { child_flags_ = flags; }
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+ // Launch the zygote early in the browser startup.
+ static void EarlyZygoteLaunch();
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
private:
// Starts a process if necessary. Returns true if it succeeded or a process
// has already been started via StartBatchMode().
diff --git a/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.cc b/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.cc
index 9d9aca7c632..d42d2b9d81c 100644
--- a/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.cc
+++ b/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.cc
@@ -40,9 +40,9 @@ CardboardVRDevice::~CardboardVRDevice() {
j_cardboard_device_.obj());
}
-VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
+mojom::VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
TRACE_EVENT0("input", "CardboardVRDevice::GetVRDevice");
- VRDeviceInfoPtr device = VRDeviceInfo::New();
+ mojom::VRDeviceInfoPtr device = mojom::VRDeviceInfo::New();
JNIEnv* env = AttachCurrentThread();
@@ -58,15 +58,15 @@ VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
std::vector<float> fov;
base::android::JavaFloatArrayToFloatVector(env, j_fov.obj(), &fov);
- device->hmdInfo = VRHMDInfo::New();
- VRHMDInfoPtr& hmdInfo = device->hmdInfo;
+ device->hmdInfo = mojom::VRHMDInfo::New();
+ mojom::VRHMDInfoPtr& hmdInfo = device->hmdInfo;
- hmdInfo->leftEye = VREyeParameters::New();
- hmdInfo->rightEye = VREyeParameters::New();
- VREyeParametersPtr& left_eye = hmdInfo->leftEye;
- VREyeParametersPtr& right_eye = hmdInfo->rightEye;
+ hmdInfo->leftEye = mojom::VREyeParameters::New();
+ hmdInfo->rightEye = mojom::VREyeParameters::New();
+ mojom::VREyeParametersPtr& left_eye = hmdInfo->leftEye;
+ mojom::VREyeParametersPtr& right_eye = hmdInfo->rightEye;
- left_eye->recommendedFieldOfView = VRFieldOfView::New();
+ left_eye->recommendedFieldOfView = mojom::VRFieldOfView::New();
left_eye->recommendedFieldOfView->upDegrees = fov[0];
left_eye->recommendedFieldOfView->downDegrees = fov[1];
left_eye->recommendedFieldOfView->leftDegrees = fov[2];
@@ -74,7 +74,7 @@ VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
// Cardboard devices always assume a mirrored FOV, so this is just the left
// eye FOV with the left and right degrees swapped.
- right_eye->recommendedFieldOfView = VRFieldOfView::New();
+ right_eye->recommendedFieldOfView = mojom::VRFieldOfView::New();
right_eye->recommendedFieldOfView->upDegrees = fov[0];
right_eye->recommendedFieldOfView->downDegrees = fov[1];
right_eye->recommendedFieldOfView->leftDegrees = fov[3];
@@ -88,12 +88,12 @@ VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
float ipd = Java_CardboardVRDevice_getIpd(env, j_cardboard_device_.obj());
- left_eye->eyeTranslation = VRVector3::New();
+ left_eye->eyeTranslation = mojom::VRVector3::New();
left_eye->eyeTranslation->x = ipd * -0.5f;
left_eye->eyeTranslation->y = 0.0f;
left_eye->eyeTranslation->z = 0.0f;
- right_eye->eyeTranslation = VRVector3::New();
+ right_eye->eyeTranslation = mojom::VRVector3::New();
right_eye->eyeTranslation->x = ipd * 0.5f;
right_eye->eyeTranslation->y = 0.0f;
right_eye->eyeTranslation->z = 0.0f;
@@ -106,13 +106,13 @@ VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
base::android::JavaIntArrayToIntVector(env, j_screen_size.obj(),
&screen_size);
- left_eye->renderRect = VRRect::New();
+ left_eye->renderRect = mojom::VRRect::New();
left_eye->renderRect->x = 0;
left_eye->renderRect->y = 0;
left_eye->renderRect->width = screen_size[0] / 2.0;
left_eye->renderRect->height = screen_size[1];
- right_eye->renderRect = VRRect::New();
+ right_eye->renderRect = mojom::VRRect::New();
right_eye->renderRect->x = screen_size[0] / 2.0;
right_eye->renderRect->y = 0;
right_eye->renderRect->width = screen_size[0] / 2.0;
@@ -121,9 +121,9 @@ VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() {
return device;
}
-VRSensorStatePtr CardboardVRDevice::GetSensorState() {
+mojom::VRSensorStatePtr CardboardVRDevice::GetSensorState() {
TRACE_EVENT0("input", "CardboardVRDevice::GetSensorState");
- VRSensorStatePtr state = VRSensorState::New();
+ mojom::VRSensorStatePtr state = mojom::VRSensorState::New();
state->timestamp = base::Time::Now().ToJsTime();
state->frameIndex = frame_index_++;
@@ -145,13 +145,13 @@ VRSensorStatePtr CardboardVRDevice::GetSensorState() {
gfx::DecomposedTransform decomposed_transform;
gfx::DecomposeTransform(&decomposed_transform, transform);
- state->orientation = VRVector4::New();
+ state->orientation = mojom::VRVector4::New();
state->orientation->x = decomposed_transform.quaternion[0];
state->orientation->y = decomposed_transform.quaternion[1];
state->orientation->z = decomposed_transform.quaternion[2];
state->orientation->w = decomposed_transform.quaternion[3];
- state->position = VRVector3::New();
+ state->position = mojom::VRVector3::New();
state->position->x = decomposed_transform.translate[0];
state->position->y = decomposed_transform.translate[1];
state->position->z = decomposed_transform.translate[2];
diff --git a/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.h b/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.h
index 66f82876ab1..2708c6ad47c 100644
--- a/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.h
+++ b/chromium/content/browser/vr/android/cardboard/cardboard_vr_device.h
@@ -20,8 +20,8 @@ class CardboardVRDevice : public VRDevice {
explicit CardboardVRDevice(VRDeviceProvider* provider);
~CardboardVRDevice() override;
- VRDeviceInfoPtr GetVRDevice() override;
- VRSensorStatePtr GetSensorState() override;
+ mojom::VRDeviceInfoPtr GetVRDevice() override;
+ mojom::VRSensorStatePtr GetSensorState() override;
void ResetSensor() override;
private:
diff --git a/chromium/content/browser/vr/vr_device.h b/chromium/content/browser/vr/vr_device.h
index e3026d73ef8..e3f181715eb 100644
--- a/chromium/content/browser/vr/vr_device.h
+++ b/chromium/content/browser/vr/vr_device.h
@@ -30,8 +30,8 @@ class VRDevice {
VRDeviceProvider* provider() const { return provider_; }
unsigned int id() const { return id_; }
- virtual VRDeviceInfoPtr GetVRDevice() = 0;
- virtual VRSensorStatePtr GetSensorState() = 0;
+ virtual mojom::VRDeviceInfoPtr GetVRDevice() = 0;
+ virtual mojom::VRSensorStatePtr GetSensorState() = 0;
virtual void ResetSensor() = 0;
private:
diff --git a/chromium/content/browser/vr/vr_device_manager.cc b/chromium/content/browser/vr/vr_device_manager.cc
index c99ee393009..181f48d07a7 100644
--- a/chromium/content/browser/vr/vr_device_manager.cc
+++ b/chromium/content/browser/vr/vr_device_manager.cc
@@ -45,7 +45,8 @@ VRDeviceManager::~VRDeviceManager() {
g_vr_device_manager = nullptr;
}
-void VRDeviceManager::BindRequest(mojo::InterfaceRequest<VRService> request) {
+void VRDeviceManager::BindRequest(
+ mojo::InterfaceRequest<mojom::VRService> request) {
VRDeviceManager* device_manager = GetInstance();
device_manager->bindings_.AddBinding(device_manager, std::move(request));
}
@@ -77,7 +78,7 @@ bool VRDeviceManager::HasInstance() {
return !!g_vr_device_manager;
}
-mojo::Array<VRDeviceInfoPtr> VRDeviceManager::GetVRDevices() {
+mojo::Array<mojom::VRDeviceInfoPtr> VRDeviceManager::GetVRDevices() {
DCHECK(thread_checker_.CalledOnValidThread());
InitializeProviders();
@@ -86,7 +87,7 @@ mojo::Array<VRDeviceInfoPtr> VRDeviceManager::GetVRDevices() {
for (const auto& provider : providers_)
provider->GetDevices(&devices);
- mojo::Array<VRDeviceInfoPtr> out_devices(0);
+ mojo::Array<mojom::VRDeviceInfoPtr> out_devices;
for (const auto& device : devices) {
if (device->id() == VR_DEVICE_LAST_ID)
continue;
@@ -94,7 +95,7 @@ mojo::Array<VRDeviceInfoPtr> VRDeviceManager::GetVRDevices() {
if (devices_.find(device->id()) == devices_.end())
devices_[device->id()] = device;
- VRDeviceInfoPtr vr_device_info = device->GetVRDevice();
+ mojom::VRDeviceInfoPtr vr_device_info = device->GetVRDevice();
if (vr_device_info.is_null())
continue;
diff --git a/chromium/content/browser/vr/vr_device_manager.h b/chromium/content/browser/vr/vr_device_manager.h
index 4eb39ea685e..f1dc81b081f 100644
--- a/chromium/content/browser/vr/vr_device_manager.h
+++ b/chromium/content/browser/vr/vr_device_manager.h
@@ -18,20 +18,20 @@
#include "content/browser/vr/vr_device_provider.h"
#include "content/common/content_export.h"
#include "content/common/vr_service.mojom.h"
-#include "mojo/common/weak_binding_set.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
namespace content {
-class VRDeviceManager : public VRService {
+class VRDeviceManager : public mojom::VRService {
public:
~VRDeviceManager() override;
- static void BindRequest(mojo::InterfaceRequest<VRService> request);
+ static void BindRequest(mojo::InterfaceRequest<mojom::VRService> request);
// Returns the VRDeviceManager singleton.
static VRDeviceManager* GetInstance();
- mojo::Array<VRDeviceInfoPtr> GetVRDevices();
+ mojo::Array<mojom::VRDeviceInfoPtr> GetVRDevices();
VRDevice* GetDevice(unsigned int index);
private:
@@ -47,7 +47,7 @@ class VRDeviceManager : public VRService {
void InitializeProviders();
void RegisterProvider(scoped_ptr<VRDeviceProvider> provider);
- // VRService implementation
+ // mojom::VRService implementation
void GetDevices(const GetDevicesCallback& callback) override;
void GetSensorState(uint32_t index,
const GetSensorStateCallback& callback) override;
@@ -65,7 +65,7 @@ class VRDeviceManager : public VRService {
bool vr_initialized_;
- mojo::WeakBindingSet<VRService> bindings_;
+ mojo::BindingSet<mojom::VRService> bindings_;
// For testing. If true will not delete self when consumer count reaches 0.
bool keep_alive_;
diff --git a/chromium/content/browser/vr/vr_device_manager_unittest.cc b/chromium/content/browser/vr/vr_device_manager_unittest.cc
index 001d4403e67..86f35ae1d65 100644
--- a/chromium/content/browser/vr/vr_device_manager_unittest.cc
+++ b/chromium/content/browser/vr/vr_device_manager_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
+
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
@@ -38,7 +40,7 @@ VRDeviceManagerTest::~VRDeviceManagerTest() {
void VRDeviceManagerTest::SetUp() {
scoped_ptr<FakeVRDeviceProvider> provider(new FakeVRDeviceProvider());
provider_ = provider.get();
- device_manager_.reset(new VRDeviceManager(provider.Pass()));
+ device_manager_.reset(new VRDeviceManager(std::move(provider)));
}
TEST_F(VRDeviceManagerTest, InitializationTest) {
@@ -46,15 +48,15 @@ TEST_F(VRDeviceManagerTest, InitializationTest) {
// Calling GetDevices should initialize the service if it hasn't been
// initialized yet or the providesr have been released.
- // The VRService should initialize each of it's providers upon it's own
+ // The mojom::VRService should initialize each of it's providers upon it's own
// initialization.
- mojo::Array<VRDeviceInfoPtr> webvr_devices;
+ mojo::Array<mojom::VRDeviceInfoPtr> webvr_devices;
webvr_devices = device_manager_->GetVRDevices();
EXPECT_TRUE(provider_->IsInitialized());
}
TEST_F(VRDeviceManagerTest, GetDevicesBasicTest) {
- mojo::Array<VRDeviceInfoPtr> webvr_devices;
+ mojo::Array<mojom::VRDeviceInfoPtr> webvr_devices;
webvr_devices = device_manager_->GetVRDevices();
// Calling GetVRDevices should initialize the providers.
EXPECT_TRUE(provider_->IsInitialized());
diff --git a/chromium/content/browser/wake_lock/wake_lock_browsertest.cc b/chromium/content/browser/wake_lock/wake_lock_browsertest.cc
index 3ac458973ce..59e3ab71e1c 100644
--- a/chromium/content/browser/wake_lock/wake_lock_browsertest.cc
+++ b/chromium/content/browser/wake_lock/wake_lock_browsertest.cc
@@ -73,10 +73,10 @@ class WakeLockTest : public ContentBrowserTest {
void WaitForPossibleUpdate() {
// As Mojo channels have no common FIFO order in respect to each other and
// to the Chromium IPC, we cannot assume that when screen.keepAwake state
- // is changed from within a script, WakeLockService will receive an update
- // request before ExecuteScript() returns. Therefore, some time slack is
- // needed to make sure that WakeLockService has received any possible update
- // requests before checking the resulting wake lock state.
+ // is changed from within a script, mojom::WakeLockService will receive an
+ // update request before ExecuteScript() returns. Therefore, some time slack
+ // is needed to make sure that mojom::WakeLockService has received any
+ // possible update requests before checking the resulting wake lock state.
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
RunAllPendingInMessageLoop();
}
diff --git a/chromium/content/browser/wake_lock/wake_lock_service_context.cc b/chromium/content/browser/wake_lock/wake_lock_service_context.cc
index a6da2103def..8b551660d80 100644
--- a/chromium/content/browser/wake_lock/wake_lock_service_context.cc
+++ b/chromium/content/browser/wake_lock/wake_lock_service_context.cc
@@ -25,7 +25,7 @@ WakeLockServiceContext::~WakeLockServiceContext() {}
void WakeLockServiceContext::CreateService(
int render_process_id,
int render_frame_id,
- mojo::InterfaceRequest<WakeLockService> request) {
+ mojo::InterfaceRequest<mojom::WakeLockService> request) {
new WakeLockServiceImpl(weak_factory_.GetWeakPtr(), render_process_id,
render_frame_id, std::move(request));
}
@@ -56,7 +56,7 @@ void WakeLockServiceContext::CancelWakeLock(int render_process_id,
}
bool WakeLockServiceContext::HasWakeLockForTests() const {
- return wake_lock_;
+ return !!wake_lock_;
}
void WakeLockServiceContext::CreateWakeLock() {
@@ -65,7 +65,7 @@ void WakeLockServiceContext::CreateWakeLock() {
PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
PowerSaveBlocker::kReasonOther, "Wake Lock API");
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
// On Android, additionaly associate the blocker with this WebContents.
DCHECK(web_contents());
diff --git a/chromium/content/browser/wake_lock/wake_lock_service_context.h b/chromium/content/browser/wake_lock/wake_lock_service_context.h
index f3114d73e94..73527dc2820 100644
--- a/chromium/content/browser/wake_lock/wake_lock_service_context.h
+++ b/chromium/content/browser/wake_lock/wake_lock_service_context.h
@@ -30,7 +30,7 @@ class CONTENT_EXPORT WakeLockServiceContext : public WebContentsObserver {
// Creates a WakeLockServiceImpl that is strongly bound to |request|.
void CreateService(int render_process_id,
int render_frame_id,
- mojo::InterfaceRequest<WakeLockService> request);
+ mojo::InterfaceRequest<mojom::WakeLockService> request);
// WebContentsObserver implementation.
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
diff --git a/chromium/content/browser/wake_lock/wake_lock_service_impl.cc b/chromium/content/browser/wake_lock/wake_lock_service_impl.cc
index 036cb1dec9a..61df4c478f2 100644
--- a/chromium/content/browser/wake_lock/wake_lock_service_impl.cc
+++ b/chromium/content/browser/wake_lock/wake_lock_service_impl.cc
@@ -14,7 +14,7 @@ WakeLockServiceImpl::WakeLockServiceImpl(
base::WeakPtr<WakeLockServiceContext> context,
int render_process_id,
int render_frame_id,
- mojo::InterfaceRequest<WakeLockService> request)
+ mojo::InterfaceRequest<mojom::WakeLockService> request)
: context_(context),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
diff --git a/chromium/content/browser/wake_lock/wake_lock_service_impl.h b/chromium/content/browser/wake_lock/wake_lock_service_impl.h
index 903f5057fa3..19b8fa55312 100644
--- a/chromium/content/browser/wake_lock/wake_lock_service_impl.h
+++ b/chromium/content/browser/wake_lock/wake_lock_service_impl.h
@@ -15,12 +15,12 @@ namespace content {
class WakeLockServiceContext;
-class WakeLockServiceImpl : public WakeLockService {
+class WakeLockServiceImpl : public mojom::WakeLockService {
public:
WakeLockServiceImpl(base::WeakPtr<WakeLockServiceContext> context,
int render_process_id,
int render_frame_id,
- mojo::InterfaceRequest<WakeLockService> request);
+ mojo::InterfaceRequest<mojom::WakeLockService> request);
~WakeLockServiceImpl() override;
// WakeLockSevice implementation.
@@ -31,7 +31,7 @@ class WakeLockServiceImpl : public WakeLockService {
base::WeakPtr<WakeLockServiceContext> context_;
const int render_process_id_;
const int render_frame_id_;
- mojo::StrongBinding<WakeLockService> binding_;
+ mojo::StrongBinding<mojom::WakeLockService> binding_;
DISALLOW_COPY_AND_ASSIGN(WakeLockServiceImpl);
};
diff --git a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
index 97dd750160c..93f166e2d20 100644
--- a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
+++ b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
@@ -38,13 +38,14 @@ class OverscrollTestWebContents : public TestWebContents {
static OverscrollTestWebContents* Create(
BrowserContext* browser_context,
- SiteInstance* instance,
+ scoped_refptr<SiteInstance> instance,
scoped_ptr<aura::Window> fake_native_view,
scoped_ptr<aura::Window> fake_contents_window) {
OverscrollTestWebContents* web_contents = new OverscrollTestWebContents(
browser_context, std::move(fake_native_view),
std::move(fake_contents_window));
- web_contents->Init(WebContents::CreateParams(browser_context, instance));
+ web_contents->Init(
+ WebContents::CreateParams(browser_context, std::move(instance)));
return web_contents;
}
@@ -112,7 +113,7 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
// offset -1 on layer_delegate_.
scoped_ptr<aura::Window> window(
GetOverlay()->CreateBackWindow(GetBackSlideWindowBounds()));
- bool window_created = window;
+ bool window_created = !!window;
// Performs BACK navigation, sets image from layer_delegate_ on
// image_delegate_.
GetOverlay()->OnOverscrollCompleting();
@@ -307,7 +308,6 @@ TEST_F(OverscrollNavigationOverlayTest, Navigation_LoadingUpdate) {
// this is a "safety net" in case we mis-identify the destination webpage
// (which can happen if a new navigation is performed while while a GestureNav
// navigation is in progress).
- contents()->TestSetIsLoading(true);
contents()->TestSetIsLoading(false);
EXPECT_FALSE(GetOverlay()->web_contents());
NavigationEntry* pending = contents()->GetController().GetPendingEntry();
diff --git a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
index 067a1472258..a4a1660be5b 100644
--- a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
+++ b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
@@ -42,14 +42,12 @@ void ShadowLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {
points[0].iset(0, 0);
points[1].iset(kShadowThick, 0);
- skia::RefPtr<SkShader> shader = skia::AdoptRef(
- SkGradientShader::CreateLinear(points, kShadowColors, NULL,
- arraysize(points), SkShader::kRepeat_TileMode));
-
gfx::Rect paint_rect = gfx::Rect(0, 0, kShadowThick,
layer_->bounds().height());
SkPaint paint;
- paint.setShader(shader.get());
+ paint.setShader(SkGradientShader::MakeLinear(points, kShadowColors, NULL,
+ arraysize(points),
+ SkShader::kRepeat_TileMode));
ui::PaintRecorder recorder(context, layer_->size());
recorder.canvas()->DrawRect(paint_rect, paint);
}
diff --git a/chromium/content/browser/web_contents/web_contents_android.cc b/chromium/content/browser/web_contents/web_contents_android.cc
index f772161f6ee..7a5e1f62d7a 100644
--- a/chromium/content/browser/web_contents/web_contents_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_android.cc
@@ -69,18 +69,9 @@ void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
}
struct AccessibilitySnapshotParams {
- AccessibilitySnapshotParams(float scale,
- float horizontal_scroll,
- float vertical_offset)
- : scale_factor(scale),
- x_scroll(horizontal_scroll),
- y_offset(vertical_offset),
- has_tree_data(false),
- should_select_leaf_nodes(false) {}
-
- float scale_factor;
- float x_scroll;
- float y_offset;
+ AccessibilitySnapshotParams()
+ : has_tree_data(false), should_select_leaf_nodes(false) {}
+
bool has_tree_data;
// The current text selection within this tree, if any, expressed as the
// node ID and character offset of the anchor (selection start) and focus
@@ -96,12 +87,12 @@ struct AccessibilitySnapshotParams {
ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(
JNIEnv* env,
BrowserAccessibilityAndroid* node,
+ const gfx::Rect& parent_rect,
AccessibilitySnapshotParams* params) {
ScopedJavaLocalRef<jstring> j_text =
ConvertUTF16ToJavaString(env, node->GetText());
ScopedJavaLocalRef<jstring> j_class =
ConvertUTF8ToJavaString(env, node->GetClassName());
- const gfx::Rect& location = node->GetLocalBoundsRect();
// The style attributes exists and valid if size attribute exists. Otherwise,
// they are not. Use a negative size information to indicate the existence
// of style information.
@@ -116,15 +107,18 @@ ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(
size = node->GetFloatAttribute(ui::AX_ATTR_FONT_SIZE);
text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
}
- float scale_factor = params->scale_factor;
+
+ const gfx::Rect& absolute_rect = node->GetLocalBoundsRect();
+ gfx::Rect parent_relative_rect = absolute_rect;
+ bool is_root = node->GetParent() == nullptr;
+ if (!is_root) {
+ parent_relative_rect.Offset(-parent_rect.OffsetFromOrigin());
+ }
ScopedJavaLocalRef<jobject> j_node =
Java_WebContentsImpl_createAccessibilitySnapshotNode(
- env, scale_factor * location.x() - params->x_scroll,
- scale_factor * location.y() + params->y_offset,
- scale_factor * node->GetScrollX(), scale_factor * node->GetScrollY(),
- scale_factor * location.width(), scale_factor * location.height(),
- j_text.obj(), color, bgcolor, scale_factor * size, text_style,
- j_class.obj());
+ env, parent_relative_rect.x(), parent_relative_rect.y(),
+ absolute_rect.width(), absolute_rect.height(), is_root, j_text.obj(),
+ color, bgcolor, size, text_style, j_class.obj());
if (params->has_tree_data && node->PlatformIsLeaf()) {
int start_selection = 0;
@@ -150,14 +144,14 @@ ScopedJavaLocalRef<jobject> WalkAXTreeDepthFirst(
static_cast<BrowserAccessibilityAndroid*>(
node->PlatformGetChild(i));
Java_WebContentsImpl_addAccessibilityNodeAsChild(
- env, j_node.obj(), WalkAXTreeDepthFirst(env, child, params).obj());
+ env, j_node.obj(),
+ WalkAXTreeDepthFirst(env, child, absolute_rect, params).obj());
}
return j_node;
}
// Walks over the AXTreeUpdate and creates a light weight snapshot.
void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
- AccessibilitySnapshotParams* params,
const ui::AXTreeUpdate& result) {
JNIEnv* env = base::android::AttachCurrentThread();
if (result.nodes.empty()) {
@@ -170,27 +164,21 @@ void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
manager->set_prune_tree_for_screen_reader(false);
BrowserAccessibilityAndroid* root =
static_cast<BrowserAccessibilityAndroid*>(manager->GetRoot());
+ AccessibilitySnapshotParams params;
if (result.has_tree_data) {
- params->has_tree_data = true;
- params->sel_anchor_object_id = result.tree_data.sel_anchor_object_id;
- params->sel_anchor_offset = result.tree_data.sel_anchor_offset;
- params->sel_focus_object_id = result.tree_data.sel_focus_object_id;
- params->sel_focus_offset = result.tree_data.sel_focus_offset;
+ params.has_tree_data = true;
+ params.sel_anchor_object_id = result.tree_data.sel_anchor_object_id;
+ params.sel_anchor_offset = result.tree_data.sel_anchor_offset;
+ params.sel_focus_object_id = result.tree_data.sel_focus_object_id;
+ params.sel_focus_offset = result.tree_data.sel_focus_offset;
}
- ScopedJavaLocalRef<jobject> j_root = WalkAXTreeDepthFirst(env, root, params);
+ gfx::Rect parent_rect;
+ ScopedJavaLocalRef<jobject> j_root =
+ WalkAXTreeDepthFirst(env, root, parent_rect, &params);
Java_WebContentsImpl_onAccessibilitySnapshot(
env, j_root.obj(), callback.obj());
}
-void ReleaseAllMediaPlayers(WebContents* web_contents,
- RenderFrameHost* render_frame_host) {
- BrowserMediaPlayerManager* manager =
- MediaWebContentsObserverAndroid::FromWebContents(web_contents)
- ->GetMediaPlayerManager(render_frame_host);
- if (manager)
- manager->ReleaseAllMediaPlayers();
-}
-
} // namespace
// static
@@ -398,13 +386,17 @@ void WebContentsAndroid::OnShow(JNIEnv* env, const JavaParamRef<jobject>& obj) {
web_contents_->WasShown();
}
-void WebContentsAndroid::ReleaseMediaPlayers(
+void WebContentsAndroid::SuspendAllMediaPlayers(
JNIEnv* env,
const JavaParamRef<jobject>& jobj) {
-#if defined(ENABLE_BROWSER_CDMS)
- web_contents_->ForEachFrame(
- base::Bind(&ReleaseAllMediaPlayers, base::Unretained(web_contents_)));
-#endif // defined(ENABLE_BROWSER_CDMS)
+ MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
+ ->SuspendAllMediaPlayers();
+}
+
+void WebContentsAndroid::SetAudioMuted(JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ jboolean mute) {
+ web_contents_->SetAudioMuted(mute);
}
void WebContentsAndroid::ShowInterstitialPage(JNIEnv* env,
@@ -441,7 +433,7 @@ jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
void WebContentsAndroid::ExitFullscreen(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
- web_contents_->ExitFullscreen();
+ web_contents_->ExitFullscreen(/*will_cause_resize=*/false);
}
void WebContentsAndroid::UpdateTopControlsState(
@@ -604,21 +596,15 @@ jint WebContentsAndroid::GetThemeColor(JNIEnv* env,
void WebContentsAndroid::RequestAccessibilitySnapshot(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
- const JavaParamRef<jobject>& callback,
- jfloat y_offset,
- jfloat x_scroll) {
+ const JavaParamRef<jobject>& callback) {
// Secure the Java callback in a scoped object and give ownership of it to the
// base::Callback.
ScopedJavaGlobalRef<jobject> j_callback;
j_callback.Reset(env, callback);
gfx::DeviceDisplayInfo device_info;
- ContentViewCoreImpl* contentViewCore =
- ContentViewCoreImpl::FromWebContents(web_contents_);
- AccessibilitySnapshotParams* params = new AccessibilitySnapshotParams(
- contentViewCore->GetScaleFactor(), y_offset, x_scroll);
WebContentsImpl::AXTreeSnapshotCallback snapshot_callback =
- base::Bind(&AXTreeSnapshotCallback, j_callback, base::Owned(params));
+ base::Bind(&AXTreeSnapshotCallback, j_callback);
static_cast<WebContentsImpl*>(web_contents_)->RequestAXTreeSnapshot(
snapshot_callback);
}
@@ -682,6 +668,11 @@ void WebContentsAndroid::OnContextMenuClosed(JNIEnv* env,
->NotifyContextMenuClosed(CustomContextMenuContext());
}
+void WebContentsAndroid::ReloadLoFiImages(JNIEnv* env,
+ const JavaParamRef<jobject>& obj) {
+ static_cast<WebContentsImpl*>(web_contents_)->ReloadLoFiImages();
+}
+
void WebContentsAndroid::OnFinishGetContentBitmap(
ScopedJavaGlobalRef<jobject>* obj,
ScopedJavaGlobalRef<jobject>* callback,
diff --git a/chromium/content/browser/web_contents/web_contents_android.h b/chromium/content/browser/web_contents/web_contents_android.h
index 9453d52d020..432b65ac5a5 100644
--- a/chromium/content/browser/web_contents/web_contents_android.h
+++ b/chromium/content/browser/web_contents/web_contents_android.h
@@ -78,8 +78,11 @@ class CONTENT_EXPORT WebContentsAndroid
void OnHide(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
void OnShow(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
- void ReleaseMediaPlayers(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& jobj);
+ void SuspendAllMediaPlayers(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj);
+ void SetAudioMuted(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ jboolean mute);
void ShowInterstitialPage(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
@@ -149,9 +152,7 @@ class CONTENT_EXPORT WebContentsAndroid
void RequestAccessibilitySnapshot(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
- const base::android::JavaParamRef<jobject>& callback,
- jfloat y_offset,
- jfloat x_scroll);
+ const base::android::JavaParamRef<jobject>& callback);
void ResumeMediaSession(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
@@ -178,6 +179,9 @@ class CONTENT_EXPORT WebContentsAndroid
void OnContextMenuClosed(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
+ void ReloadLoFiImages(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj);
+
void set_synchronous_compositor_client(SynchronousCompositorClient* client) {
synchronous_compositor_client_ = client;
}
diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc
index b5b0b7853c7..e41ef9f6c7d 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl.cc
@@ -14,6 +14,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/process/process.h"
#include "base/profiler/scoped_tracker.h"
@@ -45,6 +46,7 @@
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/navigator_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/geolocation/geolocation_service_context.h"
#include "content/browser/host_zoom_map_impl.h"
@@ -53,6 +55,7 @@
#include "content/browser/media/audio_stream_monitor.h"
#include "content/browser/media/capture/web_contents_audio_muter.h"
#include "content/browser/media/media_web_contents_observer.h"
+#include "content/browser/media/session/media_session.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/plugin_content_origin_whitelist.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
@@ -72,6 +75,7 @@
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/frame_messages.h"
#include "content/common/input_messages.h"
+#include "content/common/page_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/ssl_status_serialization.h"
#include "content/common/view_messages.h"
@@ -114,7 +118,9 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "skia/public/type_converters.h"
+#include "third_party/WebKit/public/web/WebSandboxFlags.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/accessibility/ax_tree_combiner.h"
#include "ui/base/layout.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
@@ -122,14 +128,10 @@
#if defined(OS_ANDROID)
#include "content/browser/android/content_video_view.h"
-#include "content/browser/media/android/media_session.h"
-#include "content/browser/media/android/media_web_contents_observer_android.h"
-#endif // OS_ANDROID
-
-#if defined(OS_ANDROID) && !defined(USE_AURA)
#include "content/browser/android/date_time_chooser_android.h"
+#include "content/browser/media/android/media_web_contents_observer_android.h"
#include "content/browser/web_contents/web_contents_android.h"
-#endif // OS_ANDROID && !USE_AURA
+#endif // OS_ANDROID
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
@@ -164,49 +166,12 @@ void NotifyCacheOnIO(
cache->OnExternalCacheHit(url, http_method);
}
-bool FindMatchingProcess(int render_process_id,
- bool* did_match_process,
- FrameTreeNode* node) {
- if (node->current_frame_host()->GetProcess()->GetID() == render_process_id) {
- *did_match_process = true;
- return false;
+bool HasMatchingProcess(FrameTree* tree, int render_process_id) {
+ for (FrameTreeNode* node : tree->Nodes()) {
+ if (node->current_frame_host()->GetProcess()->GetID() == render_process_id)
+ return true;
}
- return true;
-}
-
-bool ForEachFrameInternal(
- const base::Callback<void(RenderFrameHost*)>& on_frame,
- FrameTreeNode* node) {
- on_frame.Run(node->current_frame_host());
- return true;
-}
-
-bool ForEachPendingFrameInternal(
- const base::Callback<void(RenderFrameHost*)>& on_frame,
- FrameTreeNode* node) {
- RenderFrameHost* pending_frame_host =
- node->render_manager()->pending_frame_host();
- if (pending_frame_host)
- on_frame.Run(pending_frame_host);
- return true;
-}
-
-void SendToAllFramesInternal(int* number_of_messages,
- IPC::Message* message,
- RenderFrameHost* rfh) {
- *number_of_messages = *number_of_messages + 1;
- IPC::Message* message_copy = new IPC::Message(*message);
- message_copy->set_routing_id(rfh->GetRoutingID());
- rfh->Send(message_copy);
-}
-
-void AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView*>* set,
- RenderFrameHost* rfh) {
- RenderWidgetHostView* rwhv = static_cast<RenderFrameHostImpl*>(rfh)
- ->frame_tree_node()
- ->render_manager()
- ->GetRenderWidgetHostView();
- set->insert(rwhv);
+ return false;
}
void SetAccessibilityModeOnFrame(AccessibilityMode mode,
@@ -218,6 +183,44 @@ void ResetAccessibility(RenderFrameHost* rfh) {
static_cast<RenderFrameHostImpl*>(rfh)->AccessibilityReset();
}
+using AXTreeSnapshotCallback =
+ base::Callback<void(const ui::AXTreeUpdate&)>;
+
+// Helper class used by WebContentsImpl::RequestAXTreeSnapshot.
+// Handles the callbacks from parallel snapshot requests to each frame,
+// and feeds the results to an AXTreeCombiner, which converts them into a
+// single combined accessibility tree.
+class AXTreeSnapshotCombiner : public base::RefCounted<AXTreeSnapshotCombiner> {
+ public:
+ explicit AXTreeSnapshotCombiner(AXTreeSnapshotCallback callback)
+ : callback_(callback) {
+ }
+
+ AXTreeSnapshotCallback AddFrame(bool is_root) {
+ // Adds a reference to |this|.
+ return base::Bind(&AXTreeSnapshotCombiner::ReceiveSnapshot,
+ this,
+ is_root);
+ }
+
+ void ReceiveSnapshot(bool is_root, const ui::AXTreeUpdate& snapshot) {
+ combiner_.AddTree(snapshot, is_root);
+ }
+
+ private:
+ friend class base::RefCounted<AXTreeSnapshotCombiner>;
+
+ // This is called automatically after the last call to ReceiveSnapshot
+ // when there are no more references to this object.
+ ~AXTreeSnapshotCombiner() {
+ combiner_.Combine();
+ callback_.Run(combiner_.combined());
+ }
+
+ ui::AXTreeCombiner combiner_;
+ AXTreeSnapshotCallback callback_;
+};
+
} // namespace
WebContents* WebContents::Create(const WebContents::CreateParams& params) {
@@ -354,15 +357,11 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
controller_(this, browser_context),
render_view_host_delegate_view_(NULL),
created_with_opener_(false),
-#if defined(OS_WIN)
- accessible_parent_(NULL),
-#endif
frame_tree_(new NavigatorImpl(&controller_, this),
this,
this,
this,
this),
- is_loading_(false),
is_load_to_different_document_(false),
crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
crashed_error_code_(0),
@@ -378,6 +377,7 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
did_first_visually_non_empty_paint_(false),
capturer_count_(0),
should_normally_be_visible_(true),
+ did_first_set_visible_(false),
is_being_destroyed_(false),
notify_disconnection_(false),
dialog_manager_(NULL),
@@ -398,6 +398,7 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
accessibility_mode_(
BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
audio_stream_monitor_(this),
+ bluetooth_connected_device_count_(0),
virtual_keyboard_requested_(false),
page_scale_factor_is_one_(true),
loading_weak_factory_(this),
@@ -410,6 +411,7 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
#else
media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
#endif
+ loader_io_thread_notifier_.reset(new LoaderIOThreadNotifier(this));
wake_lock_service_context_.reset(new WakeLockServiceContext(this));
}
@@ -418,18 +420,15 @@ WebContentsImpl::~WebContentsImpl() {
rwh_input_event_router_.reset();
- // Delete all RFH pending shutdown, which will lead the corresponding RVH to
- // shutdown and be deleted as well.
- frame_tree_.ForEach(
- base::Bind(&RenderFrameHostManager::ClearRFHsPendingShutdown));
-
- // Destroy all WebUI instances.
- frame_tree_.ForEach(base::Bind(&RenderFrameHostManager::ClearWebUIInstances));
-
- for (std::set<RenderWidgetHostImpl*>::iterator iter =
- created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
- (*iter)->DetachDelegate();
+ for (FrameTreeNode* node : frame_tree_.Nodes()) {
+ // Delete all RFHs pending shutdown, which will lead the corresponding RVHs
+ // to be shutdown and be deleted as well.
+ node->render_manager()->ClearRFHsPendingShutdown();
+ node->render_manager()->ClearWebUIInstances();
}
+
+ for (RenderWidgetHostImpl* widget : created_widgets_)
+ widget->DetachDelegate();
created_widgets_.clear();
// Clear out any JavaScript state.
@@ -469,7 +468,8 @@ WebContentsImpl::~WebContentsImpl() {
// PlzNavigate: clear up state specific to browser-side navigation.
if (IsBrowserSideNavigationEnabled()) {
- frame_tree_.root()->ResetNavigationRequest(false);
+ // Do not update state as the WebContents is being destroyed.
+ frame_tree_.root()->ResetNavigationRequest(true);
if (root->speculative_frame_host()) {
root->speculative_frame_host()->SetRenderFrameCreated(false);
root->speculative_frame_host()->SetNavigationHandle(
@@ -510,11 +510,28 @@ WebContentsImpl* WebContentsImpl::CreateWithOpener(
TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener");
WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context);
+ FrameTreeNode* new_root = new_contents->GetFrameTree()->root();
+
if (!params.opener_suppressed && opener) {
- new_contents->GetFrameTree()->root()->SetOpener(opener);
+ new_root->SetOpener(opener);
new_contents->created_with_opener_ = true;
}
+ // If the opener is sandboxed, a new popup must inherit the opener's sandbox
+ // flags, and these flags take effect immediately. An exception is if the
+ // opener's sandbox flags lack the PropagatesToAuxiliaryBrowsingContexts
+ // bit (which is controlled by the "allow-popups-to-escape-sandbox" token).
+ // See https://html.spec.whatwg.org/#attr-iframe-sandbox.
+ if (opener) {
+ blink::WebSandboxFlags opener_flags = opener->effective_sandbox_flags();
+ const blink::WebSandboxFlags inherit_flag =
+ blink::WebSandboxFlags::PropagatesToAuxiliaryBrowsingContexts;
+ if ((opener_flags & inherit_flag) == inherit_flag) {
+ new_root->SetPendingSandboxFlags(opener_flags);
+ new_root->CommitPendingSandboxFlags();
+ }
+ }
+
// This may be true even when opener is null, such as when opening blocked
// popups.
if (params.created_with_opener)
@@ -647,7 +664,7 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
OnUnregisterProtocolHandler)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdatePageImportanceSignals,
OnUpdatePageImportanceSignals)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_Find_Reply, OnFindReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
#if defined(ENABLE_PLUGINS)
@@ -670,8 +687,8 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
OnHideValidationMessage)
IPC_MESSAGE_HANDLER(ViewHostMsg_MoveValidationMessage,
OnMoveValidationMessage)
-#if defined(OS_ANDROID) && !defined(USE_AURA)
- IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply,
+#if defined(OS_ANDROID)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_FindMatchRects_Reply,
OnFindMatchRectsReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog,
OnOpenDateTimeDialog)
@@ -775,17 +792,37 @@ RenderFrameHostImpl* WebContentsImpl::FindFrameByFrameTreeNodeId(
void WebContentsImpl::ForEachFrame(
const base::Callback<void(RenderFrameHost*)>& on_frame) {
- frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame));
+ for (FrameTreeNode* node : frame_tree_.Nodes()) {
+ on_frame.Run(node->current_frame_host());
+ }
+}
+
+std::vector<RenderFrameHost*> WebContentsImpl::GetAllFrames() {
+ std::vector<RenderFrameHost*> frame_hosts;
+ for (FrameTreeNode* node : frame_tree_.Nodes())
+ frame_hosts.push_back(node->current_frame_host());
+ return frame_hosts;
}
int WebContentsImpl::SendToAllFrames(IPC::Message* message) {
int number_of_messages = 0;
- ForEachFrame(
- base::Bind(&SendToAllFramesInternal, &number_of_messages, message));
+ for (RenderFrameHost* rfh : GetAllFrames()) {
+ if (!rfh->IsRenderFrameLive())
+ continue;
+
+ ++number_of_messages;
+ IPC::Message* message_copy = new IPC::Message(*message);
+ message_copy->set_routing_id(rfh->GetRoutingID());
+ rfh->Send(message_copy);
+ }
delete message;
return number_of_messages;
}
+void WebContentsImpl::SendPageMessage(IPC::Message* msg) {
+ frame_tree_.root()->render_manager()->SendPageMessage(msg);
+}
+
RenderViewHostImpl* WebContentsImpl::GetRenderViewHost() const {
return GetRenderManager()->current_host();
}
@@ -837,12 +874,14 @@ void WebContentsImpl::SetAccessibilityMode(AccessibilityMode mode) {
return;
accessibility_mode_ = mode;
- frame_tree_.ForEach(
- base::Bind(&ForEachFrameInternal,
- base::Bind(&SetAccessibilityModeOnFrame, mode)));
- frame_tree_.ForEach(
- base::Bind(&ForEachPendingFrameInternal,
- base::Bind(&SetAccessibilityModeOnFrame, mode)));
+
+ for (FrameTreeNode* node : frame_tree_.Nodes()) {
+ SetAccessibilityModeOnFrame(mode, node->current_frame_host());
+ RenderFrameHost* pending_frame_host =
+ node->render_manager()->pending_frame_host();
+ if (pending_frame_host)
+ SetAccessibilityModeOnFrame(mode, pending_frame_host);
+ }
}
void WebContentsImpl::AddAccessibilityMode(AccessibilityMode mode) {
@@ -854,10 +893,16 @@ void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
}
void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback) {
- // TODO(dmazzoni): http://crbug.com/475608 This only returns the
- // accessibility tree from the main frame and everything in the
- // same site instance.
- GetMainFrame()->RequestAXTreeSnapshot(callback);
+ // Send a request to each of the frames in parallel. Each one will return
+ // an accessibility tree snapshot, and AXTreeSnapshotCombiner will combine
+ // them into a single tree and call |callback| with that result, then
+ // delete |combiner|.
+ AXTreeSnapshotCombiner* combiner = new AXTreeSnapshotCombiner(callback);
+ for (FrameTreeNode* frame_tree_node : frame_tree_.Nodes()) {
+ bool is_root = frame_tree_node->parent() == nullptr;
+ frame_tree_node->current_frame_host()->RequestAXTreeSnapshot(
+ combiner->AddFrame(is_root));
+ }
}
WebUI* WebContentsImpl::CreateSubframeWebUI(const GURL& url,
@@ -890,8 +935,8 @@ void WebContentsImpl::SetUserAgentOverride(const std::string& override) {
// Reload the page if a load is currently in progress to avoid having
// different parts of the page loaded using different user agents.
NavigationEntry* entry = controller_.GetVisibleEntry();
- if (is_loading_ && entry != NULL && entry->GetIsOverridingUserAgent())
- controller_.ReloadIgnoringCache(true);
+ if (IsLoading() && entry != NULL && entry->GetIsOverridingUserAgent())
+ controller_.ReloadBypassingCache(true);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
UserAgentOverrideSet(override));
@@ -902,10 +947,12 @@ const std::string& WebContentsImpl::GetUserAgentOverride() const {
}
void WebContentsImpl::EnableTreeOnlyAccessibilityMode() {
- if (GetAccessibilityMode() != AccessibilityModeOff)
- ForEachFrame(base::Bind(&ResetAccessibility));
- else
+ if (GetAccessibilityMode() != AccessibilityModeOff) {
+ for (RenderFrameHost* rfh : GetAllFrames())
+ ResetAccessibility(rfh);
+ } else {
AddAccessibilityMode(AccessibilityModeTreeOnly);
+ }
}
bool WebContentsImpl::IsTreeOnlyAccessibilityModeForTesting() const {
@@ -916,16 +963,6 @@ bool WebContentsImpl::IsFullAccessibilityModeForTesting() const {
return accessibility_mode_ == AccessibilityModeComplete;
}
-#if defined(OS_WIN)
-void WebContentsImpl::SetParentNativeViewAccessible(
-gfx::NativeViewAccessible accessible_parent) {
- accessible_parent_ = accessible_parent;
- RenderFrameHostImpl* rfh = GetMainFrame();
- if (rfh)
- rfh->SetParentNativeViewAccessible(accessible_parent);
-}
-#endif
-
const PageImportanceSignals& WebContentsImpl::GetPageImportanceSignals() const {
return page_importance_signals_;
}
@@ -934,11 +971,8 @@ const base::string16& WebContentsImpl::GetTitle() const {
// Transient entries take precedence. They are used for interstitial pages
// that are shown on top of existing pages.
NavigationEntry* entry = controller_.GetTransientEntry();
- std::string accept_languages =
- GetContentClient()->browser()->GetAcceptLangs(
- GetBrowserContext());
if (entry) {
- return entry->GetTitleForDisplay(accept_languages);
+ return entry->GetTitleForDisplay();
}
WebUI* navigating_web_ui = GetRenderManager()->GetNavigatingWebUI();
@@ -979,7 +1013,7 @@ const base::string16& WebContentsImpl::GetTitle() const {
}
if (entry) {
- return entry->GetTitleForDisplay(accept_languages);
+ return entry->GetTitleForDisplay();
}
// |page_title_when_no_navigation_entry_| is finally used
@@ -1028,11 +1062,13 @@ SiteInstanceImpl* WebContentsImpl::GetPendingSiteInstance() const {
}
bool WebContentsImpl::IsLoading() const {
- return is_loading_;
+ return frame_tree_.IsLoading() &&
+ !(ShowingInterstitialPage() &&
+ GetRenderManager()->interstitial_page()->pause_throbber());
}
bool WebContentsImpl::IsLoadingToDifferentDocument() const {
- return is_loading_ && is_load_to_different_document_;
+ return IsLoading() && is_load_to_different_document_;
}
bool WebContentsImpl::IsWaitingForResponse() const {
@@ -1132,6 +1168,27 @@ void WebContentsImpl::SetAudioMuted(bool mute) {
NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
}
+void WebContentsImpl::IncrementBluetoothConnectedDeviceCount() {
+ // Notify for UI updates if the state changes.
+ bluetooth_connected_device_count_++;
+ if (bluetooth_connected_device_count_ == 1) {
+ NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ }
+}
+
+void WebContentsImpl::DecrementBluetoothConnectedDeviceCount() {
+ // Notify for UI updates if the state changes.
+ DCHECK(bluetooth_connected_device_count_ != 0);
+ bluetooth_connected_device_count_--;
+ if (bluetooth_connected_device_count_ == 0) {
+ NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ }
+}
+
+bool WebContentsImpl::IsConnectedToBluetoothDevice() const {
+ return bluetooth_connected_device_count_ > 0;
+}
+
bool WebContentsImpl::IsCrashed() const {
return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
@@ -1158,6 +1215,10 @@ base::TerminationStatus WebContentsImpl::GetCrashedStatus() const {
return crashed_status_;
}
+int WebContentsImpl::GetCrashedErrorCode() const {
+ return crashed_error_code_;
+}
+
bool WebContentsImpl::IsBeingDestroyed() const {
return is_being_destroyed_;
}
@@ -1265,6 +1326,19 @@ void WebContentsImpl::AttachToOuterWebContentsFrame(
WebContents* outer_web_contents,
RenderFrameHost* outer_contents_frame) {
CHECK(BrowserPluginGuestMode::UseCrossProcessFramesForGuests());
+ RenderFrameHostManager* render_manager = GetRenderManager();
+
+ // When the WebContents being initialized has an opener, the browser side
+ // Render{View,Frame}Host must be initialized and the RenderWidgetHostView
+ // created. This is needed because the usual initialization happens during
+ // the first navigation, but when attaching a new window we don't navigate
+ // before attaching. If the browser side is already initialized, the calls
+ // below will just early return.
+ render_manager->InitRenderView(GetRenderViewHost(), nullptr);
+ GetMainFrame()->Init();
+ if (!render_manager->GetRenderWidgetHostView())
+ CreateRenderWidgetHostViewForRenderManager(GetRenderViewHost());
+
// Create a link to our outer WebContents.
node_.reset(new WebContentsTreeNode());
node_->ConnectToOuterWebContents(
@@ -1276,16 +1350,21 @@ void WebContentsImpl::AttachToOuterWebContentsFrame(
// Create a proxy in top-level RenderFrameHostManager, pointing to the
// SiteInstance of the outer WebContents. The proxy will be used to send
// postMessage to the inner WebContents.
- GetRenderManager()->CreateOuterDelegateProxy(
+ render_manager->CreateOuterDelegateProxy(
outer_contents_frame->GetSiteInstance(),
static_cast<RenderFrameHostImpl*>(outer_contents_frame));
- GetRenderManager()->SetRWHViewForInnerContents(
- GetRenderManager()->GetRenderWidgetHostView());
+ render_manager->SetRWHViewForInnerContents(
+ render_manager->GetRenderWidgetHostView());
+
+ static_cast<RenderWidgetHostViewChildFrame*>(
+ render_manager->GetRenderWidgetHostView())
+ ->RegisterSurfaceNamespaceId();
}
void WebContentsImpl::Stop() {
- frame_tree_.ForEach(base::Bind(&FrameTreeNode::StopLoading));
+ for (FrameTreeNode* node : frame_tree_.Nodes())
+ node->StopLoading();
FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped());
}
@@ -1371,7 +1450,11 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
GetRenderManager()->Init(site_instance.get(), view_routing_id,
params.main_frame_routing_id,
main_frame_widget_routing_id);
- frame_tree_.root()->SetFrameName(params.main_frame_name);
+
+ // blink::FrameTree::setName uses |name| as the |unique_name| for the main
+ // frame - let's do the same thing here.
+ std::string unique_name = params.main_frame_name;
+ frame_tree_.root()->SetFrameName(params.main_frame_name, unique_name);
WebContentsViewDelegate* delegate =
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -1419,7 +1502,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
manifest_manager_host_.reset(new ManifestManagerHost(this));
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
date_time_chooser_.reset(new DateTimeChooserAndroid());
#endif
@@ -1493,8 +1576,13 @@ WebContentsImpl::GetRenderWidgetHostViewsInTree() {
if (ShowingInterstitialPage()) {
set.insert(GetRenderWidgetHostView());
} else {
- ForEachFrame(
- base::Bind(&AddRenderWidgetHostViewToSet, base::Unretained(&set)));
+ for (RenderFrameHost* rfh : GetAllFrames()) {
+ RenderWidgetHostView* rwhv = static_cast<RenderFrameHostImpl*>(rfh)
+ ->frame_tree_node()
+ ->render_manager()
+ ->GetRenderWidgetHostView();
+ set.insert(rwhv);
+ }
}
return set;
}
@@ -1670,11 +1758,13 @@ void WebContentsImpl::EnterFullscreenMode(const GURL& origin) {
delegate_->EnterFullscreenModeForTab(this, origin);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab(
- GetRenderViewHost()->GetWidget())));
+ DidToggleFullscreenModeForTab(
+ IsFullscreenForCurrentTab(
+ GetRenderViewHost()->GetWidget()),
+ false));
}
-void WebContentsImpl::ExitFullscreenMode() {
+void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
// This method is being called to leave renderer-initiated fullscreen mode.
// Make sure any existing fullscreen widget is shut down first.
RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
@@ -1686,26 +1776,32 @@ void WebContentsImpl::ExitFullscreenMode() {
#if defined(OS_ANDROID)
ContentVideoView* video_view = ContentVideoView::GetInstance();
if (video_view != NULL)
- video_view->OnExitFullscreen();
+ video_view->ExitFullscreen();
#endif
if (delegate_)
delegate_->ExitFullscreenModeForTab(this);
- // Ensure web contents exit fullscreen state by sending a resize message,
- // which includes the fullscreen state. This is required for the situation
- // of the browser moving the view into a fullscreen state "browser fullscreen"
- // and then the contents entering "tab fullscreen". Exiting the contents
- // "tab fullscreen" then won't have the side effect of the view resizing,
- // hence the explicit call here is required.
- if (RenderWidgetHostView* rwh_view = GetRenderWidgetHostView()) {
- if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
- render_widget_host->WasResized();
+ // The fullscreen state is communicated to the renderer through a resize
+ // message. If the change in fullscreen state doesn't cause a view resize
+ // then we must ensure web contents exit the fullscreen state by explicitly
+ // sending a resize message. This is required for the situation of the browser
+ // moving the view into a "browser fullscreen" state and then the contents
+ // entering "tab fullscreen". Exiting the contents "tab fullscreen" then won't
+ // have the side effect of the view resizing, hence the explicit call here is
+ // required.
+ if (!will_cause_resize) {
+ if (RenderWidgetHostView* rwhv = GetRenderWidgetHostView()) {
+ if (RenderWidgetHost* render_widget_host = rwhv->GetRenderWidgetHost())
+ render_widget_host->WasResized();
+ }
}
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab(
- GetRenderViewHost()->GetWidget())));
+ DidToggleFullscreenModeForTab(
+ IsFullscreenForCurrentTab(
+ GetRenderViewHost()->GetWidget()),
+ will_cause_resize));
}
bool WebContentsImpl::IsFullscreenForCurrentTab(
@@ -1751,11 +1847,15 @@ void WebContentsImpl::LostMouseLock(RenderWidgetHostImpl* render_widget_host) {
void WebContentsImpl::ForwardCompositorProto(
RenderWidgetHostImpl* render_widget_host,
const std::vector<uint8_t>& proto) {
- if (render_widget_host != GetRenderViewHost()->GetWidget())
- return;
-
if (delegate_)
- delegate_->ForwardCompositorProto(proto);
+ delegate_->ForwardCompositorProto(render_widget_host, proto);
+}
+
+void WebContentsImpl::OnRenderFrameProxyVisibilityChanged(bool visible) {
+ if (visible)
+ WasShown();
+ else
+ WasHidden();
}
void WebContentsImpl::CreateNewWindow(
@@ -1771,12 +1871,6 @@ void WebContentsImpl::CreateNewWindow(
// SiteInstance in its own BrowsingInstance.
bool is_guest = BrowserPluginGuest::IsGuest(this);
- if (is_guest && BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
- // TODO(lazyboy): CreateNewWindow doesn't work for OOPIF-based <webview>
- // yet.
- NOTREACHED();
- }
-
// If the opener is to be suppressed, the new window can be in any process.
// Since routing ids are process specific, we must not have one passed in
// as argument here.
@@ -1791,10 +1885,7 @@ void WebContentsImpl::CreateNewWindow(
// in this WebContents' FrameTree. If any other process sends the request, it
// is invalid and the process must be terminated.
int render_process_id = source_site_instance->GetProcess()->GetID();
- bool did_match_process = false;
- frame_tree_.ForEach(
- base::Bind(&FindMatchingProcess, render_process_id, &did_match_process));
- if (!did_match_process) {
+ if (!HasMatchingProcess(&frame_tree_, render_process_id)) {
RenderProcessHost* rph = source_site_instance->GetProcess();
base::ProcessHandle process_handle = rph->GetHandle();
if (process_handle != base::kNullProcessHandle) {
@@ -1831,7 +1922,10 @@ void WebContentsImpl::CreateNewWindow(
// delete the RenderView that had already been created.
Send(new ViewMsg_Close(route_id));
}
- GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
+ // It's safe to only target the frame because the render process will not
+ // have a chance to create more frames at this point.
+ ResourceDispatcherHostImpl::ResumeBlockedRequestsForRouteFromUI(
+ GlobalFrameRoutingId(render_process_id, main_frame_route_id));
return;
}
@@ -1939,20 +2033,16 @@ void WebContentsImpl::CreateNewWidget(int32_t render_process_id,
int32_t route_id,
bool is_fullscreen,
blink::WebPopupType popup_type) {
- RenderProcessHost* process = GetRenderProcessHost();
+ RenderProcessHost* process = RenderProcessHost::FromID(render_process_id);
// A message to create a new widget can only come from an active process for
// this WebContentsImpl instance. If any other process sends the request,
// it is invalid and the process must be terminated.
- bool did_match_process = false;
- frame_tree_.ForEach(
- base::Bind(&FindMatchingProcess, render_process_id, &did_match_process));
- if (!did_match_process) {
- RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
- base::ProcessHandle process_handle = rph->GetHandle();
+ if (!HasMatchingProcess(&frame_tree_, render_process_id)) {
+ base::ProcessHandle process_handle = process->GetHandle();
if (process_handle != base::kNullProcessHandle) {
RecordAction(
base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget"));
- rph->Shutdown(RESULT_CODE_KILLED, false);
+ process->Shutdown(RESULT_CODE_KILLED, false);
}
return;
}
@@ -2194,7 +2284,19 @@ void WebContentsImpl::OnMoveValidationMessage(
delegate_->MoveValidationMessage(this, anchor_in_root_view);
}
-void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
+void WebContentsImpl::SendScreenRects() {
+ for (FrameTreeNode* node : frame_tree_.Nodes()) {
+ if (node->current_frame_host()->GetRenderWidgetHost())
+ node->current_frame_host()->GetRenderWidgetHost()->SendScreenRects();
+ }
+
+ RenderWidgetHostViewBase* rwhv =
+ static_cast<RenderWidgetHostViewBase*>(GetRenderWidgetHostView());
+ if (rwhv) {
+ SendPageMessage(new PageMsg_UpdateWindowScreenRect(
+ MSG_ROUTING_NONE, rwhv->GetBoundsInRootWindow()));
+ }
+
if (browser_plugin_embedder_)
browser_plugin_embedder_->DidSendScreenRects();
}
@@ -2290,13 +2392,35 @@ void WebContentsImpl::AttachInterstitialPage(
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidAttachInterstitialPage());
+
+ // Stop the throbber if needed while the interstitial page is shown.
+ if (frame_tree_.IsLoading())
+ LoadingStateChanged(true, true, nullptr);
+}
+
+void WebContentsImpl::DidProceedOnInterstitial() {
+ // The interstitial page should no longer be pausing the throbber.
+ DCHECK(!(ShowingInterstitialPage() &&
+ GetRenderManager()->interstitial_page()->pause_throbber()));
+
+ // Restart the throbber now that the interstitial page no longer pauses it.
+ if (ShowingInterstitialPage() && frame_tree_.IsLoading())
+ LoadingStateChanged(true, true, nullptr);
}
void WebContentsImpl::DetachInterstitialPage() {
+ bool interstitial_pausing_throbber =
+ ShowingInterstitialPage() &&
+ GetRenderManager()->interstitial_page()->pause_throbber();
if (ShowingInterstitialPage())
GetRenderManager()->remove_interstitial_page();
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidDetachInterstitialPage());
+
+ // Restart the throbber if needed now that the interstitial page is going
+ // away.
+ if (interstitial_pausing_throbber && frame_tree_.IsLoading())
+ LoadingStateChanged(true, true, nullptr);
}
void WebContentsImpl::SetHistoryOffsetAndLength(int history_offset,
@@ -2313,13 +2437,17 @@ void WebContentsImpl::SetHistoryOffsetAndLengthForView(
render_view_host->GetRoutingID(), history_offset, history_length));
}
-void WebContentsImpl::ReloadFocusedFrame(bool ignore_cache) {
+void WebContentsImpl::ReloadFocusedFrame(bool bypass_cache) {
RenderFrameHost* focused_frame = GetFocusedFrame();
if (!focused_frame)
return;
focused_frame->Send(new FrameMsg_Reload(
- focused_frame->GetRoutingID(), ignore_cache));
+ focused_frame->GetRoutingID(), bypass_cache));
+}
+
+void WebContentsImpl::ReloadLoFiImages() {
+ SendToAllFrames(new FrameMsg_ReloadLoFiImages(MSG_ROUTING_NONE));
}
void WebContentsImpl::Undo() {
@@ -2674,14 +2802,6 @@ void WebContentsImpl::DidGetRedirectForResourceRequest(
NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
Source<WebContents>(this),
Details<const ResourceRedirectDetails>(&details));
-
- if (IsResourceTypeFrame(details.resource_type)) {
- NavigationHandleImpl* navigation_handle =
- static_cast<RenderFrameHostImpl*>(render_frame_host)
- ->navigation_handle();
- if (navigation_handle)
- navigation_handle->DidRedirectNavigation(details.new_url);
- }
}
void WebContentsImpl::NotifyWebContentsFocused() {
@@ -2696,7 +2816,8 @@ void WebContentsImpl::SystemDragEnded() {
}
void WebContentsImpl::UserGestureDone() {
- OnUserGesture(GetRenderViewHost()->GetWidget());
+ OnUserInteraction(GetRenderViewHost()->GetWidget(),
+ blink::WebInputEvent::Undefined);
}
void WebContentsImpl::SetClosedByUserGesture(bool value) {
@@ -2796,7 +2917,7 @@ int WebContentsImpl::DownloadImage(
const WebContents::ImageDownloadCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
static int next_image_download_id = 0;
- const image_downloader::ImageDownloaderPtr& mojo_image_downloader =
+ const content::mojom::ImageDownloaderPtr& mojo_image_downloader =
GetMainFrame()->GetMojoImageDownloader();
const int download_id = ++next_image_download_id;
if (!mojo_image_downloader) {
@@ -2804,29 +2925,18 @@ int WebContentsImpl::DownloadImage(
// Android), the downloader service will be invalid. Pre-Mojo, this would
// hang the callback indefinetly since the IPC would be dropped. Now,
// respond with a 400 HTTP error code to indicate that something went wrong.
- image_downloader::DownloadResultPtr result =
- image_downloader::DownloadResult::New();
- result->http_status_code = 400;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&WebContentsImpl::OnDidDownloadImage,
- weak_factory_.GetWeakPtr(), callback, download_id, url,
- base::Passed(&result)));
+ weak_factory_.GetWeakPtr(), callback, download_id, url, 400,
+ nullptr, nullptr));
return download_id;
}
- image_downloader::DownloadRequestPtr req =
- image_downloader::DownloadRequest::New();
-
- req->url = mojo::String::From(url);
- req->is_favicon = is_favicon;
- req->max_bitmap_size = max_bitmap_size;
- req->bypass_cache = bypass_cache;
-
mojo_image_downloader->DownloadImage(
- std::move(req), base::Bind(&WebContentsImpl::OnDidDownloadImage,
- weak_factory_.GetWeakPtr(), callback,
- download_id, url));
+ mojo::String::From(url), is_favicon, max_bitmap_size, bypass_cache,
+ base::Bind(&WebContentsImpl::OnDidDownloadImage,
+ weak_factory_.GetWeakPtr(), callback, download_id, url));
return download_id;
}
@@ -2848,7 +2958,8 @@ void WebContentsImpl::Find(int request_id,
browser_plugin_embedder_->Find(request_id, search_text, options)) {
return;
}
- Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options));
+ GetMainFrame()->Send(new FrameMsg_Find(GetMainFrame()->GetRoutingID(),
+ request_id, search_text, options));
}
void WebContentsImpl::StopFinding(StopFindAction action) {
@@ -2857,7 +2968,8 @@ void WebContentsImpl::StopFinding(StopFindAction action) {
browser_plugin_embedder_->StopFinding(action)) {
return;
}
- Send(new ViewMsg_StopFinding(GetRoutingID(), action));
+ GetMainFrame()->Send(
+ new FrameMsg_StopFinding(GetMainFrame()->GetRoutingID(), action));
}
void WebContentsImpl::InsertCSS(const std::string& css) {
@@ -2877,10 +2989,10 @@ void WebContentsImpl::HasManifest(const HasManifestCallback& callback) {
manifest_manager_host_->HasManifest(GetMainFrame(), callback);
}
-void WebContentsImpl::ExitFullscreen() {
+void WebContentsImpl::ExitFullscreen(bool will_cause_resize) {
// Clean up related state and initiate the fullscreen exit.
GetRenderViewHost()->GetWidget()->RejectMouseLockOrUnlockIfNecessary();
- ExitFullscreenMode();
+ ExitFullscreenMode(will_cause_resize);
}
void WebContentsImpl::ResumeLoadingCreatedWebContents() {
@@ -2900,9 +3012,28 @@ void WebContentsImpl::ResumeLoadingCreatedWebContents() {
}
bool WebContentsImpl::FocusLocationBarByDefault() {
- NavigationEntry* entry = controller_.GetVisibleEntry();
- if (entry && entry->GetURL() == GURL(url::kAboutBlankURL))
+ // When the browser is started with about:blank as the startup URL, focus
+ // the location bar (which will also select its contents) so people can
+ // simply begin typing to navigate elsewhere.
+ //
+ // We need to be careful not to trigger this for anything other than the
+ // startup navigation. In particular, if we allow an attacker to open a
+ // popup to about:blank, then navigate, focusing the Omnibox will cause the
+ // end of the new URL to be scrolled into view instead of the start,
+ // allowing the attacker to spoof other URLs. The conditions checked here
+ // are all aimed at ensuring no such attacker-controlled navigation can
+ // trigger this.
+ //
+ // Note that we check the pending entry instead of the visible one; for the
+ // startup URL case these are the same, but for the attacker-controlled
+ // navigation case the visible entry is the committed "about:blank" URL and
+ // the pending entry is the problematic navigation elsewhere.
+ NavigationEntryImpl* entry = controller_.GetPendingEntry();
+ if (controller_.IsInitialNavigation() && entry &&
+ !entry->is_renderer_initiated() &&
+ entry->GetURL() == GURL(url::kAboutBlankURL)) {
return true;
+ }
return delegate_ && delegate_->ShouldFocusLocationBarByDefault(this);
}
@@ -3063,7 +3194,7 @@ void WebContentsImpl::DidNavigateMainFramePreCommit(
return;
}
if (IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()))
- ExitFullscreen();
+ ExitFullscreen(false);
DCHECK(!IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()));
}
@@ -3188,8 +3319,8 @@ void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
resource_type == RESOURCE_TYPE_MEDIA ?
GetBrowserContext()->GetMediaRequestContextForRenderProcess(
GetRenderProcessHost()->GetID()) :
- GetBrowserContext()->GetRequestContextForRenderProcess(
- GetRenderProcessHost()->GetID()));
+ GetRenderProcessHost()->GetStoragePartition()->
+ GetURLRequestContext());
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
@@ -3362,7 +3493,7 @@ void WebContentsImpl::OnFindReply(int request_id,
}
}
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
void WebContentsImpl::OnFindMatchRectsReply(
int version,
const std::vector<gfx::RectF>& rects,
@@ -3512,29 +3643,26 @@ void WebContentsImpl::OnUpdateFaviconURL(
DidUpdateFaviconURL(candidates));
}
-#if defined(OS_ANDROID)
-
void WebContentsImpl::OnMediaSessionStateChanged() {
MediaSession* session = MediaSession::Get(this);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
MediaSessionStateChanged(session->IsControllable(),
- session->IsSuspended()));
+ session->IsSuspended(),
+ session->metadata()));
}
void WebContentsImpl::ResumeMediaSession() {
- MediaSession::Get(this)->Resume();
+ MediaSession::Get(this)->Resume(MediaSession::SuspendType::UI);
}
void WebContentsImpl::SuspendMediaSession() {
- MediaSession::Get(this)->Suspend();
+ MediaSession::Get(this)->Suspend(MediaSession::SuspendType::UI);
}
void WebContentsImpl::StopMediaSession() {
- MediaSession::Get(this)->Stop();
+ MediaSession::Get(this)->Stop(MediaSession::SuspendType::UI);
}
-#endif // defined(OS_ANDROID)
-
void WebContentsImpl::OnFirstVisuallyNonEmptyPaint() {
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidFirstVisuallyNonEmptyPaint());
@@ -3577,53 +3705,6 @@ bool WebContentsImpl::HasAccessedInitialDocument() {
return has_accessed_initial_document_;
}
-// Notifies the RenderWidgetHost instance about the fact that the page is
-// loading, or done loading.
-void WebContentsImpl::SetIsLoading(bool is_loading,
- bool to_different_document,
- LoadNotificationDetails* details) {
- if (is_loading == is_loading_)
- return;
-
- if (!is_loading) {
- load_state_ = net::LoadStateWithParam(net::LOAD_STATE_IDLE,
- base::string16());
- load_state_host_.clear();
- upload_size_ = 0;
- upload_position_ = 0;
- }
-
- GetRenderManager()->SetIsLoading(is_loading);
-
- is_loading_ = is_loading;
- waiting_for_response_ = is_loading;
- is_load_to_different_document_ = to_different_document;
-
- if (delegate_)
- delegate_->LoadingStateChanged(this, to_different_document);
- NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD);
-
- std::string url = (details ? details->url.possibly_invalid_spec() : "NULL");
- if (is_loading) {
- TRACE_EVENT_ASYNC_BEGIN2("browser,navigation", "WebContentsImpl Loading",
- this, "URL", url, "Main FrameTreeNode id",
- GetFrameTree()->root()->frame_tree_node_id());
- FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStartLoading());
- } else {
- TRACE_EVENT_ASYNC_END1("browser,navigation", "WebContentsImpl Loading",
- this, "URL", url);
- FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStopLoading());
- }
-
- // TODO(avi): Remove. http://crbug.com/170921
- int type = is_loading ? NOTIFICATION_LOAD_START : NOTIFICATION_LOAD_STOP;
- NotificationDetails det = NotificationService::NoDetails();
- if (details)
- det = Details<LoadNotificationDetails>(details);
- NotificationService::current()->Notify(
- type, Source<NavigationController>(&controller_), det);
-}
-
void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) {
// If we are creating a RVH for a restored controller, then we need to make
// sure the RenderView starts with a next_page_id_ larger than the number
@@ -3689,6 +3770,59 @@ void WebContentsImpl::ResetLoadProgressState() {
loading_last_progress_update_ = base::TimeTicks();
}
+// Notifies the RenderWidgetHost instance about the fact that the page is
+// loading, or done loading.
+void WebContentsImpl::LoadingStateChanged(bool to_different_document,
+ bool due_to_interstitial,
+ LoadNotificationDetails* details) {
+ // Do not send notifications about loading changes in the FrameTree while the
+ // interstitial page is pausing the throbber.
+ if (ShowingInterstitialPage() &&
+ GetRenderManager()->interstitial_page()->pause_throbber() &&
+ !due_to_interstitial) {
+ return;
+ }
+
+ bool is_loading = IsLoading();
+
+ if (!is_loading) {
+ load_state_ = net::LoadStateWithParam(net::LOAD_STATE_IDLE,
+ base::string16());
+ load_state_host_.clear();
+ upload_size_ = 0;
+ upload_position_ = 0;
+ }
+
+ GetRenderManager()->SetIsLoading(is_loading);
+
+ waiting_for_response_ = is_loading;
+ is_load_to_different_document_ = to_different_document;
+
+ if (delegate_)
+ delegate_->LoadingStateChanged(this, to_different_document);
+ NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD);
+
+ std::string url = (details ? details->url.possibly_invalid_spec() : "NULL");
+ if (is_loading) {
+ TRACE_EVENT_ASYNC_BEGIN2("browser,navigation", "WebContentsImpl Loading",
+ this, "URL", url, "Main FrameTreeNode id",
+ GetFrameTree()->root()->frame_tree_node_id());
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStartLoading());
+ } else {
+ TRACE_EVENT_ASYNC_END1("browser,navigation", "WebContentsImpl Loading",
+ this, "URL", url);
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidStopLoading());
+ }
+
+ // TODO(avi): Remove. http://crbug.com/170921
+ int type = is_loading ? NOTIFICATION_LOAD_START : NOTIFICATION_LOAD_STOP;
+ NotificationDetails det = NotificationService::NoDetails();
+ if (details)
+ det = Details<LoadNotificationDetails>(details);
+ NotificationService::current()->Notify(
+ type, Source<NavigationController>(&controller_), det);
+}
+
void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
RenderViewHost* new_host) {
// After sending out a swap notification, we need to send a disconnect
@@ -3744,6 +3878,16 @@ void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) {
observers_,
RenderFrameCreated(render_frame_host));
SetAccessibilityModeOnFrame(accessibility_mode_, render_frame_host);
+
+ if (!render_frame_host->IsRenderFrameLive() || render_frame_host->GetParent())
+ return;
+
+ NavigationEntry* entry = controller_.GetPendingEntry();
+ if (entry && entry->IsViewSourceMode()) {
+ // Put the renderer in view source mode.
+ render_frame_host->Send(
+ new FrameMsg_EnableViewSourceMode(render_frame_host->GetRoutingID()));
+ }
}
void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
@@ -3774,18 +3918,14 @@ void WebContentsImpl::RunJavaScriptMessage(
// showing an interstitial as it's shown over the previous page and we don't
// want the hidden page's dialogs to interfere with the interstitial.
bool suppress_this_message =
- static_cast<RenderFrameHostImpl*>(render_frame_host)->is_swapped_out() ||
ShowingInterstitialPage() || !delegate_ ||
delegate_->ShouldSuppressDialogs(this) ||
!delegate_->GetJavaScriptDialogManager(this);
if (!suppress_this_message) {
- std::string accept_lang = GetContentClient()->browser()->
- GetAcceptLangs(GetBrowserContext());
dialog_manager_ = delegate_->GetJavaScriptDialogManager(this);
dialog_manager_->RunJavaScriptDialog(
- this, frame_url, accept_lang, javascript_message_type, message,
- default_prompt,
+ this, frame_url, javascript_message_type, message, default_prompt,
base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID(), reply_msg, false),
@@ -3806,7 +3946,6 @@ void WebContentsImpl::RunJavaScriptMessage(
void WebContentsImpl::RunBeforeUnloadConfirm(
RenderFrameHost* render_frame_host,
- const base::string16& message,
bool is_reload,
IPC::Message* reply_msg) {
RenderFrameHostImpl* rfhi =
@@ -3815,7 +3954,7 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
delegate_->WillRunBeforeUnloadConfirm();
bool suppress_this_message =
- rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT ||
+ !rfhi->is_active() ||
ShowingInterstitialPage() || !delegate_ ||
delegate_->ShouldSuppressDialogs(this) ||
!delegate_->GetJavaScriptDialogManager(this);
@@ -3827,7 +3966,7 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
is_showing_before_unload_dialog_ = true;
dialog_manager_ = delegate_->GetJavaScriptDialogManager(this);
dialog_manager_->RunBeforeUnloadDialog(
- this, message, is_reload,
+ this, is_reload,
base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID(), reply_msg,
@@ -3844,12 +3983,6 @@ bool WebContentsImpl::IsNeverVisible() {
return delegate_->IsNeverVisible(this);
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible WebContentsImpl::GetParentNativeViewAccessible() {
- return accessible_parent_;
-}
-#endif
-
RenderViewHostDelegateView* WebContentsImpl::GetDelegateView() {
return render_view_host_delegate_view_;
}
@@ -3889,13 +4022,6 @@ void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
Source<WebContents>(this),
Details<RenderViewHost>(render_view_host));
- NavigationEntry* entry = controller_.GetPendingEntry();
- if (entry && entry->IsViewSourceMode()) {
- // Put the renderer in view source mode.
- render_view_host->Send(
- new ViewMsg_EnableViewSourceMode(render_view_host->GetRoutingID()));
- }
-
view_->RenderViewCreated(render_view_host);
FOR_EACH_OBSERVER(
@@ -3940,7 +4066,7 @@ void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
// Ensure fullscreen mode is exited in the |delegate_| since a crashed
// renderer may not have made a clean exit.
if (IsFullscreenForCurrentTab(GetRenderViewHost()->GetWidget()))
- ExitFullscreenMode();
+ ExitFullscreenMode(false);
// Cancel any visible dialogs so they are not left dangling over the sad tab.
CancelActiveAndPendingDialogs();
@@ -3948,15 +4074,13 @@ void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
if (delegate_)
delegate_->HideValidationMessage(this);
- SetIsLoading(false, true, nullptr);
- NotifyDisconnected();
- SetIsCrashed(status, error_code);
-
// Reset the loading progress. TODO(avi): What does it mean to have a
// "renderer crash" when there is more than one renderer process serving a
// webpage? Once this function is called at a more granular frame level, we
// probably will need to more granularly reset the state here.
ResetLoadProgressState();
+ NotifyDisconnected();
+ SetIsCrashed(status, error_code);
FOR_EACH_OBSERVER(WebContentsObserver,
observers_,
@@ -4050,7 +4174,7 @@ void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) {
void WebContentsImpl::DidStartLoading(FrameTreeNode* frame_tree_node,
bool to_different_document) {
- SetIsLoading(true, to_different_document, nullptr);
+ LoadingStateChanged(to_different_document, false, nullptr);
// Notify accessibility that the user is navigating away from the
// current document.
@@ -4084,7 +4208,7 @@ void WebContentsImpl::DidStopLoading() {
controller_.GetCurrentEntryIndex()));
}
- SetIsLoading(false, true, details.get());
+ LoadingStateChanged(true, false, details.get());
}
void WebContentsImpl::DidChangeLoadProgress() {
@@ -4206,9 +4330,9 @@ void WebContentsImpl::UpdateTitle(RenderFrameHost* render_frame_host,
NavigationEntryImpl* entry = controller_.GetEntryWithPageID(
render_frame_host->GetSiteInstance(), page_id);
- NavigationEntryImpl* new_entry = controller_.GetEntryWithUniqueID(
- static_cast<RenderFrameHostImpl*>(render_frame_host)->nav_entry_id());
- DCHECK_EQ(entry, new_entry);
+ // TODO(creis): Find a way to use nav entry IDs to locate the entry to update,
+ // and intentionally skip updates when the most recent commit was ignored.
+ // See https://crbug.com/577449.
// We can handle title updates when we don't have an entry in
// UpdateTitleForEntry, but only if the update is from the current RVH.
@@ -4272,16 +4396,12 @@ void WebContentsImpl::EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) {
return;
}
- if (GetBrowserPluginGuest()) {
- // We create a swapped out RenderView or RenderFrameProxyHost for the
- // embedder in the guest's render process but we intentionally do not
- // expose the embedder's opener chain to it.
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- source_web_contents->GetRenderManager()->CreateRenderFrameProxy(
- GetSiteInstance());
- } else {
- source_web_contents->CreateSwappedOutRenderView(GetSiteInstance());
- }
+ if (this != source_web_contents && GetBrowserPluginGuest()) {
+ // We create a RenderFrameProxyHost for the embedder in the guest's render
+ // process but we intentionally do not expose the embedder's opener chain
+ // to it.
+ source_web_contents->GetRenderManager()->CreateRenderFrameProxy(
+ GetSiteInstance());
} else {
RenderFrameHostImpl* source_rfhi =
static_cast<RenderFrameHostImpl*>(source_rfh);
@@ -4301,36 +4421,24 @@ bool WebContentsImpl::AddMessageToConsole(int32_t level,
source_id);
}
-int WebContentsImpl::CreateSwappedOutRenderView(
- SiteInstance* instance) {
- int render_view_routing_id = MSG_ROUTING_NONE;
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- GetRenderManager()->CreateRenderFrameProxy(instance);
- } else {
- GetRenderManager()->CreateRenderFrame(
- instance, CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN,
- &render_view_routing_id);
- }
- return render_view_routing_id;
-}
-
-void WebContentsImpl::OnUserGesture(RenderWidgetHostImpl* render_widget_host) {
+void WebContentsImpl::OnUserInteraction(
+ RenderWidgetHostImpl* render_widget_host,
+ const blink::WebInputEvent::Type type) {
+ // Ignore when the renderer is swapped out.
+ // TODO(dominickn,creis): support widgets for out-of-process iframes.
if (render_widget_host != GetRenderViewHost()->GetWidget())
return;
- // Notify observers.
- FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetUserGesture());
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ DidGetUserInteraction(type));
ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
- if (rdh) // NULL in unittests.
+ // Exclude scroll events as user gestures for resource load dispatches.
+ // rdh is NULL in unittests.
+ if (rdh && type != blink::WebInputEvent::MouseWheel)
rdh->OnUserGesture(this);
}
-void WebContentsImpl::OnUserInteraction(const blink::WebInputEvent::Type type) {
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidGetUserInteraction(type));
-}
-
void WebContentsImpl::OnIgnoredUIEvent() {
// Notify observers.
FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetIgnoredUIEvent());
@@ -4338,6 +4446,9 @@ void WebContentsImpl::OnIgnoredUIEvent() {
void WebContentsImpl::RendererUnresponsive(
RenderWidgetHostImpl* render_widget_host) {
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ OnRendererUnresponsive(render_widget_host));
+
// Don't show hung renderer dialog for a swapped out RVH.
if (render_widget_host != GetRenderViewHost()->GetWidget())
return;
@@ -4404,9 +4515,7 @@ void WebContentsImpl::LoadStateChanged(
load_state_ = load_state;
upload_position_ = upload_position;
upload_size_ = upload_size;
- load_state_host_ = url_formatter::IDNToUnicode(
- url.host(),
- GetContentClient()->browser()->GetAcceptLangs(GetBrowserContext()));
+ load_state_host_ = url_formatter::IDNToUnicode(url.host());
if (load_state_.state == net::LOAD_STATE_READING_RESPONSE)
SetNotWaitingForResponse();
if (IsLoading()) {
@@ -4574,7 +4683,7 @@ bool WebContentsImpl::CreateRenderFrameForRenderManager(
return true;
}
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
WebContentsImpl::GetJavaWebContents() {
@@ -4614,14 +4723,14 @@ void WebContentsImpl::OnDidDownloadImage(
const ImageDownloadCallback& callback,
int id,
const GURL& image_url,
- image_downloader::DownloadResultPtr result) {
- const std::vector<SkBitmap> images =
- result->images.To<std::vector<SkBitmap>>();
- const std::vector<gfx::Size> original_image_sizes =
- result->original_image_sizes.To<std::vector<gfx::Size>>();
+ int32_t http_status_code,
+ mojo::Array<skia::mojom::BitmapPtr> images,
+ mojo::Array<mojo::SizePtr> original_image_sizes) {
+ const std::vector<SkBitmap> bitmaps = images.To<std::vector<SkBitmap>>();
+ const std::vector<gfx::Size> sizes =
+ original_image_sizes.To<std::vector<gfx::Size>>();
- callback.Run(id, result->http_status_code, image_url, images,
- original_image_sizes);
+ callback.Run(id, http_status_code, image_url, bitmaps, sizes);
}
void WebContentsImpl::OnDialogClosed(int render_process_id,
@@ -4635,11 +4744,12 @@ void WebContentsImpl::OnDialogClosed(int render_process_id,
last_dialog_suppressed_ = dialog_was_suppressed;
if (is_showing_before_unload_dialog_ && !success) {
- // If a beforeunload dialog is canceled, we need to stop the throbber from
- // spinning, since we forced it to start spinning in Navigate.
- if (rfh)
- DidStopLoading();
- controller_.DiscardNonCommittedEntries();
+ // It is possible for the current RenderFrameHost to have changed in the
+ // meantime. Do not reset the navigation state in that case.
+ if (rfh && rfh == rfh->frame_tree_node()->current_frame_host()) {
+ rfh->frame_tree_node()->BeforeUnloadCanceled();
+ controller_.DiscardNonCommittedEntries();
+ }
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
BeforeUnloadDialogCancelled());
@@ -4763,6 +4873,29 @@ void WebContentsImpl::MediaStoppedPlaying(
FOR_EACH_OBSERVER(WebContentsObserver, observers_, MediaStoppedPlaying(id));
}
+void WebContentsImpl::UpdateWebContentsVisibility(bool visible) {
+ if (!did_first_set_visible_) {
+ // If this WebContents has not yet been set to be visible for the first
+ // time, ignore any requests to make it hidden, since resources would
+ // immediately be destroyed and only re-created after content loaded. In
+ // this state the window content is undefined and can show garbage.
+ // However, the page load mechanism requires an activation call through a
+ // visibility call to (re)load.
+ if (visible) {
+ did_first_set_visible_ = true;
+ WasShown();
+ }
+ return;
+ }
+ if (visible == should_normally_be_visible_)
+ return;
+
+ if (visible)
+ WasShown();
+ else
+ WasHidden();
+}
+
void WebContentsImpl::SetJavaScriptDialogManagerForTesting(
JavaScriptDialogManager* dialog_manager) {
dialog_manager_ = dialog_manager;
diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h
index 5e0547168e3..bdf85b4c17e 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.h
+++ b/chromium/content/browser/web_contents/web_contents_impl.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <functional>
#include <map>
#include <set>
#include <string>
@@ -58,6 +59,7 @@ class DownloadItem;
class GeolocationServiceContext;
class InterstitialPageImpl;
class JavaScriptDialogManager;
+class LoaderIOThreadNotifier;
class ManifestManagerHost;
class MediaWebContentsObserver;
class PluginContentOriginWhitelist;
@@ -83,7 +85,7 @@ struct LoadNotificationDetails;
struct ResourceRedirectDetails;
struct ResourceRequestDetails;
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
class WebContentsAndroid;
#endif
@@ -118,12 +120,6 @@ class CONTENT_EXPORT WebContentsImpl
static WebContents* FromRenderFrameHostID(int render_process_host_id,
int render_frame_host_id);
- // Creates a swapped out RenderView. This is used by the browser plugin to
- // create a swapped out RenderView in the embedder render process for the
- // guest, to expose the guest's window object to the embedder.
- // This returns the routing ID of the newly created swapped out RenderView.
- int CreateSwappedOutRenderView(SiteInstance* instance);
-
// Complex initialization here. Specifically needed to avoid having
// members call back into our virtual functions in the constructor.
virtual void Init(const WebContents::CreateParams& params);
@@ -131,7 +127,7 @@ class CONTENT_EXPORT WebContentsImpl
// Returns the SavePackage which manages the page saving job. May be NULL.
SavePackage* save_package() const { return save_package_.get(); }
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
// In Android WebView, the RenderView needs created even there is no
// navigation entry, this allows Android WebViews to use
// javascript: URLs that load into the DOMWindow before the first page
@@ -244,6 +240,7 @@ class CONTENT_EXPORT WebContentsImpl
int frame_tree_node_id) override;
void ForEachFrame(
const base::Callback<void(RenderFrameHost*)>& on_frame) override;
+ std::vector<RenderFrameHost*> GetAllFrames() override;
int SendToAllFrames(IPC::Message* message) override;
RenderViewHostImpl* GetRenderViewHost() const override;
int GetRoutingID() const override;
@@ -260,10 +257,6 @@ class CONTENT_EXPORT WebContentsImpl
void EnableTreeOnlyAccessibilityMode() override;
bool IsTreeOnlyAccessibilityModeForTesting() const override;
bool IsFullAccessibilityModeForTesting() const override;
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) override;
-#endif
const PageImportanceSignals& GetPageImportanceSignals() const override;
const base::string16& GetTitle() const override;
int32_t GetMaxPageID() override;
@@ -284,9 +277,13 @@ class CONTENT_EXPORT WebContentsImpl
int GetCapturerCount() const override;
bool IsAudioMuted() const override;
void SetAudioMuted(bool mute) override;
+ void IncrementBluetoothConnectedDeviceCount();
+ void DecrementBluetoothConnectedDeviceCount();
+ bool IsConnectedToBluetoothDevice() const override;
bool IsCrashed() const override;
void SetIsCrashed(base::TerminationStatus status, int error_code) override;
base::TerminationStatus GetCrashedStatus() const override;
+ int GetCrashedErrorCode() const override;
bool IsBeingDestroyed() const override;
void NotifyNavigationStateChanged(InvalidateTypes changed_flags) override;
base::TimeTicks GetLastActiveTime() const override;
@@ -300,7 +297,7 @@ class CONTENT_EXPORT WebContentsImpl
RenderFrameHost* outer_contents_frame) override;
void Stop() override;
WebContents* Clone() override;
- void ReloadFocusedFrame(bool ignore_cache) override;
+ void ReloadFocusedFrame(bool bypass_cache) override;
void Undo() override;
void Redo() override;
void Cut() override;
@@ -315,6 +312,7 @@ class CONTENT_EXPORT WebContentsImpl
void ReplaceMisspelling(const base::string16& word) override;
void NotifyContextMenuClosed(
const CustomContextMenuContext& context) override;
+ void ReloadLoFiImages() override;
void ExecuteCustomContextMenuCommand(
int action,
const CustomContextMenuContext& context) override;
@@ -377,17 +375,16 @@ class CONTENT_EXPORT WebContentsImpl
bool WasRecentlyAudible() override;
void GetManifest(const GetManifestCallback& callback) override;
void HasManifest(const HasManifestCallback& callback) override;
- void ExitFullscreen() override;
+ void ExitFullscreen(bool will_cause_resize) override;
void ResumeLoadingCreatedWebContents() override;
-#if defined(OS_ANDROID)
void OnMediaSessionStateChanged();
void ResumeMediaSession() override;
void SuspendMediaSession() override;
void StopMediaSession() override;
-#if !defined(USE_AURA)
+
+#if defined(OS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override;
virtual WebContentsAndroid* GetWebContentsAndroid();
-#endif // !USE_AURA
#elif defined(OS_MACOSX)
void SetAllowOtherViews(bool allow) override;
bool GetAllowOtherViews() override;
@@ -415,7 +412,6 @@ class CONTENT_EXPORT WebContentsImpl
JavaScriptMessageType type,
IPC::Message* reply_msg) override;
void RunBeforeUnloadConfirm(RenderFrameHost* render_frame_host,
- const base::string16& message,
bool is_reload,
IPC::Message* reply_msg) override;
void DidAccessInitialDocument() override;
@@ -441,15 +437,12 @@ class CONTENT_EXPORT WebContentsImpl
GeolocationServiceContext* GetGeolocationServiceContext() override;
WakeLockServiceContext* GetWakeLockServiceContext() override;
void EnterFullscreenMode(const GURL& origin) override;
- void ExitFullscreenMode() override;
+ void ExitFullscreenMode(bool will_cause_resize) override;
bool ShouldRouteMessageEvent(
RenderFrameHost* target_rfh,
SiteInstance* source_site_instance) const override;
void EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) override;
scoped_ptr<WebUIImpl> CreateWebUIForRenderFrameHost(const GURL& url) override;
-#if defined(OS_WIN)
- gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
-#endif
// RenderViewHostDelegate ----------------------------------------------------
RenderViewHostDelegateView* GetDelegateView() override;
@@ -480,7 +473,8 @@ class CONTENT_EXPORT WebContentsImpl
const base::string16& source_id) override;
RendererPreferences GetRendererPrefs(
BrowserContext* browser_context) const override;
- void OnUserInteraction(const blink::WebInputEvent::Type type) override;
+ void OnUserInteraction(RenderWidgetHostImpl* render_widget_host,
+ const blink::WebInputEvent::Type type) override;
void OnIgnoredUIEvent() override;
void LoadStateChanged(const GURL& url,
const net::LoadStateWithParam& load_state,
@@ -580,9 +574,7 @@ class CONTENT_EXPORT WebContentsImpl
bool* is_keyboard_shortcut) override;
void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
bool HandleWheelEvent(const blink::WebMouseWheelEvent& event) override;
- void OnUserGesture(RenderWidgetHostImpl* render_widget_host) override;
bool PreHandleGestureEvent(const blink::WebGestureEvent& event) override;
- void DidSendScreenRects(RenderWidgetHostImpl* rwh) override;
BrowserAccessibilityManager* GetRootBrowserAccessibilityManager() override;
BrowserAccessibilityManager* GetOrCreateRootBrowserAccessibilityManager()
override;
@@ -614,6 +606,8 @@ class CONTENT_EXPORT WebContentsImpl
void LostMouseLock(RenderWidgetHostImpl* render_widget_host) override;
void ForwardCompositorProto(RenderWidgetHostImpl* render_widget_host,
const std::vector<uint8_t>& proto) override;
+ void OnRenderFrameProxyVisibilityChanged(bool visible) override;
+ void SendScreenRects() override;
// RenderFrameHostManager::Delegate ------------------------------------------
@@ -704,12 +698,8 @@ class CONTENT_EXPORT WebContentsImpl
// Unsets the currently showing interstitial.
void DetachInterstitialPage() override;
- // Changes the IsLoading state and notifies the delegate as needed.
- // |details| is used to provide details on the load that just finished
- // (but can be null if not applicable).
- void SetIsLoading(bool is_loading,
- bool to_different_document,
- LoadNotificationDetails* details) override;
+ // Unpause the throbber if it was paused.
+ void DidProceedOnInterstitial() override;
typedef base::Callback<void(WebContents*)> CreatedCallback;
@@ -729,6 +719,9 @@ class CONTENT_EXPORT WebContentsImpl
return media_web_contents_observer_.get();
}
+ // Update the web contents visibility.
+ void UpdateWebContentsVisibility(bool visible);
+
private:
friend class WebContentsObserver;
friend class WebContents; // To implement factory methods.
@@ -753,6 +746,8 @@ class CONTENT_EXPORT WebContentsImpl
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrossSiteIframe);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessAccessibilityBrowserTest,
CrossSiteIframeAccessibility);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+ JavaScriptDialogsInMainAndSubframes);
// So InterstitialPageImpl can access SetIsLoading.
friend class InterstitialPageImpl;
@@ -823,7 +818,9 @@ class CONTENT_EXPORT WebContentsImpl
void OnDidDownloadImage(const ImageDownloadCallback& callback,
int id,
const GURL& image_url,
- image_downloader::DownloadResultPtr result);
+ int32_t http_status_code,
+ mojo::Array<skia::mojom::BitmapPtr> images,
+ mojo::Array<mojo::SizePtr> original_image_sizes);
// Callback function when showing JavaScript dialogs. Takes in a routing ID
// pair to identify the RenderFrameHost that opened the dialog, because it's
@@ -879,7 +876,7 @@ class CONTENT_EXPORT WebContentsImpl
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
void OnFindMatchRectsReply(int version,
const std::vector<gfx::RectF>& rects,
const gfx::RectF& active_rect);
@@ -976,6 +973,9 @@ class CONTENT_EXPORT WebContentsImpl
// called once as this call also removes it from the internal map.
WebContentsImpl* GetCreatedWindow(int route_id);
+ // Sends a Page message IPC.
+ void SendPageMessage(IPC::Message* msg);
+
// Tracking loading progress -------------------------------------------------
// Resets the tracking state of the current load progress.
@@ -984,6 +984,15 @@ class CONTENT_EXPORT WebContentsImpl
// Notifies the delegate that the load progress was updated.
void SendChangeLoadProgress();
+ // Notifies the delegate of a change in loading state.
+ // |details| is used to provide details on the load that just finished
+ // (but can be null if not applicable).
+ // |due_to_interstitial| is true if the change in load state occurred because
+ // an interstitial page started showing/proceeded.
+ void LoadingStateChanged(bool to_different_document,
+ bool due_to_interstitial,
+ LoadNotificationDetails* details);
+
// Misc non-view stuff -------------------------------------------------------
// Sets the history for a specified RenderViewHost to |history_length|
@@ -1064,10 +1073,6 @@ class CONTENT_EXPORT WebContentsImpl
// is closed.
bool created_with_opener_;
-#if defined(OS_WIN)
- gfx::NativeViewAccessible accessible_parent_;
-#endif
-
// Helper classes ------------------------------------------------------------
// Manages the frame tree of the page and process swaps in each node.
@@ -1082,9 +1087,6 @@ class CONTENT_EXPORT WebContentsImpl
// Data for loading state ----------------------------------------------------
- // Indicates whether we're currently loading a resource.
- bool is_loading_;
-
// Indicates whether the current load is to a different document. Only valid
// if is_loading_ is true.
bool is_load_to_different_document_;
@@ -1161,6 +1163,12 @@ class CONTENT_EXPORT WebContentsImpl
// Tracks whether RWHV should be visible once capturer_count_ becomes zero.
bool should_normally_be_visible_;
+ // Tracks whether this WebContents was ever set to be visible. Used to
+ // facilitate WebContents being loaded in the background by setting
+ // |should_normally_be_visible_|. Ensures WasShown() will trigger when first
+ // becoming visible to the user, and prevents premature unloading.
+ bool did_first_set_visible_;
+
// See getter above.
bool is_being_destroyed_;
@@ -1203,7 +1211,7 @@ class CONTENT_EXPORT WebContentsImpl
// this overrides |preferred_size_|.
gfx::Size preferred_size_for_capture_;
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if defined(OS_ANDROID)
// Date time chooser opened by this tab.
// Only used in Android since all other platforms use a multi field UI.
scoped_ptr<DateTimeChooserAndroid> date_time_chooser_;
@@ -1303,8 +1311,13 @@ class CONTENT_EXPORT WebContentsImpl
// Created on-demand to mute all audio output from this WebContents.
scoped_ptr<WebContentsAudioMuter> audio_muter_;
+ size_t bluetooth_connected_device_count_;
+
bool virtual_keyboard_requested_;
+ // Notifies ResourceDispatcherHostImpl of various events related to loading.
+ scoped_ptr<LoaderIOThreadNotifier> loader_io_thread_notifier_;
+
// Manages media players, CDMs, and power save blockers for media.
scoped_ptr<MediaWebContentsObserver> media_web_contents_observer_;
diff --git a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
index 532cf018ff7..6534b140d49 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -11,6 +11,8 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view.h"
#include "content/common/frame_messages.h"
+#include "content/common/site_isolation_policy.h"
+#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/load_notification_details.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_details.h"
@@ -18,6 +20,7 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/url_constants.h"
@@ -27,6 +30,7 @@
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -108,8 +112,13 @@ class NavigateOnCommitObserver : public WebContentsObserver {
const LoadCommittedDetails& load_details) override {
if (!done_) {
done_ = true;
- shell_->Stop();
shell_->LoadURL(url_);
+
+ // There should be a pending entry.
+ CHECK(shell_->web_contents()->GetController().GetPendingEntry());
+
+ // Now that there is a pending entry, stop the load.
+ shell_->Stop();
}
}
@@ -189,16 +198,8 @@ class LoadingStateChangedDelegate : public WebContentsDelegate {
int loadingStateToDifferentDocumentCount_;
};
-// See: http://crbug.com/298193
-#if defined(OS_WIN) || defined(OS_LINUX)
-#define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
-#else
-#define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
-#endif
-
// Test that DidStopLoading includes the correct URL in the details.
-IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
- MAYBE_DidStopLoadingDetails) {
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, DidStopLoadingDetails) {
ASSERT_TRUE(embedded_test_server()->Start());
LoadStopNotificationObserver load_observer(
@@ -212,20 +213,15 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
load_observer.controller_);
}
-// See: http://crbug.com/298193
-#if defined(OS_WIN) || defined(OS_LINUX)
-#define MAYBE_DidStopLoadingDetailsWithPending \
- DISABLED_DidStopLoadingDetailsWithPending
-#else
-#define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending
-#endif
-
// Test that DidStopLoading includes the correct URL in the details when a
// pending entry is present.
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
- MAYBE_DidStopLoadingDetailsWithPending) {
+ DidStopLoadingDetailsWithPending) {
ASSERT_TRUE(embedded_test_server()->Start());
- GURL url("data:text/html,<div>test</div>");
+ // TODO(clamy): Add a cross-process navigation case as well once
+ // crbug.com/581024 is fixed.
+ GURL url1 = embedded_test_server()->GetURL("/title1.html");
+ GURL url2 = embedded_test_server()->GetURL("/title2.html");
// Listen for the first load to stop.
LoadStopNotificationObserver load_observer(
@@ -233,12 +229,11 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
// Start a new pending navigation as soon as the first load commits.
// We will hear a DidStopLoading from the first load as the new load
// is started.
- NavigateOnCommitObserver commit_observer(
- shell(), embedded_test_server()->GetURL("/title2.html"));
- NavigateToURL(shell(), url);
+ NavigateOnCommitObserver commit_observer(shell(), url2);
+ NavigateToURL(shell(), url1);
load_observer.Wait();
- EXPECT_EQ(url, load_observer.url_);
+ EXPECT_EQ(url1, load_observer.url_);
EXPECT_EQ(0, load_observer.session_index_);
EXPECT_EQ(&shell()->web_contents()->GetController(),
load_observer.controller_);
@@ -606,19 +601,21 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
// Simulate a navigation that has not completed.
+ const GURL kURL2 = embedded_test_server()->GetURL("/title2.html");
+ NavigationStallDelegate stall_delegate(kURL2);
+ ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
scoped_ptr<LoadProgressDelegateAndObserver> delegate(
new LoadProgressDelegateAndObserver(shell()));
- RenderFrameHost* main_frame = shell()->web_contents()->GetMainFrame();
- FrameHostMsg_DidStartLoading start_msg(main_frame->GetRoutingID(), true);
- static_cast<RenderFrameHostImpl*>(main_frame)->OnMessageReceived(start_msg);
+ shell()->LoadURL(kURL2);
EXPECT_TRUE(delegate->did_start_loading);
EXPECT_FALSE(delegate->did_stop_loading);
// Also simulate a DidChangeLoadProgress, but not a DidStopLoading.
+ RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
FrameHostMsg_DidChangeLoadProgress progress_msg(main_frame->GetRoutingID(),
1.0);
- static_cast<RenderFrameHostImpl*>(main_frame)->OnMessageReceived(
- progress_msg);
+ main_frame->OnMessageReceived(progress_msg);
EXPECT_TRUE(delegate->did_start_loading);
EXPECT_FALSE(delegate->did_stop_loading);
@@ -631,6 +628,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
// We should have gotten to DidStopLoading.
EXPECT_TRUE(delegate->did_stop_loading);
+
+ ResourceDispatcherHost::Get()->SetDelegate(nullptr);
}
struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
@@ -818,4 +817,197 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, NewNamedWindow) {
}
}
+// TODO(clamy): Make the test work on Windows and on Mac. On Mac and Windows,
+// there seem to be an issue with the ShellJavascriptDialogManager.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_NoResetOnBeforeUnloadCanceledOnCommit \
+ DISABLED_NoResetOnBeforeUnloadCanceledOnCommit
+#else
+#define MAYBE_NoResetOnBeforeUnloadCanceledOnCommit \
+ NoResetOnBeforeUnloadCanceledOnCommit
+#endif
+// Test that if a BeforeUnload dialog is destroyed due to the commit of a
+// cross-site navigation, it will not reset the loading state.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ MAYBE_NoResetOnBeforeUnloadCanceledOnCommit) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ const GURL kStartURL(
+ embedded_test_server()->GetURL("/hang_before_unload.html"));
+ const GURL kCrossSiteURL(
+ embedded_test_server()->GetURL("bar.com", "/title1.html"));
+
+ // Navigate to a first web page with a BeforeUnload event listener.
+ EXPECT_TRUE(NavigateToURL(shell(), kStartURL));
+
+ // Start a cross-site navigation that will not commit for the moment.
+ TestNavigationManager cross_site_delayer(shell()->web_contents(),
+ kCrossSiteURL);
+ shell()->LoadURL(kCrossSiteURL);
+ cross_site_delayer.WaitForWillStartRequest();
+
+ // Click on a link in the page. This will show the BeforeUnload dialog.
+ // Ensure the dialog is not dismissed, which will cause it to still be
+ // present when the cross-site navigation later commits.
+ // Note: the javascript function executed will not do the link click but
+ // schedule it for afterwards. Since the BeforeUnload event is synchronous,
+ // clicking on the link right away would cause the ExecuteScript to never
+ // return.
+ SetShouldProceedOnBeforeUnload(shell(), false);
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), "clickLinkSoon()"));
+ WaitForAppModalDialog(shell());
+
+ // Have the cross-site navigation commit. The main RenderFrameHost should
+ // still be loading after that.
+ cross_site_delayer.ResumeNavigation();
+ cross_site_delayer.WaitForNavigationFinished();
+ EXPECT_TRUE(shell()->web_contents()->IsLoading());
+}
+
+namespace {
+
+class TestJavaScriptDialogManager : public JavaScriptDialogManager,
+ public WebContentsDelegate {
+ public:
+ TestJavaScriptDialogManager() : message_loop_runner_(new MessageLoopRunner) {}
+ ~TestJavaScriptDialogManager() override {}
+
+ void Wait() {
+ message_loop_runner_->Run();
+ message_loop_runner_ = new MessageLoopRunner;
+ }
+
+ std::string last_message() { return last_message_; }
+
+ // WebContentsDelegate
+
+ JavaScriptDialogManager* GetJavaScriptDialogManager(
+ WebContents* source) override {
+ return this;
+ }
+
+ // JavaScriptDialogManager
+
+ void RunJavaScriptDialog(WebContents* web_contents,
+ const GURL& origin_url,
+ JavaScriptMessageType javascript_message_type,
+ const base::string16& message_text,
+ const base::string16& default_prompt_text,
+ const DialogClosedCallback& callback,
+ bool* did_suppress_message) override {
+ last_message_ = base::UTF16ToUTF8(message_text);
+ *did_suppress_message = true;
+
+ message_loop_runner_->Quit();
+ };
+
+ void RunBeforeUnloadDialog(WebContents* web_contents,
+ bool is_reload,
+ const DialogClosedCallback& callback) override {}
+
+ bool HandleJavaScriptDialog(WebContents* web_contents,
+ bool accept,
+ const base::string16* prompt_override) override {
+ return true;
+ }
+
+ void CancelActiveAndPendingDialogs(WebContents* web_contents) override {}
+
+ void ResetDialogState(WebContents* web_contents) override {}
+
+ private:
+ std::string last_message_;
+
+ // The MessageLoopRunner used to spin the message loop.
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ JavaScriptDialogsInMainAndSubframes) {
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+ TestJavaScriptDialogManager dialog_manager;
+ wc->SetDelegate(&dialog_manager);
+
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ NavigateToURL(shell(),
+ embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(WaitForLoadStop(wc));
+
+ FrameTreeNode* root = wc->GetFrameTree()->root();
+ ASSERT_EQ(0U, root->child_count());
+
+ std::string script =
+ "var iframe = document.createElement('iframe');"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* frame = root->child_at(0);
+ ASSERT_NE(nullptr, frame);
+
+ url::Replacements<char> clear_port;
+ clear_port.ClearPort();
+
+ // A dialog from the main frame.
+ std::string alert_location = "alert(document.location)";
+ EXPECT_TRUE(
+ content::ExecuteScript(root->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ(GURL("http://a.com/title1.html"),
+ GURL(dialog_manager.last_message()).ReplaceComponents(clear_port));
+
+ // A dialog from the subframe.
+ EXPECT_TRUE(
+ content::ExecuteScript(frame->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ("about:blank", dialog_manager.last_message());
+
+ // Navigate the subframe cross-site.
+ NavigateFrameToURL(frame,
+ embedded_test_server()->GetURL("b.com", "/title2.html"));
+ EXPECT_TRUE(WaitForLoadStop(wc));
+
+ // A dialog from the subframe.
+ EXPECT_TRUE(
+ content::ExecuteScript(frame->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ(GURL("http://b.com/title2.html"),
+ GURL(dialog_manager.last_message()).ReplaceComponents(clear_port));
+
+ // A dialog from the main frame.
+ EXPECT_TRUE(
+ content::ExecuteScript(root->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ(GURL("http://a.com/title1.html"),
+ GURL(dialog_manager.last_message()).ReplaceComponents(clear_port));
+
+ // Navigate the top frame cross-site; ensure that dialogs work.
+ NavigateToURL(shell(),
+ embedded_test_server()->GetURL("c.com", "/title3.html"));
+ EXPECT_TRUE(WaitForLoadStop(wc));
+ EXPECT_TRUE(
+ content::ExecuteScript(root->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ(GURL("http://c.com/title3.html"),
+ GURL(dialog_manager.last_message()).ReplaceComponents(clear_port));
+
+ // Navigate back; ensure that dialogs work.
+ wc->GetController().GoBack();
+ EXPECT_TRUE(WaitForLoadStop(wc));
+ EXPECT_TRUE(
+ content::ExecuteScript(root->current_frame_host(), alert_location));
+ dialog_manager.Wait();
+ EXPECT_EQ(GURL("http://a.com/title1.html"),
+ GURL(dialog_manager.last_message()).ReplaceComponents(clear_port));
+
+ wc->SetDelegate(nullptr);
+ wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
index 4d1e2e6f026..ef96953682c 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -23,6 +23,7 @@
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/common/frame_messages.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/common/media/media_player_delegate_messages.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
#include "content/public/browser/global_request_id.h"
@@ -40,6 +41,7 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_utils.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_content_client.h"
@@ -50,6 +52,7 @@
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "url/url_constants.h"
namespace content {
namespace {
@@ -352,12 +355,14 @@ class FakeValidationMessageDelegate : public WebContentsDelegate {
TEST_F(WebContentsImplTest, UpdateTitle) {
NavigationControllerImpl& cont =
static_cast<NavigationControllerImpl&>(controller());
+ cont.LoadURL(GURL(url::kAboutBlankURL), Referrer(), ui::PAGE_TRANSITION_TYPED,
+ std::string());
+
FrameHostMsg_DidCommitProvisionalLoad_Params params;
InitNavigateParams(&params, 0, 0, true, GURL(url::kAboutBlankURL),
ui::PAGE_TRANSITION_TYPED);
- LoadCommittedDetails details;
- cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
contents()->UpdateTitle(contents()->GetMainFrame(), 0,
base::ASCIIToUTF16(" Lots O' Whitespace\n"),
@@ -411,16 +416,15 @@ TEST_F(WebContentsImplTest, NTPViewSource) {
cont.LoadURL(
kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
int entry_id = cont.GetPendingEntry()->GetUniqueID();
- rvh()->GetDelegate()->RenderViewCreated(rvh());
// Did we get the expected message?
EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
- ViewMsg_EnableViewSourceMode::ID));
+ FrameMsg_EnableViewSourceMode::ID));
FrameHostMsg_DidCommitProvisionalLoad_Params params;
InitNavigateParams(&params, 0, entry_id, true, kGURL,
ui::PAGE_TRANSITION_TYPED);
- LoadCommittedDetails details;
- cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
+ contents()->GetMainFrame()->PrepareForCommit();
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
// Also check title and url.
EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
}
@@ -487,7 +491,7 @@ TEST_F(WebContentsImplTest, SimpleNavigation) {
TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
// Construct a URL that's kMaxURLChars + 1 long of all 'a's.
const GURL url(std::string("http://example.org/").append(
- kMaxURLChars + 1, 'a'));
+ url::kMaxURLChars + 1, 'a'));
controller().LoadURL(
url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
@@ -545,6 +549,7 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
+ EXPECT_TRUE(pending_rfh->GetLastCommittedURL().is_empty());
int pending_rvh_delete_count = 0;
pending_rfh->GetRenderViewHost()->set_delete_counter(
&pending_rvh_delete_count);
@@ -585,10 +590,6 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
if (IsBrowserSideNavigationEnabled())
contents()->GetMainFrame()->PrepareForCommit();
TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
- if (!SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- // Recycling the rfh is a behavior specific to swappedout://
- EXPECT_EQ(orig_rfh, goback_rfh);
- }
EXPECT_TRUE(contents()->CrossProcessNavigationPending());
// Navigations should be suspended in goback_rfh until BeforeUnloadACK.
@@ -971,20 +972,15 @@ TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
popup->GetRenderManager()->GetOpenerRoutingID(instance);
RenderFrameProxyHost* proxy =
contents()->GetRenderManager()->GetRenderFrameProxyHost(instance);
- if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
- EXPECT_TRUE(proxy);
- EXPECT_EQ(proxy->GetRoutingID(), opener_frame_routing_id);
-
- // Ensure that committing the navigation removes the proxy.
- int entry_id = controller().GetPendingEntry()->GetUniqueID();
- contents()->TestDidNavigate(pending_rfh, 2, entry_id, true, url2,
- ui::PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(
- contents()->GetRenderManager()->GetRenderFrameProxyHost(instance));
- } else {
- EXPECT_FALSE(proxy);
- EXPECT_EQ(pending_rfh->GetRoutingID(), opener_frame_routing_id);
- }
+ EXPECT_TRUE(proxy);
+ EXPECT_EQ(proxy->GetRoutingID(), opener_frame_routing_id);
+
+ // Ensure that committing the navigation removes the proxy.
+ entry_id = controller().GetPendingEntry()->GetUniqueID();
+ contents()->TestDidNavigate(pending_rfh, 2, entry_id, true, url2,
+ ui::PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(
+ contents()->GetRenderManager()->GetRenderFrameProxyHost(instance));
}
// Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
@@ -1399,6 +1395,7 @@ TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
int entry1_id = controller().GetPendingEntry()->GetUniqueID();
TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+ orig_rfh->PrepareForCommit();
EXPECT_FALSE(contents()->CrossProcessNavigationPending());
// Navigate to new site, with the beforeunload request in flight.
@@ -3044,7 +3041,6 @@ TEST_F(WebContentsImplTestWithSiteIsolation, StartStopEventsBalance) {
controller().LoadURL(
main_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
int entry_id = controller().GetPendingEntry()->GetUniqueID();
- orig_rfh->PrepareForCommit();
orig_rfh->OnMessageReceived(
FrameHostMsg_DidStartLoading(orig_rfh->GetRoutingID(), false));
contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, main_url,
@@ -3060,7 +3056,6 @@ TEST_F(WebContentsImplTestWithSiteIsolation, StartStopEventsBalance) {
// Navigate the child frame to about:blank, which will send both
// DidStartLoading and DidStopLoading messages.
{
- subframe->SendRendererInitiatedNavigationRequest(initial_url, false);
subframe->OnMessageReceived(
FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
subframe->SendNavigateWithTransition(1, 0, false, initial_url,
@@ -3200,9 +3195,7 @@ TEST_F(WebContentsImplTest, NoEarlyStop) {
}
TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
- // PlayerIDs are actually pointers cast to int64_t, so verify that both
- // negative
- // and positive player ids don't blow up.
+ // Verify that both negative and positive player ids don't blow up.
const int kPlayerAudioVideoId = 15;
const int kPlayerAudioOnlyId = -15;
const int kPlayerVideoOnlyId = 30;
@@ -3236,8 +3229,8 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
// Start a player with both audio and video. A video power save blocker
// should be created. If audio stream monitoring is available, an audio power
// save blocker should be created too.
- rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
- 0, kPlayerAudioVideoId, true, true, false));
+ rfh->OnMessageReceived(MediaPlayerDelegateHostMsg_OnMediaPlaying(
+ 0, kPlayerAudioVideoId, true, true, false, base::TimeDelta()));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
@@ -3249,8 +3242,8 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
// Start another player that only has video. There should be no change in
// the power save blockers. The notification should take into account the
// visibility state of the WebContents.
- rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
- 0, kPlayerVideoOnlyId, true, false, false));
+ rfh->OnMessageReceived(MediaPlayerDelegateHostMsg_OnMediaPlaying(
+ 0, kPlayerVideoOnlyId, true, false, false, base::TimeDelta()));
EXPECT_FALSE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
@@ -3261,16 +3254,16 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
// Start another player that only has audio. There should be no change in
// the power save blockers.
- rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
- 0, kPlayerAudioOnlyId, false, true, false));
+ rfh->OnMessageReceived(MediaPlayerDelegateHostMsg_OnMediaPlaying(
+ 0, kPlayerAudioOnlyId, false, true, false, base::TimeDelta()));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
// Start a remote player. There should be no change in the power save
// blockers.
- rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
- 0, kPlayerRemoteId, true, true, true));
+ rfh->OnMessageReceived(MediaPlayerDelegateHostMsg_OnMediaPlaying(
+ 0, kPlayerRemoteId, true, true, true, base::TimeDelta()));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
@@ -3278,34 +3271,34 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
// Destroy the original audio video player. Both power save blockers should
// remain.
rfh->OnMessageReceived(
- FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
+ MediaPlayerDelegateHostMsg_OnMediaPaused(0, kPlayerAudioVideoId, false));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
// Destroy the audio only player. The video power save blocker should remain.
rfh->OnMessageReceived(
- FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
+ MediaPlayerDelegateHostMsg_OnMediaPaused(0, kPlayerAudioOnlyId, false));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_FALSE(has_audio_power_save_blocker());
// Destroy the video only player. No power save blockers should remain.
rfh->OnMessageReceived(
- FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
+ MediaPlayerDelegateHostMsg_OnMediaPaused(0, kPlayerVideoOnlyId, false));
EXPECT_FALSE(has_video_power_save_blocker());
EXPECT_FALSE(has_audio_power_save_blocker());
// Destroy the remote player. No power save blockers should remain.
rfh->OnMessageReceived(
- FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
+ MediaPlayerDelegateHostMsg_OnMediaPaused(0, kPlayerRemoteId, false));
EXPECT_FALSE(has_video_power_save_blocker());
EXPECT_FALSE(has_audio_power_save_blocker());
// Start a player with both audio and video. A video power save blocker
// should be created. If audio stream monitoring is available, an audio power
// save blocker should be created too.
- rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
- 0, kPlayerAudioVideoId, true, true, false));
+ rfh->OnMessageReceived(MediaPlayerDelegateHostMsg_OnMediaPlaying(
+ 0, kPlayerAudioVideoId, true, true, false, base::TimeDelta()));
EXPECT_TRUE(has_video_power_save_blocker());
EXPECT_EQ(has_audio_power_save_blocker(),
!AudioStreamMonitor::monitoring_available());
@@ -3321,6 +3314,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
TEST_F(WebContentsImplTest, ThemeColorChangeDependingOnFirstVisiblePaint) {
TestWebContentsObserver observer(contents());
TestRenderFrameHost* rfh = contents()->GetMainFrame();
+ rfh->InitializeRenderFrameIfNeeded();
SkColor transparent = SK_ColorTRANSPARENT;
@@ -3371,6 +3365,9 @@ TEST_F(WebContentsImplTest, LoadResourceFromMemoryCacheWithBadSecurityInfo) {
// does not mistakenly think it has seen a good certificate and thus forget any
// user exceptions for that host. See https://crbug.com/516808.
TEST_F(WebContentsImplTest, LoadResourceFromMemoryCacheWithEmptySecurityInfo) {
+ WebContentsImplTestBrowserClient browser_client;
+ SetBrowserClientForTesting(&browser_client);
+
scoped_refptr<net::X509Certificate> cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
SSLPolicyBackend* backend = contents()->controller_.ssl_manager()->backend();
@@ -3383,8 +3380,12 @@ TEST_F(WebContentsImplTest, LoadResourceFromMemoryCacheWithEmptySecurityInfo) {
RESOURCE_TYPE_MAIN_FRAME);
EXPECT_TRUE(backend->HasAllowException(test_url.host()));
+
+ DeleteContents();
}
+namespace {
+
class TestJavaScriptDialogManager : public JavaScriptDialogManager {
public:
TestJavaScriptDialogManager() {}
@@ -3396,7 +3397,6 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager {
void RunJavaScriptDialog(WebContents* web_contents,
const GURL& origin_url,
- const std::string& accept_lang,
JavaScriptMessageType javascript_message_type,
const base::string16& message_text,
const base::string16& default_prompt_text,
@@ -3406,7 +3406,6 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager {
};
void RunBeforeUnloadDialog(WebContents* web_contents,
- const base::string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) override {}
@@ -3426,26 +3425,23 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager {
DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
};
+} // namespace
+
TEST_F(WebContentsImplTest, ResetJavaScriptDialogOnUserNavigate) {
- scoped_ptr<TestJavaScriptDialogManager> delegate(
- new TestJavaScriptDialogManager());
- contents()->SetJavaScriptDialogManagerForTesting(delegate.get());
+ TestJavaScriptDialogManager dialog_manager;
+ contents()->SetJavaScriptDialogManagerForTesting(&dialog_manager);
// A user-initiated navigation.
-
- contents()->GetMainFrame()->PrepareForCommit();
contents()->TestDidNavigate(contents()->GetMainFrame(), 1, 0, true,
GURL("about:whatever"),
ui::PAGE_TRANSITION_TYPED);
- EXPECT_EQ(1u, delegate->reset_count());
+ EXPECT_EQ(1u, dialog_manager.reset_count());
// An automatic navigation.
-
- contents()->GetMainFrame()->PrepareForCommit();
contents()->GetMainFrame()->SendNavigateWithModificationCallback(
2, 0, true, GURL(url::kAboutBlankURL), base::Bind(SetAsNonUserGesture));
- EXPECT_EQ(1u, delegate->reset_count());
+ EXPECT_EQ(1u, dialog_manager.reset_count());
contents()->SetJavaScriptDialogManagerForTesting(nullptr);
}
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura.cc b/chromium/content/browser/web_contents/web_contents_view_aura.cc
index a899bf33104..7053c50b576 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.cc
@@ -91,8 +91,10 @@ bool IsScrollEndEffectEnabled() {
RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
RenderWidgetHostView* view) {
- if (!view || RenderViewHostFactory::has_factory())
+ if (!view || (RenderViewHostFactory::has_factory() &&
+ !RenderViewHostFactory::is_real_render_view_host())) {
return NULL; // Can't cast to RenderWidgetHostViewAura in unit tests.
+ }
RenderViewHost* rvh = RenderViewHost::From(view->GetRenderWidgetHost());
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
@@ -236,7 +238,7 @@ const ui::Clipboard::FormatType& GetFileSystemFileFormatType() {
void WriteFileSystemFilesToPickle(
const std::vector<DropData::FileSystemFileInfo>& file_system_files,
base::Pickle* pickle) {
- pickle->WriteSizeT(file_system_files.size());
+ pickle->WriteUInt32(file_system_files.size());
for (size_t i = 0; i < file_system_files.size(); ++i) {
pickle->WriteString(file_system_files[i].url.spec());
pickle->WriteInt64(file_system_files[i].size);
@@ -249,12 +251,12 @@ bool ReadFileSystemFilesFromPickle(
std::vector<DropData::FileSystemFileInfo>* file_system_files) {
base::PickleIterator iter(pickle);
- size_t num_files = 0;
- if (!iter.ReadSizeT(&num_files))
+ uint32_t num_files = 0;
+ if (!iter.ReadUInt32(&num_files))
return false;
file_system_files->resize(num_files);
- for (size_t i = 0; i < num_files; ++i) {
+ for (uint32_t i = 0; i < num_files; ++i) {
std::string url_string;
int64_t size = 0;
if (!iter.ReadString(&url_string) || !iter.ReadInt64(&size))
@@ -404,11 +406,6 @@ class WebContentsViewAura::WindowObserver
: view_(view),
host_window_(NULL) {
view_->window_->AddObserver(this);
-
-#if defined(OS_WIN)
- if (view_->window_->GetRootWindow())
- view_->window_->GetRootWindow()->AddObserver(this);
-#endif
}
~WindowObserver() override {
@@ -417,64 +414,8 @@ class WebContentsViewAura::WindowObserver
view_->window_->GetHost()->RemoveObserver(this);
if (host_window_)
host_window_->RemoveObserver(this);
-#if defined(OS_WIN)
- if (host_window_) {
- const aura::Window::Windows& children = host_window_->children();
- for (size_t i = 0; i < children.size(); ++i)
- children[i]->RemoveObserver(this);
- }
-
- aura::Window* root_window = view_->window_->GetRootWindow();
- if (root_window) {
- root_window->RemoveObserver(this);
- const aura::Window::Windows& root_children = root_window->children();
- for (size_t i = 0; i < root_children.size(); ++i)
- root_children[i]->RemoveObserver(this);
- }
-#endif
}
-#if defined(OS_WIN)
- // Constrained windows are added as children of the parent's parent's view
- // which may overlap with windowed NPAPI plugins. In that case, tell the RWHV
- // so that it can update the plugins' cutout rects accordingly.
- // Note: this is hard coding how Chrome layer adds its dialogs. Since NPAPI is
- // going to be deprecated in a year, this is ok for now. The test for this is
- // PrintPreviewTest.WindowedNPAPIPluginHidden.
- void OnWindowAdded(aura::Window* new_window) override {
- if (!new_window->Contains(view_->window_.get())) {
- // Skip the case when the parent moves to the root window.
- if (new_window != host_window_) {
- // Observe sibling windows of the WebContents, or children of the root
- // window.
- if (new_window->parent() == host_window_ ||
- new_window->parent() == view_->window_->GetRootWindow()) {
- new_window->AddObserver(this);
- }
- }
- }
-
- if (new_window->parent() == host_window_) {
- UpdateConstrainedWindows(NULL);
- }
- }
-
- void OnWillRemoveWindow(aura::Window* window) override {
- if (window == view_->window_.get())
- return;
-
- window->RemoveObserver(this);
- UpdateConstrainedWindows(window);
- }
-
- void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
- if (window == view_->window_.get() || window->parent() == host_window_ ||
- window->parent() == view_->window_->GetRootWindow()) {
- UpdateConstrainedWindows(NULL);
- }
- }
-#endif
-
void OnWindowParentChanged(aura::Window* window,
aura::Window* parent) override {
if (window != view_->window_.get())
@@ -488,46 +429,9 @@ class WebContentsViewAura::WindowObserver
if (host_window_)
host_window_->RemoveObserver(this);
-#if defined(OS_WIN)
- if (host_window_) {
- const aura::Window::Windows& children = host_window_->children();
- for (size_t i = 0; i < children.size(); ++i)
- children[i]->RemoveObserver(this);
- RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura(
- view_->web_contents_->GetRenderWidgetHostView());
- if (rwhv)
- rwhv->UpdateConstrainedWindowRects(std::vector<gfx::Rect>());
- }
-
- // When we get parented to the root window, the code below will watch the
- // host window, aka root window. Since we already watch the root window on
- // Windows, unregister first so that the debug check doesn't fire.
- if (host_window && host_window == window->GetRootWindow())
- host_window->RemoveObserver(this);
-
- // We need to undo the above if we were parented to the root window and then
- // got parented to another window. At that point, the code before the ifdef
- // would have stopped watching the root window.
- if (window->GetRootWindow() &&
- host_window != window->GetRootWindow() &&
- !window->GetRootWindow()->HasObserver(this)) {
- window->GetRootWindow()->AddObserver(this);
- }
-#endif
-
host_window_ = host_window;
- if (host_window) {
+ if (host_window)
host_window->AddObserver(this);
-#if defined(OS_WIN)
- if (host_window != window->GetRootWindow()) {
- const aura::Window::Windows& children = host_window->children();
- for (size_t i = 0; i < children.size(); ++i) {
- if (!children[i]->Contains(view_->window_.get()))
- children[i]->AddObserver(this);
- }
- }
-#endif
- }
}
void OnWindowBoundsChanged(aura::Window* window,
@@ -541,10 +445,6 @@ class WebContentsViewAura::WindowObserver
if (selection_controller_client)
selection_controller_client->OnWindowMoved();
}
-#if defined(OS_WIN)
- } else {
- UpdateConstrainedWindows(NULL);
-#endif
}
}
@@ -556,32 +456,14 @@ class WebContentsViewAura::WindowObserver
}
void OnWindowAddedToRootWindow(aura::Window* window) override {
- if (window == view_->window_.get()) {
+ if (window == view_->window_.get())
window->GetHost()->AddObserver(this);
-#if defined(OS_WIN)
- if (!window->GetRootWindow()->HasObserver(this))
- window->GetRootWindow()->AddObserver(this);
-#endif
- }
}
void OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) override {
- if (window == view_->window_.get()) {
+ if (window == view_->window_.get())
window->GetHost()->RemoveObserver(this);
-#if defined(OS_WIN)
- window->GetRootWindow()->RemoveObserver(this);
-
- const aura::Window::Windows& root_children =
- window->GetRootWindow()->children();
- for (size_t i = 0; i < root_children.size(); ++i) {
- if (root_children[i] != view_->window_.get() &&
- root_children[i] != host_window_) {
- root_children[i]->RemoveObserver(this);
- }
- }
-#endif
- }
}
// Overridden WindowTreeHostObserver:
@@ -596,46 +478,7 @@ class WebContentsViewAura::WindowObserver
}
private:
- void SendScreenRects() {
- RenderWidgetHostImpl::From(
- view_->web_contents_->GetRenderViewHost()->GetWidget())
- ->SendScreenRects();
- }
-
-#if defined(OS_WIN)
- void UpdateConstrainedWindows(aura::Window* exclude) {
- RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
- view_->web_contents_->GetRenderWidgetHostView());
- if (!view)
- return;
-
- std::vector<gfx::Rect> constrained_windows;
- if (host_window_) {
- const aura::Window::Windows& children = host_window_->children();
- for (size_t i = 0; i < children.size(); ++i) {
- if (!children[i]->Contains(view_->window_.get()) &&
- children[i] != exclude &&
- children[i]->IsVisible()) {
- constrained_windows.push_back(children[i]->GetBoundsInRootWindow());
- }
- }
- }
-
- aura::Window* root_window = view_->window_->GetRootWindow();
- const aura::Window::Windows& root_children = root_window->children();
- if (root_window) {
- for (size_t i = 0; i < root_children.size(); ++i) {
- if (root_children[i]->IsVisible() &&
- !root_children[i]->Contains(view_->window_.get())) {
- constrained_windows.push_back(
- root_children[i]->GetBoundsInRootWindow());
- }
- }
- }
-
- view->UpdateConstrainedWindowRects(constrained_windows);
- }
-#endif
+ void SendScreenRects() { view_->web_contents_->SendScreenRects(); }
WebContentsViewAura* view_;
@@ -658,8 +501,11 @@ WebContentsViewAura::WebContentsViewAura(WebContentsImpl* web_contents,
current_rvh_for_drag_(NULL),
current_overscroll_gesture_(OVERSCROLL_NONE),
completed_overscroll_gesture_(OVERSCROLL_NONE),
- navigation_overlay_(nullptr),
- is_or_was_visible_(false) {
+ navigation_overlay_(nullptr) {}
+
+void WebContentsViewAura::SetDelegateForTesting(
+ WebContentsViewDelegate* delegate) {
+ delegate_.reset(delegate);
}
////////////////////////////////////////////////////////////////////////////////
@@ -688,8 +534,7 @@ void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) {
void WebContentsViewAura::EndDrag(blink::WebDragOperationsMask ops) {
aura::Window* root_window = GetNativeView()->GetRootWindow();
- gfx::Point screen_loc =
- gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
+ gfx::Point screen_loc = gfx::Screen::GetScreen()->GetCursorScreenPoint();
gfx::Point client_loc = screen_loc;
RenderViewHost* rvh = web_contents_->GetRenderViewHost();
aura::Window* window = rvh->GetWidget()->GetView()->GetNativeView();
@@ -839,7 +684,6 @@ void WebContentsViewAura::CreateView(
window_.reset(new aura::Window(this));
window_->set_owned_by_parent(false);
window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
- window_->SetTransparent(false);
window_->Init(ui::LAYER_NOT_DRAWN);
window_->AddObserver(this);
aura::Window* root_window = context ? context->GetRootWindow() : NULL;
@@ -951,11 +795,12 @@ void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host,
selection_controller_client->HandleContextMenu(params)) {
return;
}
+
if (delegate_) {
RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
web_contents_->GetRenderWidgetHostView());
- if (view)
- view->OnShowContextMenu();
+ if (view && !view->OnShowContextMenu(params))
+ return;
delegate_->ShowContextMenu(render_frame_host, params);
// WARNING: we may have been deleted during the call to ShowContextMenu().
@@ -1197,8 +1042,7 @@ void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) {
web_contents_->GetDelegate()->ActivateContents(web_contents_);
web_contents_->GetDelegate()->ContentsMouseEvent(
- web_contents_,
- gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
+ web_contents_, gfx::Screen::GetScreen()->GetCursorScreenPoint(),
type == ui::ET_MOUSE_MOVED, type == ui::ET_MOUSE_EXITED);
}
@@ -1223,8 +1067,7 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
if (drag_dest_delegate_)
drag_dest_delegate_->DragInitialize(web_contents_);
- gfx::Point screen_pt =
- gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
+ gfx::Point screen_pt = gfx::Screen::GetScreen()->GetCursorScreenPoint();
web_contents_->GetRenderViewHost()->DragTargetDragEnter(
*current_drop_data_.get(), event.location(), screen_pt, op,
ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
@@ -1244,8 +1087,7 @@ int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
return ui::DragDropTypes::DRAG_NONE;
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
- gfx::Point screen_pt =
- gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
+ gfx::Point screen_pt = gfx::Screen::GetScreen()->GetCursorScreenPoint();
web_contents_->GetRenderViewHost()->DragTargetDragOver(
event.location(), screen_pt, op,
ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
@@ -1280,8 +1122,7 @@ int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
return ui::DragDropTypes::DRAG_NONE;
web_contents_->GetRenderViewHost()->DragTargetDrop(
- event.location(),
- gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
+ event.location(), gfx::Screen::GetScreen()->GetCursorScreenPoint(),
ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
if (drag_dest_delegate_)
drag_dest_delegate_->OnDrop();
@@ -1295,30 +1136,7 @@ void WebContentsViewAura::OnWindowVisibilityChanged(aura::Window* window,
if (window != window_.get() && window_->Contains(window))
return;
- UpdateWebContentsVisibility(visible);
-}
-
-void WebContentsViewAura::UpdateWebContentsVisibility(bool visible) {
- if (!is_or_was_visible_) {
- // We should not hide the web contents before it was shown the first time,
- // since resources would immediately be destroyed and only re-created after
- // content got loaded. In this state the window content is undefined and can
- // show garbage.
- // However - the page load mechanism requires an activation call through a
- // visibility call to (re)load.
- if (visible) {
- is_or_was_visible_ = true;
- web_contents_->WasShown();
- }
- return;
- }
- if (visible) {
- if (!web_contents_->should_normally_be_visible())
- web_contents_->WasShown();
- } else {
- if (web_contents_->should_normally_be_visible())
- web_contents_->WasHidden();
- }
+ web_contents_->UpdateWebContentsVisibility(visible);
}
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura.h b/chromium/content/browser/web_contents/web_contents_view_aura.h
index 70c29b0583b..2c4b41d6cc4 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.h
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.h
@@ -39,8 +39,8 @@ class WebContentsViewDelegate;
class WebContentsImpl;
class WebDragDestDelegate;
-class WebContentsViewAura
- : public WebContentsView,
+class CONTENT_EXPORT WebContentsViewAura
+ : NON_EXPORTED_BASE(public WebContentsView),
public RenderViewHostDelegateView,
public OverscrollControllerDelegate,
public aura::WindowDelegate,
@@ -50,6 +50,9 @@ class WebContentsViewAura
WebContentsViewAura(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate);
+ // Allow the WebContentsViewDelegate to be set explicitly.
+ void SetDelegateForTesting(WebContentsViewDelegate* delegate);
+
private:
class WindowObserver;
@@ -157,9 +160,6 @@ class WebContentsViewAura
// Overridden from aura::WindowObserver:
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
- // Update the web contents visiblity.
- void UpdateWebContentsVisibility(bool visible);
-
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, EnableDisableOverscroll);
scoped_ptr<aura::Window> window_;
@@ -196,10 +196,6 @@ class WebContentsViewAura
scoped_ptr<GestureNavSimple> gesture_nav_simple_;
- // On Windows we can run into problems if resources get released within the
- // initialization phase while the content (and its dimensions) are not known.
- bool is_or_was_visible_;
-
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura);
};
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 8d08134b629..b8960350aa2 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -272,7 +272,7 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
controller->SetScreenshotManager(make_scoped_ptr(screenshot_manager_));
frame_watcher_ = new FrameWatcher();
- GetRenderWidgetHost()->GetProcess()->AddFilter(frame_watcher_.get());
+ frame_watcher_->AttachTo(shell()->web_contents());
}
void SetUpCommandLine(base::CommandLine* cmd) override {
diff --git a/chromium/content/browser/web_contents/web_contents_view_mac.h b/chromium/content/browser/web_contents/web_contents_view_mac.h
index 62a8b34219f..bcd6a26c9bc 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.h
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.h
@@ -50,6 +50,11 @@ CONTENT_EXPORT
- (void)setMouseDownCanMoveWindow:(BOOL)canMove;
- (void)setOpaque:(BOOL)opaque;
+
+// Returns the available drag operations. This is a required method for
+// NSDraggingSource. It is supposedly deprecated, but the non-deprecated API
+// -[NSWindow dragImage:...] still relies on it.
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
@end
namespace content {
diff --git a/chromium/content/browser/web_contents/web_contents_view_mac.mm b/chromium/content/browser/web_contents/web_contents_view_mac.mm
index 9556dde593a..b87c8b96365 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.mm
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.mm
@@ -8,6 +8,7 @@
#include <string>
+#include "base/command_line.h"
#import "base/mac/mac_util.h"
#import "base/mac/scoped_sending_event.h"
#include "base/mac/sdk_forward_declarations.h"
@@ -23,6 +24,7 @@
#include "content/common/view_messages.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_view_delegate.h"
+#include "content/public/common/content_switches.h"
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "ui/base/clipboard/custom_data_helper.h"
@@ -43,16 +45,17 @@ using content::WebContentsViewMac;
// Ensure that the blink::WebDragOperation enum values stay in sync with
// NSDragOperation constants, since the code below static_casts between 'em.
-#define STATIC_ASSERT_MATCHING_ENUM(name) \
- static_assert(int(NS##name) == int(blink::Web##name), "enum mismatch: " #name)
-STATIC_ASSERT_MATCHING_ENUM(DragOperationNone);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationCopy);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationLink);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationGeneric);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationPrivate);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationMove);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationDelete);
-STATIC_ASSERT_MATCHING_ENUM(DragOperationEvery);
+#define STATIC_ASSERT_ENUM(a, b) \
+ static_assert(static_cast<int>(a) == static_cast<int>(b), \
+ "enum mismatch: " #a)
+STATIC_ASSERT_ENUM(NSDragOperationNone, blink::WebDragOperationNone);
+STATIC_ASSERT_ENUM(NSDragOperationCopy, blink::WebDragOperationCopy);
+STATIC_ASSERT_ENUM(NSDragOperationLink, blink::WebDragOperationLink);
+STATIC_ASSERT_ENUM(NSDragOperationGeneric, blink::WebDragOperationGeneric);
+STATIC_ASSERT_ENUM(NSDragOperationPrivate, blink::WebDragOperationPrivate);
+STATIC_ASSERT_ENUM(NSDragOperationMove, blink::WebDragOperationMove);
+STATIC_ASSERT_ENUM(NSDragOperationDelete, blink::WebDragOperationDelete);
+STATIC_ASSERT_ENUM(NSDragOperationEvery, blink::WebDragOperationEvery);
@interface WebContentsViewCocoa (Private)
- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w;
@@ -66,6 +69,7 @@ STATIC_ASSERT_MATCHING_ENUM(DragOperationEvery);
- (void)cancelDeferredClose;
- (void)clearWebContentsView;
- (void)closeTabAfterEvent;
+- (void)updateWebContentsVisibility;
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification;
- (content::WebContentsImpl*)webContents;
@end
@@ -114,13 +118,15 @@ gfx::NativeWindow WebContentsViewMac::GetTopLevelNativeWindow() const {
}
void WebContentsViewMac::GetContainerBounds(gfx::Rect* out) const {
- // Convert bounds to window coordinate space.
- NSRect bounds =
- [cocoa_view_.get() convertRect:[cocoa_view_.get() bounds] toView:nil];
-
- // Convert bounds to screen coordinate space.
NSWindow* window = [cocoa_view_.get() window];
- bounds.origin = [window convertBaseToScreen:bounds.origin];
+ NSRect bounds = [cocoa_view_.get() bounds];
+ if (window) {
+ // Convert bounds to window coordinate space.
+ bounds = [cocoa_view_.get() convertRect:bounds toView:nil];
+
+ // Convert bounds to screen coordinate space.
+ bounds = [window convertRectToScreen:bounds];
+ }
// Flip y to account for screen flip.
NSScreen* screen = [[NSScreen screens] firstObject];
@@ -519,8 +525,6 @@ void WebContentsViewMac::CloseTab() {
// NSDraggingSource methods
-// Returns what kind of drag operations are available. This is a required
-// method for NSDraggingSource.
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
if (dragSource_)
return [dragSource_ draggingSourceOperationMaskForLocal:isLocal];
@@ -610,6 +614,15 @@ void WebContentsViewMac::CloseTab() {
FocusThroughTabTraversal(direction == NSSelectingPrevious);
}
+- (void)updateWebContentsVisibility {
+ WebContentsImpl* webContents = [self webContents];
+ if (!webContents || webContents->IsBeingDestroyed())
+ return;
+
+ const bool viewVisible = [self window] && ![self isHiddenOrHasHiddenAncestor];
+ webContents->UpdateWebContentsVisibility(viewVisible);
+}
+
// When the subviews require a layout, their size should be reset to the size
// of this view. (It is possible for the size to get out of sync as an
// optimization in preparation for an upcoming WebContentsView resize.
@@ -625,10 +638,12 @@ void WebContentsViewMac::CloseTab() {
NSNotificationCenter* notificationCenter =
[NSNotificationCenter defaultCenter];
- // Occlusion notification APIs are new in Mavericks.
- bool supportsOcclusionAPIs = base::mac::IsOSMavericksOrLater();
+ // Occlusion is highly undesirable for browser tests, since it will
+ // flakily change test behavior.
+ static bool isDisabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableBackgroundingOccludedWindowsForTesting);
- if (supportsOcclusionAPIs) {
+ if (!isDisabled) {
if (oldWindow) {
[notificationCenter
removeObserver:self
@@ -658,4 +673,16 @@ void WebContentsViewMac::CloseTab() {
}
}
+- (void)viewDidMoveToWindow {
+ [self updateWebContentsVisibility];
+}
+
+- (void)viewDidHide {
+ [self updateWebContentsVisibility];
+}
+
+- (void)viewDidUnhide {
+ [self updateWebContentsVisibility];
+}
+
@end
diff --git a/chromium/content/browser/web_contents/web_contents_view_mus.cc b/chromium/content/browser/web_contents/web_contents_view_mus.cc
index b987ab198b8..d4860b3a81b 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mus.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_mus.cc
@@ -104,7 +104,6 @@ void WebContentsViewMus::CreateView(const gfx::Size& initial_size,
aura_window_.reset(new aura::Window(this));
aura_window_->set_owned_by_parent(false);
aura_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
- aura_window_->SetTransparent(false);
aura_window_->Init(ui::LAYER_NOT_DRAWN);
aura::Window* root_window = context ? context->GetRootWindow() : nullptr;
if (root_window) {
diff --git a/chromium/content/browser/web_contents/web_drag_dest_mac.mm b/chromium/content/browser/web_contents/web_drag_dest_mac.mm
index ec674126d52..452bfc89cf2 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac.mm
@@ -15,6 +15,7 @@
#include "third_party/WebKit/public/web/WebInputEvent.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/cocoa/cocoa_base_utils.h"
#import "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/base/window_open_disposition.h"
@@ -98,7 +99,8 @@ int GetModifierFlags() {
- (NSPoint)flipWindowPointToScreen:(const NSPoint&)windowPoint
view:(NSView*)view {
DCHECK(view);
- NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
+ NSPoint screenPoint =
+ ui::ConvertPointFromWindowToScreen([view window], windowPoint);
NSScreen* screen = [[view window] screen];
NSRect screenFrame = [screen frame];
screenPoint.y = screenFrame.size.height - screenPoint.y;
diff --git a/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm b/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
index efa6452e267..b6a6946ab7d 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac_unittest.mm
@@ -5,6 +5,7 @@
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#import "base/mac/scoped_nsobject.h"
+#include "base/memory/ref_counted.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "content/browser/web_contents/web_drag_dest_mac.h"
@@ -13,6 +14,7 @@
#include "content/test/test_web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
+#import "ui/base/clipboard/clipboard_util_mac.h"
#import "ui/base/dragdrop/cocoa_dnd_util.h"
#import "ui/gfx/test/ui_cocoa_test_helper.h"
@@ -82,88 +84,80 @@ TEST_F(WebDragDestTest, Flip) {
}
TEST_F(WebDragDestTest, URL) {
- NSPasteboard* pboard = nil;
NSString* url = nil;
NSString* title = nil;
GURL result_url;
base::string16 result_title;
// Put a URL on the pasteboard and check it.
- pboard = [NSPasteboard pasteboardWithUniqueName];
+ scoped_refptr<ui::UniquePasteboard> pboard = new ui::UniquePasteboard;
url = @"http://www.google.com/";
- PutURLOnPasteboard(url, pboard);
- EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, NO));
+ PutURLOnPasteboard(url, pboard->get());
+ EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), NO));
EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
- [pboard releaseGlobally];
// Put a 'url ' and 'urln' on the pasteboard and check it.
- pboard = [NSPasteboard pasteboardWithUniqueName];
+ pboard = new ui::UniquePasteboard;
url = @"http://www.google.com/";
title = @"Title of Awesomeness!",
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, NO));
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard->get());
+ EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), NO));
EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
// Also check that it passes file:// via 'url '/'urln' properly.
- pboard = [NSPasteboard pasteboardWithUniqueName];
+ pboard = new ui::UniquePasteboard;
url = @"file:///tmp/dont_delete_me.txt";
title = @"very important";
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, NO));
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard->get());
+ EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), NO));
EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
// And javascript:.
- pboard = [NSPasteboard pasteboardWithUniqueName];
+ pboard = new ui::UniquePasteboard;
url = @"javascript:open('http://www.youtube.com/')";
title = @"kill some time";
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, NO));
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard->get());
+ EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), NO));
EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
- pboard = [NSPasteboard pasteboardWithUniqueName];
+ pboard = new ui::UniquePasteboard;
url = @"/bin/sh";
- [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
- owner:nil];
- [pboard setPropertyList:[NSArray arrayWithObject:url]
- forType:NSFilenamesPboardType];
- EXPECT_FALSE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, NO));
- EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(
- &result_url, &result_title, pboard, YES));
+ [pboard->get() declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
+ owner:nil];
+ [pboard->get() setPropertyList:[NSArray arrayWithObject:url]
+ forType:NSFilenamesPboardType];
+ EXPECT_FALSE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), NO));
+ EXPECT_TRUE(ui::PopulateURLAndTitleFromPasteboard(&result_url, &result_title,
+ pboard->get(), YES));
base::scoped_nsobject<NSURL> expected_output(
[[NSURL alloc] initFileURLWithPath:url isDirectory:NO]);
EXPECT_EQ([[expected_output absoluteString] UTF8String], result_url.spec());
EXPECT_EQ("sh", base::UTF16ToUTF8(result_title));
- [pboard releaseGlobally];
}
TEST_F(WebDragDestTest, Data) {
DropData data;
- NSPasteboard* pboard = [NSPasteboard pasteboardWithUniqueName];
+ scoped_refptr<ui::UniquePasteboard> pboard = new ui::UniquePasteboard;
- PutURLOnPasteboard(@"http://www.google.com", pboard);
- [pboard addTypes:[NSArray arrayWithObjects:NSHTMLPboardType,
- NSStringPboardType, nil]
- owner:nil];
+ PutURLOnPasteboard(@"http://www.google.com", pboard->get());
+ [pboard->get() addTypes:[NSArray arrayWithObjects:NSHTMLPboardType,
+ NSStringPboardType, nil]
+ owner:nil];
NSString* htmlString = @"<html><body><b>hi there</b></body></html>";
NSString* textString = @"hi there";
- [pboard setString:htmlString forType:NSHTMLPboardType];
- [pboard setString:textString forType:NSStringPboardType];
- [drag_dest_ populateDropData:&data fromPasteboard:pboard];
+ [pboard->get() setString:htmlString forType:NSHTMLPboardType];
+ [pboard->get() setString:textString forType:NSStringPboardType];
+ [drag_dest_ populateDropData:&data fromPasteboard:pboard->get()];
EXPECT_EQ(data.url.spec(), "http://www.google.com/");
EXPECT_EQ(base::SysNSStringToUTF16(textString), data.text.string());
EXPECT_EQ(base::SysNSStringToUTF16(htmlString), data.html.string());
-
- [pboard releaseGlobally];
}
diff --git a/chromium/content/browser/web_contents/web_drag_source_mac.mm b/chromium/content/browser/web_contents/web_drag_source_mac.mm
index a94f9d32daa..14321f47879 100644
--- a/chromium/content/browser/web_contents/web_drag_source_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_source_mac.mm
@@ -30,6 +30,7 @@
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/gfx/image/image.h"
#include "ui/resources/grit/ui_resources.h"
@@ -173,8 +174,8 @@ void PromiseWriterHelper(const DropData& drop_data,
// Strip out any existing escapes and then re-escape uniformly.
if (!url && dropData_->url.SchemeIs(url::kJavaScriptScheme)) {
net::UnescapeRule::Type unescapeRules =
- net::UnescapeRule::SPACES |
- net::UnescapeRule::URL_SPECIAL_CHARS |
+ net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS;
std::string unescapedUrlString =
net::UnescapeURLComponent(dropData_->url.spec(), unescapeRules);
@@ -222,7 +223,8 @@ void PromiseWriterHelper(const DropData& drop_data,
- (NSPoint)convertScreenPoint:(NSPoint)screenPoint {
DCHECK([contentsView_ window]);
- NSPoint basePoint = [[contentsView_ window] convertScreenToBase:screenPoint];
+ NSPoint basePoint =
+ ui::ConvertPointFromScreenToWindow([contentsView_ window], screenPoint);
return [contentsView_ convertPoint:basePoint fromView:nil];
}
diff --git a/chromium/content/browser/web_contents/web_drag_source_mac_unittest.mm b/chromium/content/browser/web_contents/web_drag_source_mac_unittest.mm
index 036c9268f8e..edc18884810 100644
--- a/chromium/content/browser/web_contents/web_drag_source_mac_unittest.mm
+++ b/chromium/content/browser/web_contents/web_drag_source_mac_unittest.mm
@@ -4,10 +4,12 @@
#import "content/browser/web_contents/web_drag_source_mac.h"
+#include "base/memory/ref_counted.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/drop_data.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "ui/base/clipboard/clipboard_util_mac.h"
#include "url/gurl.h"
namespace content {
@@ -23,19 +25,19 @@ TEST_F(WebDragSourceMacTest, DragInvalidlyEscapedBookmarklet) {
dropData->url = GURL("javascript:%");
WebContentsImpl* contentsImpl = static_cast<WebContentsImpl*>(contents.get());
+ scoped_refptr<ui::UniquePasteboard> pasteboard1 = new ui::UniquePasteboard;
base::scoped_nsobject<WebDragSource> source([[WebDragSource alloc]
- initWithContents:contentsImpl
- view:view
- dropData:dropData.get()
- image:nil
- offset:NSZeroPoint
- pasteboard:[NSPasteboard pasteboardWithUniqueName]
- dragOperationMask:NSDragOperationCopy]);
+ initWithContents:contentsImpl
+ view:view
+ dropData:dropData.get()
+ image:nil
+ offset:NSZeroPoint
+ pasteboard:pasteboard1->get()
+ dragOperationMask:NSDragOperationCopy]);
// Test that this call doesn't throw any exceptions: http://crbug.com/128371
- base::scoped_nsobject<NSPasteboard> pasteboard(
- [NSPasteboard pasteboardWithUniqueName]);
- [source lazyWriteToPasteboard:pasteboard forType:NSURLPboardType];
+ scoped_refptr<ui::UniquePasteboard> pasteboard2 = new ui::UniquePasteboard;
+ [source lazyWriteToPasteboard:pasteboard2->get() forType:NSURLPboardType];
}
} // namespace content
diff --git a/chromium/content/browser/webui/OWNERS b/chromium/content/browser/webui/OWNERS
index 658a9f5cd0c..262db997c92 100644
--- a/chromium/content/browser/webui/OWNERS
+++ b/chromium/content/browser/webui/OWNERS
@@ -1 +1,2 @@
+dbeam@chromium.org
estade@chromium.org
diff --git a/chromium/content/browser/webui/content_web_ui_controller_factory.cc b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
index 196da55c9f9..9d87359ded1 100644
--- a/chromium/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
@@ -19,7 +19,7 @@
#include "content/public/common/url_constants.h"
#if defined(ENABLE_WEBRTC)
-#include "content/browser/media/webrtc_internals_ui.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui.h"
#endif
namespace content {
diff --git a/chromium/content/browser/webui/url_data_manager_backend.cc b/chromium/content/browser/webui/url_data_manager_backend.cc
index b604a461224..7dfd7575996 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.cc
+++ b/chromium/content/browser/webui/url_data_manager_backend.cc
@@ -674,15 +674,14 @@ bool URLDataManagerBackend::StartRequest(const net::URLRequest* request,
// message loop before request for data. And correspondingly their
// replies are put on the IO thread in the same order.
target_message_loop->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&GetMimeTypeOnUI, scoped_refptr<URLDataSourceImpl>(source),
- path, job->AsWeakPtr()));
+ FROM_HERE, base::Bind(&GetMimeTypeOnUI, base::RetainedRef(source), path,
+ job->AsWeakPtr()));
// The DataSource wants StartDataRequest to be called on a specific thread,
// usually the UI thread, for this path.
target_message_loop->task_runner()->PostTask(
FROM_HERE, base::Bind(&URLDataManagerBackend::CallStartRequest,
- make_scoped_refptr(source), path,
+ base::RetainedRef(source), path,
render_process_id, render_frame_id, request_id));
}
return true;
diff --git a/chromium/content/browser/webui/web_ui_data_source_impl.cc b/chromium/content/browser/webui/web_ui_data_source_impl.cc
index 9a026008daf..eeac51d9e3d 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.cc
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.cc
@@ -12,10 +12,11 @@
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "content/grit/content_resources.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
-#include "mojo/public/js/constants.h"
+#include "ui/base/template_expressions.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
@@ -36,8 +37,7 @@ void WebUIDataSource::Add(BrowserContext* browser_context,
// URLDataSource.
class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
public:
- InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {
- }
+ explicit InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {}
~InternalDataSource() override {}
@@ -80,9 +80,7 @@ class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
};
WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
- : URLDataSourceImpl(
- source_name,
- new InternalDataSource(this)),
+ : URLDataSourceImpl(source_name, new InternalDataSource(this)),
source_name_(source_name),
default_resource_(-1),
add_csp_(true),
@@ -90,26 +88,30 @@ WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
frame_src_set_(false),
deny_xframe_options_(true),
disable_set_font_strings_(false),
- replace_existing_source_(true) {
-}
+ replace_existing_source_(true) {}
WebUIDataSourceImpl::~WebUIDataSourceImpl() {
}
void WebUIDataSourceImpl::AddString(const std::string& name,
const base::string16& value) {
+ // TODO(dschuyler): Share only one copy of these strings.
localized_strings_.SetString(name, value);
+ replacements_[name] = base::UTF16ToUTF8(value);
}
void WebUIDataSourceImpl::AddString(const std::string& name,
const std::string& value) {
localized_strings_.SetString(name, value);
+ replacements_[name] = value;
}
void WebUIDataSourceImpl::AddLocalizedString(const std::string& name,
int ids) {
localized_strings_.SetString(
name, GetContentClient()->GetLocalizedString(ids));
+ replacements_[name] =
+ base::UTF16ToUTF8(GetContentClient()->GetLocalizedString(ids));
}
void WebUIDataSourceImpl::AddLocalizedStrings(
@@ -119,6 +121,11 @@ void WebUIDataSourceImpl::AddLocalizedStrings(
void WebUIDataSourceImpl::AddBoolean(const std::string& name, bool value) {
localized_strings_.SetBoolean(name, value);
+ // TODO(dschuyler): Change name of |localized_strings_| to |load_time_data_|
+ // or similar. These values haven't been found as strings for
+ // localization. The boolean values are not added to |replacements_|
+ // for the same reason, that they are used as flags, rather than string
+ // replacements.
}
void WebUIDataSourceImpl::SetJsonPath(const std::string& path) {
@@ -139,24 +146,6 @@ void WebUIDataSourceImpl::SetRequestFilter(
filter_callback_ = callback;
}
-void WebUIDataSourceImpl::AddMojoResources() {
- static const struct {
- const char* path;
- int id;
- } resources[] = {
- {mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS},
- {mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS},
- {mojo::kCodecModuleName, IDR_MOJO_CODEC_JS},
- {mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS},
- {mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS},
- {mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS},
- {mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS},
- {mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS},
- };
- for (size_t i = 0; i < arraysize(resources); ++i)
- AddResourcePath(resources[i].path, resources[i].id);
-}
-
void WebUIDataSourceImpl::DisableReplaceExistingSource() {
replace_existing_source_ = false;
}
@@ -230,7 +219,19 @@ void WebUIDataSourceImpl::StartDataRequest(
if (result != path_to_idr_map_.end())
resource_id = result->second;
DCHECK_NE(resource_id, -1);
- SendFromResourceBundle(callback, resource_id);
+ scoped_refptr<base::RefCountedMemory> response(
+ GetContentClient()->GetDataResourceBytes(resource_id));
+
+ // TODO(dschuyler): improve filtering of which resource to run template
+ // expansion upon.
+ if (GetMimeType(path) == "text/html") {
+ std::string replaced = ui::ReplaceTemplateExpressions(
+ base::StringPiece(response->front_as<char>(), response->size()),
+ replacements_);
+ response = base::RefCountedString::TakeString(&replaced);
+ }
+
+ callback.Run(response.get());
}
void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
@@ -245,11 +246,4 @@ void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
callback.Run(base::RefCountedString::TakeString(&template_data));
}
-void WebUIDataSourceImpl::SendFromResourceBundle(
- const URLDataSource::GotDataCallback& callback, int idr) {
- scoped_refptr<base::RefCountedStaticMemory> response(
- GetContentClient()->GetDataResourceBytes(idr));
- callback.Run(response.get());
-}
-
} // namespace content
diff --git a/chromium/content/browser/webui/web_ui_data_source_impl.h b/chromium/content/browser/webui/web_ui_data_source_impl.h
index 7d899a9e194..53cbc736cc9 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.h
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.h
@@ -17,6 +17,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/template_expressions.h"
namespace content {
@@ -38,7 +39,6 @@ class CONTENT_EXPORT WebUIDataSourceImpl
void SetDefaultResource(int resource_id) override;
void SetRequestFilter(
const WebUIDataSource::HandleRequestCallback& callback) override;
- void AddMojoResources() override;
void DisableReplaceExistingSource() override;
void DisableContentSecurityPolicy() override;
void OverrideContentSecurityPolicyObjectSrc(const std::string& data) override;
@@ -52,10 +52,6 @@ class CONTENT_EXPORT WebUIDataSourceImpl
void SendLocalizedStringsAsJSON(
const URLDataSource::GotDataCallback& callback);
- // Completes a request by sending the file specified by |idr|.
- void SendFromResourceBundle(
- const URLDataSource::GotDataCallback& callback, int idr);
-
private:
class InternalDataSource;
friend class InternalDataSource;
@@ -85,6 +81,10 @@ class CONTENT_EXPORT WebUIDataSourceImpl
int default_resource_;
std::string json_path_;
std::map<std::string, int> path_to_idr_map_;
+ // The |replacements_| is intended to replace |localized_strings_|.
+ // TODO(dschuyler): phase out |localized_strings_| in Q1 2016. (Or rename
+ // to |load_time_flags_| if the usage is reduced to storing flags only).
+ ui::TemplateReplacements replacements_;
base::DictionaryValue localized_strings_;
WebUIDataSource::HandleRequestCallback filter_callback_;
bool add_csp_;
@@ -99,6 +99,6 @@ class CONTENT_EXPORT WebUIDataSourceImpl
DISALLOW_COPY_AND_ASSIGN(WebUIDataSourceImpl);
};
-} // content
+} // namespace content
#endif // CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_IMPL_H_
diff --git a/chromium/content/browser/webui/web_ui_impl.h b/chromium/content/browser/webui/web_ui_impl.h
index 26c051def9e..1c812a5660c 100644
--- a/chromium/content/browser/webui/web_ui_impl.h
+++ b/chromium/content/browser/webui/web_ui_impl.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_ui.h"
diff --git a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
index 805f1bb5775..920f891693a 100644
--- a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -31,7 +31,6 @@
#include "content/test/data/web_ui_test_mojo_bindings.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/js/constants.h"
#include "mojo/test/test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
@@ -44,21 +43,10 @@ bool got_message = false;
// up the generated file from disk and returns it.
bool GetResource(const std::string& id,
const WebUIDataSource::GotDataCallback& callback) {
- // These are handled by the WebUIDataSource that AddMojoDataSource() creates.
- if (id == mojo::kBindingsModuleName ||
- id == mojo::kBufferModuleName ||
- id == mojo::kCodecModuleName ||
- id == mojo::kConnectionModuleName ||
- id == mojo::kConnectorModuleName ||
- id == mojo::kUnicodeModuleName ||
- id == mojo::kRouterModuleName ||
- id == mojo::kValidatorModuleName)
- return false;
-
if (id.find(".mojom") != std::string::npos) {
std::string contents;
CHECK(base::ReadFileToString(mojo::test::GetFilePathForJSResource(id),
- &contents, std::string::npos))
+ &contents))
<< id;
base::RefCountedString* ref_contents = new base::RefCountedString;
ref_contents->data() = contents;
@@ -70,23 +58,22 @@ bool GetResource(const std::string& id,
CHECK(base::PathService::Get(content::DIR_TEST_DATA, &path));
path = path.AppendASCII(id.substr(0, id.find("?")));
std::string contents;
- CHECK(base::ReadFileToString(path, &contents, std::string::npos))
- << path.value();
+ CHECK(base::ReadFileToString(path, &contents)) << path.value();
base::RefCountedString* ref_contents = new base::RefCountedString;
ref_contents->data() = contents;
callback.Run(ref_contents);
return true;
}
-class BrowserTargetImpl : public BrowserTarget {
+class BrowserTargetImpl : public mojom::BrowserTarget {
public:
BrowserTargetImpl(base::RunLoop* run_loop,
- mojo::InterfaceRequest<BrowserTarget> request)
+ mojo::InterfaceRequest<mojom::BrowserTarget> request)
: run_loop_(run_loop), binding_(this, std::move(request)) {}
~BrowserTargetImpl() override {}
- // BrowserTarget overrides:
+ // mojom::BrowserTarget overrides:
void Start(const mojo::Closure& closure) override {
closure.Run();
}
@@ -99,7 +86,7 @@ class BrowserTargetImpl : public BrowserTarget {
base::RunLoop* run_loop_;
private:
- mojo::Binding<BrowserTarget> binding_;
+ mojo::Binding<mojom::BrowserTarget> binding_;
DISALLOW_COPY_AND_ASSIGN(BrowserTargetImpl);
};
@@ -110,7 +97,6 @@ class TestWebUIController : public WebUIController {
: WebUIController(web_ui), run_loop_(run_loop) {
content::WebUIDataSource* data_source =
WebUIDataSource::Create("mojo-web-ui");
- data_source->AddMojoResources();
data_source->SetRequestFilter(base::Bind(&GetResource));
content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
data_source);
@@ -135,12 +121,12 @@ class PingTestWebUIController : public TestWebUIController {
// WebUIController overrides:
void RenderViewCreated(RenderViewHost* render_view_host) override {
- render_view_host->GetMainFrame()->GetServiceRegistry()->
- AddService<BrowserTarget>(base::Bind(
- &PingTestWebUIController::CreateHandler, base::Unretained(this)));
+ render_view_host->GetMainFrame()->GetServiceRegistry()->AddService(
+ base::Bind(&PingTestWebUIController::CreateHandler,
+ base::Unretained(this)));
}
- void CreateHandler(mojo::InterfaceRequest<BrowserTarget> request) {
+ void CreateHandler(mojo::InterfaceRequest<mojom::BrowserTarget> request) {
browser_target_.reset(new BrowserTargetImpl(run_loop_, std::move(request)));
}
diff --git a/chromium/content/browser/zygote_host/zygote_communication_linux.cc b/chromium/content/browser/zygote_host/zygote_communication_linux.cc
new file mode 100644
index 00000000000..54f5176adbd
--- /dev/null
+++ b/chromium/content/browser/zygote_host/zygote_communication_linux.cc
@@ -0,0 +1,437 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/zygote_host/zygote_communication_linux.h"
+
+#include <string.h>
+#include <sys/socket.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/path_service.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "content/browser/renderer_host/render_sandbox_host_linux.h"
+#include "content/browser/zygote_host/zygote_host_impl_linux.h"
+#include "content/common/child_process_sandbox_support_impl_linux.h"
+#include "content/common/zygote_commands_linux.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/result_codes.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
+#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
+#include "ui/gfx/switches.h"
+
+namespace content {
+
+namespace {
+
+// Receive a fixed message on fd and return the sender's PID.
+// Returns true if the message received matches the expected message.
+bool ReceiveFixedMessage(int fd,
+ const char* expect_msg,
+ size_t expect_len,
+ base::ProcessId* sender_pid) {
+ char buf[expect_len + 1];
+ std::vector<base::ScopedFD> fds_vec;
+
+ const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid(
+ fd, buf, sizeof(buf), &fds_vec, sender_pid);
+ if (static_cast<size_t>(len) != expect_len)
+ return false;
+ if (memcmp(buf, expect_msg, expect_len) != 0)
+ return false;
+ if (!fds_vec.empty())
+ return false;
+ return true;
+}
+
+} // namespace
+
+ZygoteCommunication::ZygoteCommunication()
+ : control_fd_(-1),
+ control_lock_(),
+ pid_(),
+ list_of_running_zygote_children_(),
+ child_tracking_lock_(),
+ sandbox_status_(0),
+ have_read_sandbox_status_word_(false),
+ init_(false) {}
+
+ZygoteCommunication::~ZygoteCommunication() {}
+
+bool ZygoteCommunication::SendMessage(const base::Pickle& data,
+ const std::vector<int>* fds) {
+ DCHECK_NE(-1, control_fd_);
+ CHECK(data.size() <= kZygoteMaxMessageLength)
+ << "Trying to send too-large message to zygote (sending " << data.size()
+ << " bytes, max is " << kZygoteMaxMessageLength << ")";
+ CHECK(!fds || fds->size() <= base::UnixDomainSocket::kMaxFileDescriptors)
+ << "Trying to send message with too many file descriptors to zygote "
+ << "(sending " << fds->size() << ", max is "
+ << base::UnixDomainSocket::kMaxFileDescriptors << ")";
+
+ return base::UnixDomainSocket::SendMsg(control_fd_, data.data(), data.size(),
+ fds ? *fds : std::vector<int>());
+}
+
+ssize_t ZygoteCommunication::ReadSandboxStatus() {
+ DCHECK_NE(-1, control_fd_);
+ // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote,
+ // but don't wait for the reply. Thus, the first time that we read from the
+ // zygote, we get the reply to that request.
+ ssize_t bytes_read = HANDLE_EINTR(
+ read(control_fd_, &sandbox_status_, sizeof(sandbox_status_)));
+ if (bytes_read != sizeof(sandbox_status_)) {
+ return -1;
+ }
+ return bytes_read;
+}
+
+ssize_t ZygoteCommunication::ReadReply(void* buf, size_t buf_len) {
+ DCHECK_NE(-1, control_fd_);
+ if (!have_read_sandbox_status_word_) {
+ if (ReadSandboxStatus() == -1) {
+ return -1;
+ }
+ have_read_sandbox_status_word_ = true;
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
+ }
+
+ return HANDLE_EINTR(read(control_fd_, buf, buf_len));
+}
+
+pid_t ZygoteCommunication::ForkRequest(const std::vector<std::string>& argv,
+ scoped_ptr<FileDescriptorInfo> mapping,
+ const std::string& process_type) {
+ DCHECK(init_);
+
+ base::Pickle pickle;
+ int raw_socks[2];
+ PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks));
+ base::ScopedFD my_sock(raw_socks[0]);
+ base::ScopedFD peer_sock(raw_socks[1]);
+ CHECK(base::UnixDomainSocket::EnableReceiveProcessId(my_sock.get()));
+
+ pickle.WriteInt(kZygoteCommandFork);
+ pickle.WriteString(process_type);
+ pickle.WriteInt(argv.size());
+ for (std::vector<std::string>::const_iterator i = argv.begin();
+ i != argv.end(); ++i)
+ pickle.WriteString(*i);
+
+ // Fork requests contain one file descriptor for the PID oracle, and one
+ // more for each file descriptor mapping for the child process.
+ const size_t num_fds_to_send = 1 + mapping->GetMappingSize();
+ pickle.WriteInt(num_fds_to_send);
+
+ std::vector<int> fds;
+
+ // First FD to send is peer_sock.
+ // TODO(morrita): Ideally, this should be part of the mapping so that
+ // FileDescriptorInfo can manages its lifetime.
+ fds.push_back(peer_sock.get());
+
+ // The rest come from mapping.
+ for (size_t i = 0; i < mapping->GetMappingSize(); ++i) {
+ pickle.WriteUInt32(mapping->GetIDAt(i));
+ fds.push_back(mapping->GetFDAt(i));
+ }
+
+ // Sanity check that we've populated |fds| correctly.
+ DCHECK_EQ(num_fds_to_send, fds.size());
+
+ pid_t pid;
+ {
+ base::AutoLock lock(control_lock_);
+ if (!SendMessage(pickle, &fds))
+ return base::kNullProcessHandle;
+ mapping.reset();
+ peer_sock.reset();
+
+ {
+ char buf[sizeof(kZygoteChildPingMessage) + 1];
+ std::vector<base::ScopedFD> recv_fds;
+ base::ProcessId real_pid;
+
+ ssize_t n = base::UnixDomainSocket::RecvMsgWithPid(
+ my_sock.get(), buf, sizeof(buf), &recv_fds, &real_pid);
+ if (n != sizeof(kZygoteChildPingMessage) ||
+ 0 != memcmp(buf, kZygoteChildPingMessage,
+ sizeof(kZygoteChildPingMessage))) {
+ // Zygote children should still be trustworthy when they're supposed to
+ // ping us, so something's broken if we don't receive a valid ping.
+ LOG(ERROR) << "Did not receive ping from zygote child";
+ NOTREACHED();
+ real_pid = -1;
+ }
+ my_sock.reset();
+
+ // Always send PID back to zygote.
+ base::Pickle pid_pickle;
+ pid_pickle.WriteInt(kZygoteCommandForkRealPID);
+ pid_pickle.WriteInt(real_pid);
+ if (!SendMessage(pid_pickle, NULL))
+ return base::kNullProcessHandle;
+ }
+
+ // Read the reply, which pickles the PID and an optional UMA enumeration.
+ static const unsigned kMaxReplyLength = 2048;
+ char buf[kMaxReplyLength];
+ const ssize_t len = ReadReply(buf, sizeof(buf));
+
+ base::Pickle reply_pickle(buf, len);
+ base::PickleIterator iter(reply_pickle);
+ if (len <= 0 || !iter.ReadInt(&pid))
+ return base::kNullProcessHandle;
+
+ // If there is a nonempty UMA name string, then there is a UMA
+ // enumeration to record.
+ std::string uma_name;
+ int uma_sample;
+ int uma_boundary_value;
+ if (iter.ReadString(&uma_name) && !uma_name.empty() &&
+ iter.ReadInt(&uma_sample) && iter.ReadInt(&uma_boundary_value)) {
+ // We cannot use the UMA_HISTOGRAM_ENUMERATION macro here,
+ // because that's only for when the name is the same every time.
+ // Here we're using whatever name we got from the other side.
+ // But since it's likely that the same one will be used repeatedly
+ // (even though it's not guaranteed), we cache it here.
+ static base::HistogramBase* uma_histogram;
+ if (!uma_histogram || uma_histogram->histogram_name() != uma_name) {
+ uma_histogram = base::LinearHistogram::FactoryGet(
+ uma_name, 1, uma_boundary_value, uma_boundary_value + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ }
+ uma_histogram->Add(uma_sample);
+ }
+
+ if (pid <= 0)
+ return base::kNullProcessHandle;
+ }
+
+#if !defined(OS_OPENBSD)
+ // This is just a starting score for a renderer or extension (the
+ // only types of processes that will be started this way). It will
+ // get adjusted as time goes on. (This is the same value as
+ // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but
+ // that's not something we can include here.)
+ const int kLowestRendererOomScore = 300;
+ ZygoteHostImpl::GetInstance()->AdjustRendererOOMScore(
+ pid, kLowestRendererOomScore);
+#endif
+
+ ZygoteChildBorn(pid);
+ return pid;
+}
+
+void ZygoteCommunication::EnsureProcessTerminated(pid_t process) {
+ DCHECK(init_);
+ base::Pickle pickle;
+
+ pickle.WriteInt(kZygoteCommandReap);
+ pickle.WriteInt(process);
+ if (!SendMessage(pickle, NULL))
+ LOG(ERROR) << "Failed to send Reap message to zygote";
+ ZygoteChildDied(process);
+}
+
+void ZygoteCommunication::ZygoteChildBorn(pid_t process) {
+ base::AutoLock lock(child_tracking_lock_);
+ bool new_element_inserted =
+ list_of_running_zygote_children_.insert(process).second;
+ DCHECK(new_element_inserted);
+}
+
+void ZygoteCommunication::ZygoteChildDied(pid_t process) {
+ base::AutoLock lock(child_tracking_lock_);
+ size_t num_erased = list_of_running_zygote_children_.erase(process);
+ DCHECK_EQ(1U, num_erased);
+}
+
+void ZygoteCommunication::Init() {
+ CHECK(!init_);
+
+ base::FilePath chrome_path;
+ CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
+ base::CommandLine cmd_line(chrome_path);
+
+ cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess);
+
+ int fds[2];
+ CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
+ CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0]));
+ base::FileHandleMappingVector fds_to_map;
+ fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
+
+ base::LaunchOptions options;
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) {
+ cmd_line.PrependWrapper(
+ browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix));
+ }
+ // Append any switches from the browser process that need to be forwarded on
+ // to the zygote/renderers.
+ // Should this list be obtained from browser_render_process_host.cc?
+ static const char* kForwardSwitches[] = {
+ switches::kAllowSandboxDebugging, switches::kAndroidFontsPath,
+ switches::kDisableSeccompFilterSandbox,
+ switches::kEnableHeapProfiling,
+ switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
+ // Zygote process needs to know what resources to have loaded when it
+ // becomes a renderer process.
+ switches::kForceDeviceScaleFactor, switches::kLoggingLevel,
+ switches::kNoSandbox, switches::kPpapiInProcess,
+ switches::kRegisterPepperPlugins, switches::kV, switches::kVModule,
+ };
+ cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
+ arraysize(kForwardSwitches));
+
+ GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1);
+
+ const bool using_namespace_sandbox =
+ ZygoteHostImpl::GetInstance()->ShouldUseNamespaceSandbox();
+ // A non empty sandbox_cmd means we want a SUID sandbox.
+ const bool using_suid_sandbox =
+ !ZygoteHostImpl::GetInstance()->SandboxCommand().empty() &&
+ !using_namespace_sandbox;
+
+ // Start up the sandbox host process and get the file descriptor for the
+ // renderers to talk to it.
+ const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
+ fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
+
+ base::ScopedFD dummy_fd;
+ if (using_suid_sandbox) {
+ scoped_ptr<sandbox::SetuidSandboxHost> sandbox_host(
+ sandbox::SetuidSandboxHost::Create());
+ sandbox_host->PrependWrapper(&cmd_line);
+ sandbox_host->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
+ sandbox_host->SetupLaunchEnvironment();
+ }
+
+ options.fds_to_remap = &fds_to_map;
+ base::Process process =
+ using_namespace_sandbox
+ ? sandbox::NamespaceSandbox::LaunchProcess(cmd_line, options)
+ : base::LaunchProcess(cmd_line, options);
+ CHECK(process.IsValid()) << "Failed to launch zygote process";
+
+ dummy_fd.reset();
+
+ if (using_suid_sandbox || using_namespace_sandbox) {
+ // The SUID sandbox will execute the zygote in a new PID namespace, and
+ // the main zygote process will then fork from there. Watch now our
+ // elaborate dance to find and validate the zygote's PID.
+
+ // First we receive a message from the zygote boot process.
+ base::ProcessId boot_pid;
+ CHECK(ReceiveFixedMessage(fds[0], kZygoteBootMessage,
+ sizeof(kZygoteBootMessage), &boot_pid));
+
+ // Within the PID namespace, the zygote boot process thinks it's PID 1,
+ // but its real PID can never be 1. This gives us a reliable test that
+ // the kernel is translating the sender's PID to our namespace.
+ CHECK_GT(boot_pid, 1)
+ << "Received invalid process ID for zygote; kernel might be too old? "
+ "See crbug.com/357670 or try using --"
+ << switches::kDisableSetuidSandbox << " to workaround.";
+
+ // Now receive the message that the zygote's ready to go, along with the
+ // main zygote process's ID.
+ CHECK(ReceiveFixedMessage(fds[0], kZygoteHelloMessage,
+ sizeof(kZygoteHelloMessage), &pid_));
+ CHECK_GT(pid_, 1);
+
+ if (process.Pid() != pid_) {
+ // Reap the sandbox.
+ base::EnsureProcessGetsReaped(process.Pid());
+ }
+ } else {
+ // Not using the SUID sandbox.
+ // Note that ~base::Process() will reset the internal value, but there's no
+ // real "handle" on POSIX so that is safe.
+ pid_ = process.Pid();
+ }
+
+ close(fds[1]);
+ control_fd_ = fds[0];
+
+ ZygoteHostImpl::GetInstance()->AddZygotePid(pid_);
+
+ base::Pickle pickle;
+ pickle.WriteInt(kZygoteCommandGetSandboxStatus);
+ if (!SendMessage(pickle, NULL))
+ LOG(FATAL) << "Cannot communicate with zygote";
+
+ init_ = true;
+}
+
+base::TerminationStatus ZygoteCommunication::GetTerminationStatus(
+ base::ProcessHandle handle,
+ bool known_dead,
+ int* exit_code) {
+ DCHECK(init_);
+ base::Pickle pickle;
+ pickle.WriteInt(kZygoteCommandGetTerminationStatus);
+ pickle.WriteBool(known_dead);
+ pickle.WriteInt(handle);
+
+ static const unsigned kMaxMessageLength = 128;
+ char buf[kMaxMessageLength];
+ ssize_t len;
+ {
+ base::AutoLock lock(control_lock_);
+ if (!SendMessage(pickle, NULL))
+ LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote";
+ len = ReadReply(buf, sizeof(buf));
+ }
+
+ // Set this now to handle the error cases.
+ if (exit_code)
+ *exit_code = RESULT_CODE_NORMAL_EXIT;
+ int status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
+
+ if (len == -1) {
+ LOG(WARNING) << "Error reading message from zygote: " << errno;
+ } else if (len == 0) {
+ LOG(WARNING) << "Socket closed prematurely.";
+ } else {
+ base::Pickle read_pickle(buf, len);
+ int tmp_status, tmp_exit_code;
+ base::PickleIterator iter(read_pickle);
+ if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) {
+ LOG(WARNING)
+ << "Error parsing GetTerminationStatus response from zygote.";
+ } else {
+ if (exit_code)
+ *exit_code = tmp_exit_code;
+ status = tmp_status;
+ }
+ }
+
+ if (status != base::TERMINATION_STATUS_STILL_RUNNING) {
+ ZygoteChildDied(handle);
+ }
+ return static_cast<base::TerminationStatus>(status);
+}
+
+int ZygoteCommunication::GetSandboxStatus() {
+ if (have_read_sandbox_status_word_) {
+ return sandbox_status_;
+ }
+ if (ReadSandboxStatus() == -1) {
+ return 0;
+ }
+ have_read_sandbox_status_word_ = true;
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
+ return sandbox_status_;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/zygote_host/zygote_communication_linux.h b/chromium/content/browser/zygote_host/zygote_communication_linux.h
new file mode 100644
index 00000000000..d3f4403cb15
--- /dev/null
+++ b/chromium/content/browser/zygote_host/zygote_communication_linux.h
@@ -0,0 +1,93 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_
+#define CONTENT_BROWSER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_
+
+#include <set>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/process/kill.h"
+#include "base/synchronization/lock.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/file_descriptor_info.h"
+
+namespace content {
+
+class CONTENT_EXPORT ZygoteCommunication {
+ public:
+ ZygoteCommunication();
+ ~ZygoteCommunication();
+
+ void Init();
+
+ // Tries to start a process of type indicated by process_type.
+ // Returns its pid on success, otherwise base::kNullProcessHandle;
+ pid_t ForkRequest(const std::vector<std::string>& command_line,
+ scoped_ptr<FileDescriptorInfo> mapping,
+ const std::string& process_type);
+
+ void EnsureProcessTerminated(pid_t process);
+
+ // Should be called every time a Zygote child died.
+ void ZygoteChildDied(pid_t process);
+
+ // Get the termination status (and, optionally, the exit code) of
+ // the process. |exit_code| is set to the exit code of the child
+ // process. (|exit_code| may be NULL.)
+ // Unfortunately the Zygote can not accurately figure out if a process
+ // is already dead without waiting synchronously for it.
+ // |known_dead| should be set to true when we already know that the process
+ // is dead. When |known_dead| is false, processes could be seen as
+ // still running, even when they're not. When |known_dead| is true, the
+ // process will be SIGKILL-ed first (which should have no effect if it was
+ // really dead). This is to prevent a waiting waitpid() from blocking in
+ // a single-threaded Zygote. See crbug.com/157458.
+ base::TerminationStatus GetTerminationStatus(base::ProcessHandle handle,
+ bool known_dead,
+ int* exit_code);
+
+ // Returns the sandbox status of this zygote.
+ int GetSandboxStatus();
+
+ private:
+ // Whether we should use the namespace sandbox instead of the setuid sandbox.
+ bool ShouldUseNamespaceSandbox();
+
+ // Should be called every time a Zygote child is born.
+ void ZygoteChildBorn(pid_t process);
+
+ // Read the reply from the zygote.
+ ssize_t ReadReply(void* buf, size_t buf_len);
+
+ // Sends |data| to the zygote via |control_fd_|. If |fds| is non-NULL, the
+ // included file descriptors will also be passed. The caller is responsible
+ // for acquiring |control_lock_|.
+ bool SendMessage(const base::Pickle& data, const std::vector<int>* fds);
+
+ // Get the sandbox status from the zygote.
+ ssize_t ReadSandboxStatus();
+
+ int control_fd_; // the socket to the zygote.
+ // A lock protecting all communication with the zygote. This lock must be
+ // acquired before sending a command and released after the result has been
+ // received.
+ base::Lock control_lock_;
+ // The pid of the zygote.
+ pid_t pid_;
+ // The list of running zygote children.
+ std::set<pid_t> list_of_running_zygote_children_;
+ // The lock to guard the list of running zygote children.
+ base::Lock child_tracking_lock_;
+ int sandbox_status_;
+ bool have_read_sandbox_status_word_;
+ bool use_suid_sandbox_for_adj_oom_score_;
+ // Set to true when the zygote is initialized successfully.
+ bool init_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ZYGOTE_HOST_ZYGOTE_COMMUNICATION_LINUX_H_
diff --git a/chromium/content/browser/zygote_host/zygote_handle_linux.cc b/chromium/content/browser/zygote_host/zygote_handle_linux.cc
new file mode 100644
index 00000000000..55830f57487
--- /dev/null
+++ b/chromium/content/browser/zygote_host/zygote_handle_linux.cc
@@ -0,0 +1,22 @@
+// 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 "content/public/browser/zygote_handle_linux.h"
+
+#include "content/browser/zygote_host/zygote_communication_linux.h"
+
+namespace content {
+
+ZygoteHandle CreateZygote() {
+ ZygoteHandle zygote = new ZygoteCommunication();
+ zygote->Init();
+ return zygote;
+}
+
+ZygoteHandle* GetGenericZygote() {
+ static ZygoteHandle zygote;
+ return &zygote;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc b/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
index 5c964c531d3..e798f96fd7a 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -4,100 +4,32 @@
#include "content/browser/zygote_host/zygote_host_impl_linux.h"
-#include <errno.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "base/base_switches.h"
+#include "base/allocator/allocator_extension.h"
#include "base/command_line.h"
-#include "base/environment.h"
#include "base/files/file_enumerator.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/linux_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/path_service.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/posix/unix_domain_socket_linux.h"
-#include "base/process/launch.h"
+#include "base/process/kill.h"
#include "base/process/memory.h"
-#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/browser/renderer_host/render_sandbox_host_linux.h"
-#include "content/common/child_process_sandbox_support_impl_linux.h"
-#include "content/common/zygote_commands_linux.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_switches.h"
-#include "content/public/common/result_codes.h"
#include "sandbox/linux/services/credentials.h"
-#include "sandbox/linux/services/namespace_sandbox.h"
-#include "sandbox/linux/services/namespace_utils.h"
-#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
#include "sandbox/linux/suid/common/sandbox.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/switches.h"
-
-#if defined(USE_TCMALLOC)
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif
namespace content {
-namespace {
-
-// Receive a fixed message on fd and return the sender's PID.
-// Returns true if the message received matches the expected message.
-bool ReceiveFixedMessage(int fd,
- const char* expect_msg,
- size_t expect_len,
- base::ProcessId* sender_pid) {
- char buf[expect_len + 1];
- std::vector<base::ScopedFD> fds_vec;
-
- const ssize_t len = base::UnixDomainSocket::RecvMsgWithPid(
- fd, buf, sizeof(buf), &fds_vec, sender_pid);
- if (static_cast<size_t>(len) != expect_len)
- return false;
- if (memcmp(buf, expect_msg, expect_len) != 0)
- return false;
- if (!fds_vec.empty())
- return false;
- return true;
-}
-
-} // namespace
-
// static
ZygoteHost* ZygoteHost::GetInstance() {
return ZygoteHostImpl::GetInstance();
}
ZygoteHostImpl::ZygoteHostImpl()
- : control_fd_(-1),
- control_lock_(),
- pid_(-1),
- init_(false),
+ : should_use_namespace_sandbox_(true),
use_suid_sandbox_for_adj_oom_score_(false),
sandbox_binary_(),
- have_read_sandbox_status_word_(false),
- sandbox_status_(0),
- child_tracking_lock_(),
- list_of_running_zygote_children_(),
- should_teardown_after_last_child_exits_(false) {}
+ zygote_pids_lock_(),
+ zygote_pids_() {}
-ZygoteHostImpl::~ZygoteHostImpl() { TearDown(); }
+ZygoteHostImpl::~ZygoteHostImpl() {}
// static
ZygoteHostImpl* ZygoteHostImpl::GetInstance() {
@@ -105,348 +37,59 @@ ZygoteHostImpl* ZygoteHostImpl::GetInstance() {
}
void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
- DCHECK(!init_);
- init_ = true;
-
- base::FilePath chrome_path;
- CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
- base::CommandLine cmd_line(chrome_path);
+ sandbox_binary_ = sandbox_cmd;
- cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess);
-
- int fds[2];
- CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
- CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0]));
- base::FileHandleMappingVector fds_to_map;
- fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
-
- base::LaunchOptions options;
- const base::CommandLine& browser_command_line =
+ const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
- if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) {
- cmd_line.PrependWrapper(
- browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix));
+ if (command_line.HasSwitch(switches::kNoSandbox) ||
+ command_line.HasSwitch(switches::kDisableNamespaceSandbox) ||
+ !sandbox::Credentials::CanCreateProcessInNewUserNS()) {
+ should_use_namespace_sandbox_ = false;
}
- // Append any switches from the browser process that need to be forwarded on
- // to the zygote/renderers.
- // Should this list be obtained from browser_render_process_host.cc?
- static const char* kForwardSwitches[] = {
- switches::kAllowSandboxDebugging,
- switches::kDisableSeccompFilterSandbox,
- switches::kEnableHeapProfiling,
- switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
- // Zygote process needs to know what resources to have loaded when it
- // becomes a renderer process.
- switches::kForceDeviceScaleFactor,
- switches::kLoggingLevel,
- switches::kNoSandbox,
- switches::kPpapiInProcess,
- switches::kRegisterPepperPlugins,
- switches::kV,
- switches::kVModule,
- };
- cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
- arraysize(kForwardSwitches));
-
- GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1);
-
- sandbox_binary_ = sandbox_cmd.c_str();
const bool using_namespace_sandbox = ShouldUseNamespaceSandbox();
// A non empty sandbox_cmd means we want a SUID sandbox.
const bool using_suid_sandbox =
- !sandbox_cmd.empty() && !using_namespace_sandbox;
+ !sandbox_binary_.empty() && !using_namespace_sandbox;
// Use the SUID sandbox for adjusting OOM scores when we are using the setuid
- // or namespace sandbox. This is needed beacuse the processes are
- // non-dumpable, so /proc/pid/oom_score_adj can only be written by root.
- use_suid_sandbox_for_adj_oom_score_ =
- !sandbox_binary_.empty() && using_suid_sandbox;
+ // sandbox. This is needed beacuse the processes are non-dumpable, so
+ // /proc/pid/oom_score_adj can only be written by root.
+ use_suid_sandbox_for_adj_oom_score_ = using_suid_sandbox;
#if defined(OS_CHROMEOS)
// Chrome OS has a kernel patch that restricts oom_score_adj. See
// crbug.com/576409 for details.
- if (!sandbox_binary_.empty() && using_namespace_sandbox) {
+ if (!sandbox_binary_.empty()) {
use_suid_sandbox_for_adj_oom_score_ = true;
}
#endif
-
- // Start up the sandbox host process and get the file descriptor for the
- // renderers to talk to it.
- const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
- fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
-
- base::ScopedFD dummy_fd;
- if (using_suid_sandbox) {
- scoped_ptr<sandbox::SetuidSandboxHost> sandbox_host(
- sandbox::SetuidSandboxHost::Create());
- sandbox_host->PrependWrapper(&cmd_line);
- sandbox_host->SetupLaunchOptions(&options, &fds_to_map, &dummy_fd);
- sandbox_host->SetupLaunchEnvironment();
- }
-
- options.fds_to_remap = &fds_to_map;
- base::Process process =
- using_namespace_sandbox
- ? sandbox::NamespaceSandbox::LaunchProcess(cmd_line, options)
- : base::LaunchProcess(cmd_line, options);
- CHECK(process.IsValid()) << "Failed to launch zygote process";
-
- dummy_fd.reset();
-
- if (using_suid_sandbox || using_namespace_sandbox) {
- // The SUID sandbox will execute the zygote in a new PID namespace, and
- // the main zygote process will then fork from there. Watch now our
- // elaborate dance to find and validate the zygote's PID.
-
- // First we receive a message from the zygote boot process.
- base::ProcessId boot_pid;
- CHECK(ReceiveFixedMessage(
- fds[0], kZygoteBootMessage, sizeof(kZygoteBootMessage), &boot_pid));
-
- // Within the PID namespace, the zygote boot process thinks it's PID 1,
- // but its real PID can never be 1. This gives us a reliable test that
- // the kernel is translating the sender's PID to our namespace.
- CHECK_GT(boot_pid, 1)
- << "Received invalid process ID for zygote; kernel might be too old? "
- "See crbug.com/357670 or try using --"
- << switches::kDisableSetuidSandbox << " to workaround.";
-
- // Now receive the message that the zygote's ready to go, along with the
- // main zygote process's ID.
- CHECK(ReceiveFixedMessage(
- fds[0], kZygoteHelloMessage, sizeof(kZygoteHelloMessage), &pid_));
- CHECK_GT(pid_, 1);
-
- if (process.Pid() != pid_) {
- // Reap the sandbox.
- base::EnsureProcessGetsReaped(process.Pid());
- }
- } else {
- // Not using the SUID sandbox.
- // Note that ~base::Process() will reset the internal value, but there's no
- // real "handle" on POSIX so that is safe.
- pid_ = process.Pid();
- }
-
- close(fds[1]);
- control_fd_ = fds[0];
-
- base::Pickle pickle;
- pickle.WriteInt(kZygoteCommandGetSandboxStatus);
- if (!SendMessage(pickle, NULL))
- LOG(FATAL) << "Cannot communicate with zygote";
- // We don't wait for the reply. We'll read it in ReadReply.
}
-void ZygoteHostImpl::TearDownAfterLastChild() {
- bool do_teardown = false;
- {
- base::AutoLock lock(child_tracking_lock_);
- should_teardown_after_last_child_exits_ = true;
- do_teardown = list_of_running_zygote_children_.empty();
- }
- if (do_teardown) {
- TearDown();
- }
+void ZygoteHostImpl::AddZygotePid(pid_t pid) {
+ base::AutoLock lock(zygote_pids_lock_);
+ zygote_pids_.insert(pid);
}
-// Note: this is also called from the destructor.
-void ZygoteHostImpl::TearDown() {
- base::AutoLock lock(control_lock_);
- if (control_fd_ > -1) {
- // Closing the IPC channel will act as a notification to exit
- // to the Zygote.
- if (IGNORE_EINTR(close(control_fd_))) {
- PLOG(ERROR) << "Could not close Zygote control channel.";
- NOTREACHED();
- }
- control_fd_ = -1;
- }
-}
-
-void ZygoteHostImpl::ZygoteChildBorn(pid_t process) {
- base::AutoLock lock(child_tracking_lock_);
- bool new_element_inserted =
- list_of_running_zygote_children_.insert(process).second;
- DCHECK(new_element_inserted);
+bool ZygoteHostImpl::IsZygotePid(pid_t pid) {
+ base::AutoLock lock(zygote_pids_lock_);
+ return zygote_pids_.find(pid) != zygote_pids_.end();
}
-void ZygoteHostImpl::ZygoteChildDied(pid_t process) {
- bool do_teardown = false;
- {
- base::AutoLock lock(child_tracking_lock_);
- size_t num_erased = list_of_running_zygote_children_.erase(process);
- DCHECK_EQ(1U, num_erased);
- do_teardown = should_teardown_after_last_child_exits_ &&
- list_of_running_zygote_children_.empty();
- }
- if (do_teardown) {
- TearDown();
- }
+const std::string& ZygoteHostImpl::SandboxCommand() const {
+ return sandbox_binary_;
}
-bool ZygoteHostImpl::SendMessage(const base::Pickle& data,
- const std::vector<int>* fds) {
- DCHECK_NE(-1, control_fd_);
- CHECK(data.size() <= kZygoteMaxMessageLength)
- << "Trying to send too-large message to zygote (sending " << data.size()
- << " bytes, max is " << kZygoteMaxMessageLength << ")";
- CHECK(!fds || fds->size() <= base::UnixDomainSocket::kMaxFileDescriptors)
- << "Trying to send message with too many file descriptors to zygote "
- << "(sending " << fds->size() << ", max is "
- << base::UnixDomainSocket::kMaxFileDescriptors << ")";
-
- return base::UnixDomainSocket::SendMsg(control_fd_,
- data.data(), data.size(),
- fds ? *fds : std::vector<int>());
+void ZygoteHostImpl::SetRendererSandboxStatus(int status) {
+ renderer_sandbox_status_ = status;
}
-ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) {
- DCHECK_NE(-1, control_fd_);
- // At startup we send a kZygoteCommandGetSandboxStatus request to the zygote,
- // but don't wait for the reply. Thus, the first time that we read from the
- // zygote, we get the reply to that request.
- if (!have_read_sandbox_status_word_) {
- if (HANDLE_EINTR(read(control_fd_, &sandbox_status_,
- sizeof(sandbox_status_))) !=
- sizeof(sandbox_status_)) {
- return -1;
- }
-
- have_read_sandbox_status_word_ = true;
- UMA_HISTOGRAM_SPARSE_SLOWLY("Linux.SandboxStatus", sandbox_status_);
- }
-
- return HANDLE_EINTR(read(control_fd_, buf, buf_len));
+int ZygoteHostImpl::GetRendererSandboxStatus() const {
+ return renderer_sandbox_status_;
}
-pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv,
- scoped_ptr<FileDescriptorInfo> mapping,
- const std::string& process_type) {
- DCHECK(init_);
- base::Pickle pickle;
-
- int raw_socks[2];
- PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks));
- base::ScopedFD my_sock(raw_socks[0]);
- base::ScopedFD peer_sock(raw_socks[1]);
- CHECK(base::UnixDomainSocket::EnableReceiveProcessId(my_sock.get()));
-
- pickle.WriteInt(kZygoteCommandFork);
- pickle.WriteString(process_type);
- pickle.WriteInt(argv.size());
- for (std::vector<std::string>::const_iterator
- i = argv.begin(); i != argv.end(); ++i)
- pickle.WriteString(*i);
-
- // Fork requests contain one file descriptor for the PID oracle, and one
- // more for each file descriptor mapping for the child process.
- const size_t num_fds_to_send = 1 + mapping->GetMappingSize();
- pickle.WriteInt(num_fds_to_send);
-
- std::vector<int> fds;
-
- // First FD to send is peer_sock.
- // TODO(morrita): Ideally, this should be part of the mapping so that
- // FileDescriptorInfo can manages its lifetime.
- fds.push_back(peer_sock.get());
-
- // The rest come from mapping.
- for (size_t i = 0; i < mapping->GetMappingSize(); ++i) {
- pickle.WriteUInt32(mapping->GetIDAt(i));
- fds.push_back(mapping->GetFDAt(i));
- }
-
- // Sanity check that we've populated |fds| correctly.
- DCHECK_EQ(num_fds_to_send, fds.size());
-
- pid_t pid;
- {
- base::AutoLock lock(control_lock_);
- if (!SendMessage(pickle, &fds))
- return base::kNullProcessHandle;
- mapping.reset();
- peer_sock.reset();
-
- {
- char buf[sizeof(kZygoteChildPingMessage) + 1];
- std::vector<base::ScopedFD> recv_fds;
- base::ProcessId real_pid;
-
- ssize_t n = base::UnixDomainSocket::RecvMsgWithPid(
- my_sock.get(), buf, sizeof(buf), &recv_fds, &real_pid);
- if (n != sizeof(kZygoteChildPingMessage) ||
- 0 != memcmp(buf,
- kZygoteChildPingMessage,
- sizeof(kZygoteChildPingMessage))) {
- // Zygote children should still be trustworthy when they're supposed to
- // ping us, so something's broken if we don't receive a valid ping.
- LOG(ERROR) << "Did not receive ping from zygote child";
- NOTREACHED();
- real_pid = -1;
- }
- my_sock.reset();
-
- // Always send PID back to zygote.
- base::Pickle pid_pickle;
- pid_pickle.WriteInt(kZygoteCommandForkRealPID);
- pid_pickle.WriteInt(real_pid);
- if (!SendMessage(pid_pickle, NULL))
- return base::kNullProcessHandle;
- }
-
- // Read the reply, which pickles the PID and an optional UMA enumeration.
- static const unsigned kMaxReplyLength = 2048;
- char buf[kMaxReplyLength];
- const ssize_t len = ReadReply(buf, sizeof(buf));
-
- base::Pickle reply_pickle(buf, len);
- base::PickleIterator iter(reply_pickle);
- if (len <= 0 || !iter.ReadInt(&pid))
- return base::kNullProcessHandle;
-
- // If there is a nonempty UMA name string, then there is a UMA
- // enumeration to record.
- std::string uma_name;
- int uma_sample;
- int uma_boundary_value;
- if (iter.ReadString(&uma_name) &&
- !uma_name.empty() &&
- iter.ReadInt(&uma_sample) &&
- iter.ReadInt(&uma_boundary_value)) {
- // We cannot use the UMA_HISTOGRAM_ENUMERATION macro here,
- // because that's only for when the name is the same every time.
- // Here we're using whatever name we got from the other side.
- // But since it's likely that the same one will be used repeatedly
- // (even though it's not guaranteed), we cache it here.
- static base::HistogramBase* uma_histogram;
- if (!uma_histogram || uma_histogram->histogram_name() != uma_name) {
- uma_histogram = base::LinearHistogram::FactoryGet(
- uma_name, 1,
- uma_boundary_value,
- uma_boundary_value + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- }
- uma_histogram->Add(uma_sample);
- }
-
- if (pid <= 0)
- return base::kNullProcessHandle;
- }
-
-#if !defined(OS_OPENBSD)
- // This is just a starting score for a renderer or extension (the
- // only types of processes that will be started this way). It will
- // get adjusted as time goes on. (This is the same value as
- // chrome::kLowestRendererOomScore in chrome/chrome_constants.h, but
- // that's not something we can include here.)
- const int kLowestRendererOomScore = 300;
- AdjustRendererOOMScore(pid, kLowestRendererOomScore);
-#endif
-
- ZygoteChildBorn(pid);
- return pid;
+bool ZygoteHostImpl::ShouldUseNamespaceSandbox() {
+ return should_use_namespace_sandbox_;
}
#if !defined(OS_OPENBSD)
@@ -492,13 +135,12 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
}
if (use_suid_sandbox_for_adj_oom_score_ && !selinux) {
-#if defined(USE_TCMALLOC)
// If heap profiling is running, these processes are not exiting, at least
// on ChromeOS. The easiest thing to do is not launch them when profiling.
// TODO(stevenjb): Investigate further and fix.
- if (IsHeapProfilerRunning())
+ if (base::allocator::IsHeapProfilerRunning())
return;
-#endif
+
std::vector<std::string> adj_oom_score_cmdline;
adj_oom_score_cmdline.push_back(sandbox_binary_);
adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch);
@@ -522,92 +164,4 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
}
#endif
-void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) {
- DCHECK(init_);
- base::Pickle pickle;
-
- pickle.WriteInt(kZygoteCommandReap);
- pickle.WriteInt(process);
- if (!SendMessage(pickle, NULL))
- LOG(ERROR) << "Failed to send Reap message to zygote";
- ZygoteChildDied(process);
-}
-
-base::TerminationStatus ZygoteHostImpl::GetTerminationStatus(
- base::ProcessHandle handle,
- bool known_dead,
- int* exit_code) {
- DCHECK(init_);
- base::Pickle pickle;
- pickle.WriteInt(kZygoteCommandGetTerminationStatus);
- pickle.WriteBool(known_dead);
- pickle.WriteInt(handle);
-
- static const unsigned kMaxMessageLength = 128;
- char buf[kMaxMessageLength];
- ssize_t len;
- {
- base::AutoLock lock(control_lock_);
- if (!SendMessage(pickle, NULL))
- LOG(ERROR) << "Failed to send GetTerminationStatus message to zygote";
- len = ReadReply(buf, sizeof(buf));
- }
-
- // Set this now to handle the error cases.
- if (exit_code)
- *exit_code = RESULT_CODE_NORMAL_EXIT;
- int status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
-
- if (len == -1) {
- LOG(WARNING) << "Error reading message from zygote: " << errno;
- } else if (len == 0) {
- LOG(WARNING) << "Socket closed prematurely.";
- } else {
- base::Pickle read_pickle(buf, len);
- int tmp_status, tmp_exit_code;
- base::PickleIterator iter(read_pickle);
- if (!iter.ReadInt(&tmp_status) || !iter.ReadInt(&tmp_exit_code)) {
- LOG(WARNING)
- << "Error parsing GetTerminationStatus response from zygote.";
- } else {
- if (exit_code)
- *exit_code = tmp_exit_code;
- status = tmp_status;
- }
- }
-
- if (status != base::TERMINATION_STATUS_STILL_RUNNING) {
- ZygoteChildDied(handle);
- }
- return static_cast<base::TerminationStatus>(status);
-}
-
-pid_t ZygoteHostImpl::GetPid() const {
- return pid_;
-}
-
-int ZygoteHostImpl::GetSandboxStatus() const {
- if (have_read_sandbox_status_word_)
- return sandbox_status_;
- return 0;
-}
-
-bool ZygoteHostImpl::ShouldUseNamespaceSandbox() {
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kNoSandbox)) {
- return false;
- }
-
- if (command_line.HasSwitch(switches::kDisableNamespaceSandbox)) {
- return false;
- }
-
- if (!sandbox::Credentials::CanCreateProcessInNewUserNS()) {
- return false;
- }
-
- return true;
-}
-
} // namespace content
diff --git a/chromium/content/browser/zygote_host/zygote_host_impl_linux.h b/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
index 6793f73757c..e42a222913f 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -5,16 +5,13 @@
#ifndef CONTENT_BROWSER_ZYGOTE_HOST_ZYGOTE_HOST_IMPL_LINUX_H_
#define CONTENT_BROWSER_ZYGOTE_HOST_ZYGOTE_HOST_IMPL_LINUX_H_
-#include <stddef.h>
+#include <sys/types.h>
#include <set>
#include <string>
-#include <vector>
-#include "base/pickle.h"
-#include "base/process/kill.h"
+#include "base/process/process_handle.h"
#include "base/synchronization/lock.h"
-#include "content/public/browser/file_descriptor_info.h"
#include "content/public/browser/zygote_host_linux.h"
namespace base {
@@ -31,35 +28,19 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
void Init(const std::string& sandbox_cmd);
- // After the last known Zygote child exits, notify the Zygote to exit.
- void TearDownAfterLastChild();
-
- // Tries to start a process of type indicated by process_type.
- // Returns its pid on success, otherwise
- // base::kNullProcessHandle;
- pid_t ForkRequest(const std::vector<std::string>& command_line,
- scoped_ptr<FileDescriptorInfo> mapping,
- const std::string& process_type);
- void EnsureProcessTerminated(pid_t process);
-
- // Get the termination status (and, optionally, the exit code) of
- // the process. |exit_code| is set to the exit code of the child
- // process. (|exit_code| may be NULL.)
- // Unfortunately the Zygote can not accurately figure out if a process
- // is already dead without waiting synchronously for it.
- // |known_dead| should be set to true when we already know that the process
- // is dead. When |known_dead| is false, processes could be seen as
- // still running, even when they're not. When |known_dead| is true, the
- // process will be SIGKILL-ed first (which should have no effect if it was
- // really dead). This is to prevent a waiting waitpid() from blocking in
- // a single-threaded Zygote. See crbug.com/157458.
- base::TerminationStatus GetTerminationStatus(base::ProcessHandle handle,
- bool known_dead,
- int* exit_code);
-
- // ZygoteHost implementation:
- pid_t GetPid() const override;
- int GetSandboxStatus() const override;
+ // Retrieves the sandbox command passed into Init();
+ const std::string& SandboxCommand() const;
+
+ // Tells the ZygoteHost the PIDs of all the zygotes.
+ void AddZygotePid(pid_t pid);
+
+ // Returns whether or not this pid is the pid of a zygote.
+ bool IsZygotePid(pid_t pid) override;
+
+ bool ShouldUseNamespaceSandbox();
+
+ void SetRendererSandboxStatus(int status);
+ int GetRendererSandboxStatus() const override;
void AdjustRendererOOMScore(base::ProcessHandle process_handle,
int score) override;
@@ -69,42 +50,14 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
ZygoteHostImpl();
~ZygoteHostImpl() override;
- // Notify the Zygote to exit immediately. This object should not be
- // used afterwards.
- void TearDown();
-
- // Should be called every time a Zygote child is born.
- void ZygoteChildBorn(pid_t process);
-
- // Should be called every time a Zygote child died.
- void ZygoteChildDied(pid_t process);
-
- // Sends |data| to the zygote via |control_fd_|. If |fds| is non-NULL, the
- // included file descriptors will also be passed. The caller is responsible
- // for acquiring |control_lock_|.
- bool SendMessage(const base::Pickle& data, const std::vector<int>* fds);
-
- ssize_t ReadReply(void* buf, size_t buflen);
-
- // Whether we should use the namespace sandbox instead of the setuid sandbox.
- bool ShouldUseNamespaceSandbox();
-
- int control_fd_; // the socket to the zygote
- // A lock protecting all communication with the zygote. This lock must be
- // acquired before sending a command and released after the result has been
- // received.
- base::Lock control_lock_;
- pid_t pid_;
- bool init_;
+ int renderer_sandbox_status_;
+ bool should_use_namespace_sandbox_;
bool use_suid_sandbox_for_adj_oom_score_;
std::string sandbox_binary_;
- bool have_read_sandbox_status_word_;
- int sandbox_status_;
- // A lock protecting list_of_running_zygote_children_ and
- // should_teardown_after_last_child_exits_.
- base::Lock child_tracking_lock_;
- std::set<pid_t> list_of_running_zygote_children_;
- bool should_teardown_after_last_child_exits_;
+ // This lock protects the |zygote_pids_| set.
+ base::Lock zygote_pids_lock_;
+ // This is a set of PIDs representing all the running zygotes.
+ std::set<pid_t> zygote_pids_;
};
} // namespace content